Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c979561fa5 | |||
| fe11983dab | |||
| 1e93add7bd | |||
| c328726ed0 | |||
| 7e826b75d7 | |||
| 72f4797428 | |||
| aad2144e7c | |||
| a1c8d6e531 | |||
| 0d5d7503ec | |||
| ee1a0fedcc | |||
| 3fc3f35bb5 | |||
| 9a98788476 | |||
| 43b8d3b618 | |||
| 6d1e700d8b | |||
| 1b2fcd72b9 | |||
| 6c20c7bb8b | |||
| f5289baecd | |||
| bb4dda5d9f | |||
| 14b7b1d181 | |||
| 83c7065d2a | |||
| 3978c9ad47 | |||
| e1ced3f76d | |||
| cdbca3b074 | |||
| e4eca321f6 | |||
| 0eacc92a45 | |||
| e96fded8ff | |||
| 710f96e9e7 | |||
| 4609be7a9d | |||
| 57b78dc62e | |||
| 87fa1107d7 | |||
| 3915761477 | |||
| 5ba592db21 | |||
| b81783b470 | |||
| cebcbc2823 | |||
| b5b7c208f2 | |||
| 8aa2f61b3c | |||
| f2a9cdd216 | |||
| c99539c0a9 | |||
| 33cf6cde39 |
@@ -1,9 +1,38 @@
|
|||||||
# GoPass
|
# GoPass
|
||||||
An easy to use command-line password generator that creates secure passwords (Version 1.1 adds proper cryptographic seeding of math/rand)
|
|
||||||
|
An easy to use command-line password generator that creates secure passwords
|
||||||
|
|
||||||
# Usage:
|
# Usage:
|
||||||
<code>./gopass [number of characters]</code><br>
|
|
||||||
|
`./gopass [number of characters]`<br>
|
||||||
|
or <br>
|
||||||
|
`./gopass [number of characters] -r=[excluded characters] [-s to remove all symbols]`
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
eg:
|
|
||||||
<code>./gopass 32</code><br>
|
eg: `./gopass 32` <br>
|
||||||
output: <code>E$bGOiiPASS*,ISl{!MJ&<\[COOL0eVw</code>
|
output: `E$bGOiiPASS*,ISl{!MJ&<\[COOL0eVw` <br>
|
||||||
|
eg: (with excluded characters): `./gopass 32 -r=$,!` <br>
|
||||||
|
output: `EYbGOiiPASS*2ISl{?MJ&<\[COOL0eVw` <- note the excluded characters are not present in the output <br>
|
||||||
|
eg: `./gopass 32 -s` <br>
|
||||||
|
output: `LEYbGOiiPASS2ISlMJCOOL0eRt3KPOVw` <- note the symbols are not present in the output <br>
|
||||||
|
eg: `./gopass 32 -r=$,! -s` the -r and -s flags can be combined <br>
|
||||||
|
|
||||||
|
# How to install/use for Windows:
|
||||||
|
|
||||||
|
1. Download Windows binary, it may be helpful to simply rename it to "gopass.exe" (make sure to add .exe, this won't
|
||||||
|
need to
|
||||||
|
be typed to execute the file from the CLI, but it is required for Windows to recognize the binary) to keep
|
||||||
|
commands shorter.
|
||||||
|
2. Move the file to your `C:\Users\[Username]` directory
|
||||||
|
3. Opening the console *without* Administrator privileges will put you in the directory mentioned above by default
|
||||||
|
4. Now type `gopass [number of characters]` (Ex. `gopass 64`) to generate a new password!
|
||||||
|
|
||||||
|
# How to install/use for Linux:
|
||||||
|
|
||||||
|
1. Download Linux binary, it may be helpful to simply rename it to "gopass" to keep commands shorter.
|
||||||
|
2. Move the file to your home directory.
|
||||||
|
3. `chmod +x gopass` if necessary
|
||||||
|
3. Opening your terminal should put you in your home directory by default, if not, just type `cd` to get sent back to
|
||||||
|
home.
|
||||||
|
4. Now type `./gopass [number of characters]` (Ex. `./gopass 64`) to generate a new password!
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -1,45 +1,161 @@
|
|||||||
// GoPass
|
// GoPass
|
||||||
// Author: Maximilian Patterson
|
// Author: Maximilian Patterson
|
||||||
// Version: 1.1
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
cryptorand "crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
mathrand "math/rand"
|
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var runes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?")
|
var allowedCharacters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()_+[]\\{}|;':,./<>?")
|
||||||
|
|
||||||
func main() {
|
const (
|
||||||
// Take OS arg (only accepts one arg)
|
Version = "1.3.5"
|
||||||
arg := os.Args[1]
|
symbols = "`~!@#$%^&*()_+[]\\{}|;':,./<>?"
|
||||||
|
chunkSize = 16 // The size of each chunk of the password to be generated by the worker goroutines
|
||||||
|
)
|
||||||
|
|
||||||
// Convert String arg to int
|
func matchArguments(args []string) string {
|
||||||
size, err := strconv.Atoi(arg)
|
// If there are no arguments
|
||||||
if err != nil {
|
if len(args) == 0 {
|
||||||
panic(err)
|
return "No password length specified! (ex: gopass 16)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First argument is special, must be an integer, -v, or -h
|
||||||
|
var size = 0 // Password length
|
||||||
|
switch args[0] {
|
||||||
|
case "-v":
|
||||||
|
return "GoPass version " + Version
|
||||||
|
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" +
|
||||||
|
" Example: gopass 16 -r=abc123!@#\n" +
|
||||||
|
" 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]
|
||||||
|
switch {
|
||||||
|
case v == "-s":
|
||||||
|
removeDisallowed([]rune(symbols))
|
||||||
|
case strings.HasPrefix(v, "-r="):
|
||||||
|
// Remove all characters after the = until next whitespace
|
||||||
|
removeDisallowed([]rune(v[2:]))
|
||||||
|
default:
|
||||||
|
return "Invalid argument (\"" + v + "\") supplied! (Type gopass -h for help)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if size <= 0 {
|
||||||
|
return "No/invalid password length specified! (ex: gopass 16)"
|
||||||
|
} else {
|
||||||
|
return generatePassword(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all disallowed characters from the allowedCharacters slice
|
||||||
|
func removeDisallowed(disallowed []rune) {
|
||||||
|
disallowedMap := make(map[rune]bool, len(disallowed))
|
||||||
|
for _, r := range disallowed {
|
||||||
|
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
|
// Make empty array of runes with size of size
|
||||||
pass := make([]rune, size)
|
pass := make([]rune, size)
|
||||||
|
|
||||||
// Seed rand with time
|
// Create a channel to receive chunks of the password
|
||||||
var b [8]byte
|
passChan := make(chan []rune)
|
||||||
_, err = cryptorand.Read(b[:])
|
|
||||||
if err != nil {
|
|
||||||
panic("Error securely seeding rand!")
|
|
||||||
}
|
|
||||||
mathrand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
|
|
||||||
|
|
||||||
// Assign every slot of pass to a random rune (generate rand int of length runes to select)
|
// Determine the number of worker goroutines to use
|
||||||
for i := range pass {
|
numWorkers := runtime.NumCPU()
|
||||||
pass[i] = runes[mathrand.Intn(len(runes))]
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the pass :D
|
// Collect the chunks of the password from the channel
|
||||||
fmt.Println(string(pass))
|
for i := 0; i < size; i += chunkSize {
|
||||||
|
chunk := <-passChan
|
||||||
|
copy(pass[i:], chunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(pass)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Process arguments
|
||||||
|
fmt.Println(matchArguments(os.Args[1:]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# The current version number of the program
|
||||||
|
VERSION := 1.3.5
|
||||||
|
|
||||||
|
# List of OS and architecture combinations to build
|
||||||
|
BUILD_OS_ARCH := \
|
||||||
|
darwin/amd64 \
|
||||||
|
freebsd/386 \
|
||||||
|
freebsd/amd64 \
|
||||||
|
freebsd/arm \
|
||||||
|
linux/386 \
|
||||||
|
linux/amd64 \
|
||||||
|
linux/arm \
|
||||||
|
plan9/386 \
|
||||||
|
plan9/amd64 \
|
||||||
|
plan9/arm \
|
||||||
|
windows/386 \
|
||||||
|
windows/amd64 \
|
||||||
|
windows/arm
|
||||||
|
|
||||||
|
# Build all targets
|
||||||
|
all: $(BUILD_OS_ARCH)
|
||||||
|
|
||||||
|
# Build targets in the form of `OS/ARCH`
|
||||||
|
darwin/amd64:
|
||||||
|
GOOS=darwin \
|
||||||
|
GOARCH=amd64 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-darwin-amd64-$(VERSION)" main.go
|
||||||
|
|
||||||
|
freebsd/386:
|
||||||
|
GOOS=freebsd \
|
||||||
|
GOARCH=386 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-386-$(VERSION)" main.go
|
||||||
|
|
||||||
|
freebsd/amd64:
|
||||||
|
GOOS=freebsd \
|
||||||
|
GOARCH=amd64 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-amd64-$(VERSION)" main.go
|
||||||
|
|
||||||
|
freebsd/arm:
|
||||||
|
GOOS=freebsd \
|
||||||
|
GOARCH=arm \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-freebsd-arm-$(VERSION)" main.go
|
||||||
|
|
||||||
|
linux/386:
|
||||||
|
GOOS=linux \
|
||||||
|
GOARCH=386 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-386-$(VERSION)" main.go
|
||||||
|
|
||||||
|
linux/amd64:
|
||||||
|
GOOS=linux \
|
||||||
|
GOARCH=amd64 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-amd64-$(VERSION)" main.go
|
||||||
|
|
||||||
|
linux/arm:
|
||||||
|
GOOS=linux \
|
||||||
|
GOARCH=arm \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-linux-arm-$(VERSION)" main.go
|
||||||
|
|
||||||
|
plan9/386:
|
||||||
|
GOOS=plan9 \
|
||||||
|
GOARCH=386 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-386-$(VERSION)" main.go
|
||||||
|
|
||||||
|
plan9/amd64:
|
||||||
|
GOOS=plan9 \
|
||||||
|
GOARCH=amd64 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-amd64-$(VERSION)" main.go
|
||||||
|
|
||||||
|
plan9/arm:
|
||||||
|
GOOS=plan9 \
|
||||||
|
GOARCH=arm \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-plan9-arm-$(VERSION)" main.go
|
||||||
|
|
||||||
|
windows/386:
|
||||||
|
GOOS=windows \
|
||||||
|
GOARCH=386 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-386-$(VERSION)" main.go
|
||||||
|
|
||||||
|
windows/amd64:
|
||||||
|
GOOS=windows \
|
||||||
|
GOARCH=amd64 \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-amd64-$(VERSION)" main.go
|
||||||
|
|
||||||
|
windows/arm:
|
||||||
|
GOOS=windows \
|
||||||
|
GOARCH=arm \
|
||||||
|
go build -trimpath -buildvcs=false -ldflags="-s -w" -o "gopass-windows-arm-$(VERSION)" main.go
|
||||||
Reference in New Issue
Block a user