17 Commits

Author SHA1 Message Date
Max c979561fa5 refactor: remove math/big, fix RNG bias, optimize builds, and bump Go version 2026-01-04 22:10:28 -06:00
max fe11983dab Make version reflect build version 2025-03-10 14:07:37 -05:00
max 1e93add7bd Make version reflect build version 2025-03-10 14:05:22 -05:00
max c328726ed0 Build with latest Go version 2025-03-10 14:04:19 -05:00
max 7e826b75d7 Fixed 1.3.3 build 2024-11-01 14:40:05 -05:00
max 72f4797428 Fix version displayed by -v 2024-11-01 14:39:24 -05:00
max aad2144e7c Build updated binaries 2024-11-01 14:31:08 -05:00
max a1c8d6e531 Bump version 2024-11-01 14:30:16 -05:00
max 0d5d7503ec Build with Go 1.23.2 2024-11-01 14:29:11 -05:00
max ee1a0fedcc Build with Go 1.22 2024-02-14 13:39:33 -06:00
max 3fc3f35bb5 Bump version to 1.3.2 2024-02-14 13:32:56 -06:00
max 9a98788476 Update Go version to 1.22 2024-02-14 13:32:07 -06:00
Maximilian 43b8d3b618 Update binaries to 1.3.1 2023-02-14 16:33:07 -06:00
Maximilian 6d1e700d8b Update version 2023-02-14 16:12:15 -06:00
Maximilian 1b2fcd72b9 Use switch statements for argument matching, use a map for removing disallowedCharacters, and set up worker pool for concurrent "chunk" generation of the password 2023-02-14 16:12:02 -06:00
Maximilian 6c20c7bb8b Add go.sum 2023-02-14 15:27:38 -06:00
Maximilian f5289baecd Update Go version to 1.20 2023-02-14 15:27:24 -06:00
30 changed files with 105 additions and 38 deletions
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -1,3 +1,3 @@
module GoPass
go 1.19
go 1.25.5
View File
+90 -23
View File
@@ -5,8 +5,8 @@ package main
import (
"crypto/rand"
"fmt"
"math/big"
"os"
"runtime"
"strconv"
"strings"
)
@@ -14,8 +14,9 @@ import (
var allowedCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?")
const (
Version = "1.3.0"
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
Version = "1.3.5"
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
chunkSize = 16 // The size of each chunk of the password to be generated by the worker goroutines
)
func matchArguments(args []string) string {
@@ -26,11 +27,10 @@ func matchArguments(args []string) string {
// First argument is special, must be an integer, -v, or -h
var size = 0 // Password length
err := error(nil)
if size, err = strconv.Atoi(args[0]); err == nil { // If first argument is an integer
} else if args[0] == "-v" {
switch args[0] {
case "-v":
return "GoPass version " + Version
} else if args[0] == "-h" {
case "-h":
return "GoPass - A simple password generator written in Go\n" +
"Usage: gopass [length] [disallowed characters] [optional remove symbols -s]\n" +
" Example: gopass 16\n" +
@@ -38,16 +38,23 @@ func matchArguments(args []string) string {
" Example: gopass 16 -s\n" +
"\nFor help (this output): gopass -h\n" +
"For version: gopass -v\n"
default:
var err error
size, err = strconv.Atoi(args[0])
if err != nil {
return "Invalid first argument (\"" + args[0] + "\") supplied! (Type gopass -h for help)"
}
}
for i := 1; i < len(args); i++ {
v := args[i]
if v == "-s" {
switch {
case v == "-s":
removeDisallowed([]rune(symbols))
} else if strings.HasPrefix(v, "-r=") { // If argument starts with -r=
case strings.HasPrefix(v, "-r="):
// Remove all characters after the = until next whitespace
removeDisallowed([]rune(v[2:]))
} else {
default:
return "Invalid argument (\"" + v + "\") supplied! (Type gopass -h for help)"
}
}
@@ -61,28 +68,88 @@ func matchArguments(args []string) string {
// Remove all disallowed characters from the allowedCharacters slice
func removeDisallowed(disallowed []rune) {
disallowedMap := make(map[rune]bool, len(disallowed))
for _, r := range disallowed {
for i, v := range allowedCharacters {
if v == r {
allowedCharacters = append(allowedCharacters[:i], allowedCharacters[i+1:]...)
}
disallowedMap[r] = true
}
i := 0
for _, v := range allowedCharacters {
if !disallowedMap[v] {
allowedCharacters[i] = v
i++
}
}
allowedCharacters = allowedCharacters[:i]
}
func generatePassword(size int) string {
// Make empty array of runes with size of size
pass := make([]rune, size)
// Assign every slot of pass to a random allowedCharacter
for i := range pass {
// Generate a random int greater than 0 and not to exceed the length of allowedCharacters
index, err := rand.Int(rand.Reader, big.NewInt(int64(len(allowedCharacters))))
if err != nil {
println("Error securely generating random character!")
return ""
}
pass[i] = allowedCharacters[index.Int64()]
// Create a channel to receive chunks of the password
passChan := make(chan []rune)
// Determine the number of worker goroutines to use
numWorkers := runtime.NumCPU()
// Launch the worker goroutines
for range numWorkers {
go func() {
allowedLen := len(allowedCharacters)
// Calculate the rejection limit to avoid modulo bias.
// Any random byte value > maxByte must be discarded.
maxByte := 255 - (256 % allowedLen)
// Create a buffer for random bytes.
// We read enough bytes for the whole chunk at once (plus some extra
// in case of rejections) to reduce system calls.
randBuf := make([]byte, chunkSize*2)
for {
// Fill the buffer initially
if _, err := rand.Read(randBuf); err != nil {
println("Error securely generating random character chunk!")
return
}
bufIdx := 0
chunk := make([]rune, chunkSize)
for i := range chunk {
for {
// If we exhausted the buffer due to rejections, refill it
if bufIdx >= len(randBuf) {
if _, err := rand.Read(randBuf); err != nil {
println("Error securely generating random character chunk!")
return
}
bufIdx = 0
}
b := randBuf[bufIdx]
bufIdx++
// If the byte causes bias, discard and retry
if int(b) > maxByte {
continue
}
// Safe to map to character set
chunk[i] = allowedCharacters[int(b)%allowedLen]
break
}
}
// Send the chunk of the password to the main goroutine
passChan <- chunk
}
}()
}
// Collect the chunks of the password from the channel
for i := 0; i < size; i += chunkSize {
chunk := <-passChan
copy(pass[i:], chunk)
}
return string(pass)
+14 -14
View File
@@ -1,5 +1,5 @@
# The current version number of the program
VERSION := 1.3.0
VERSION := 1.3.5
# List of OS and architecture combinations to build
BUILD_OS_ARCH := \
@@ -24,64 +24,64 @@ all: $(BUILD_OS_ARCH)
darwin/amd64:
GOOS=darwin \
GOARCH=amd64 \
go build -ldflags="-s -w" -o "gopass-darwin-amd64-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-darwin-amd64-$(VERSION)" main.go
freebsd/386:
GOOS=freebsd \
GOARCH=386 \
go build -ldflags="-s -w" -o "gopass-freebsd-386-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-386-$(VERSION)" main.go
freebsd/amd64:
GOOS=freebsd \
GOARCH=amd64 \
go build -ldflags="-s -w" -o "gopass-freebsd-amd64-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-amd64-$(VERSION)" main.go
freebsd/arm:
GOOS=freebsd \
GOARCH=arm \
go build -ldflags="-s -w" -o "gopass-freebsd-arm-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-arm-$(VERSION)" main.go
linux/386:
GOOS=linux \
GOARCH=386 \
go build -ldflags="-s -w" -o "gopass-linux-386-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-386-$(VERSION)" main.go
linux/amd64:
GOOS=linux \
GOARCH=amd64 \
go build -ldflags="-s -w" -o "gopass-linux-amd64-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-amd64-$(VERSION)" main.go
linux/arm:
GOOS=linux \
GOARCH=arm \
go build -ldflags="-s -w" -o "gopass-linux-arm-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-arm-$(VERSION)" main.go
plan9/386:
GOOS=plan9 \
GOARCH=386 \
go build -ldflags="-s -w" -o "gopass-plan9-386-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-386-$(VERSION)" main.go
plan9/amd64:
GOOS=plan9 \
GOARCH=amd64 \
go build -ldflags="-s -w" -o "gopass-plan9-amd64-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-amd64-$(VERSION)" main.go
plan9/arm:
GOOS=plan9 \
GOARCH=arm \
go build -ldflags="-s -w" -o "gopass-plan9-arm-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-arm-$(VERSION)" main.go
windows/386:
GOOS=windows \
GOARCH=386 \
go build -ldflags="-s -w" -o "gopass-windows-386-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-386-$(VERSION)" main.go
windows/amd64:
GOOS=windows \
GOARCH=amd64 \
go build -ldflags="-s -w" -o "gopass-windows-amd64-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-amd64-$(VERSION)" main.go
windows/arm:
GOOS=windows \
GOARCH=arm \
go build -ldflags="-s -w" -o "gopass-windows-arm-$(VERSION)" main.go
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-arm-$(VERSION)" main.go