Compare commits

...

7 Commits

Author SHA1 Message Date
akulij
c3c506e206 move cmd utility location to follow projects name 2025-02-27 20:02:49 +00:00
akulij
6ded6ec767 rename project from age-gen-passphrase to age-passgen 2025-02-27 20:01:44 +00:00
akulij
5522a1265e FIX: missing --entropy-level flag in --help 2025-02-27 19:52:00 +00:00
akulij
a9943d2358 use entropy level for password 2025-02-27 03:02:39 +00:00
akulij
7e28ea3c94 add --entropy-level flag 2025-02-27 01:51:29 +00:00
akulij
dbe48ec586 fix usage info 2025-02-27 00:00:48 +00:00
akulij
adc6b32c3b check raw/verbose output todo as done 2025-02-26 23:41:24 +00:00
3 changed files with 59 additions and 9 deletions

View File

@ -1,7 +1,7 @@
# Generate age keys from passphrase
## Description
This utility (age-gen-passphrase) generates secret and public keys (into stdout) from your entered passphrase or piped stdin
This utility (age-passgen) generates secret and public keys (into stdout) from your entered passphrase or piped stdin
Strong password highly recomended
## Password selection
@ -10,5 +10,5 @@ Exact amount of required characters can be calculated by formula: $\lceil 256 /
## TODO
[ ] piped/terminal output as raw/verbose
[X] piped/terminal output as raw/verbose
[ ] handle broken pipe signal since program will so much depend on pipes

View File

@ -7,6 +7,8 @@ import (
"io"
"log"
"os"
"slices"
"strconv"
"time"
"unsafe"
@ -23,32 +25,54 @@ type X25519Identity struct {
}
const usage = `Usage:
age-gen-passphrase [-o OUTPUT] [--raw-input]
age-passgen [-o OUTPUT] [--raw-input]
Options:
-o, --output OUTPUT Write the result to the file at path OUTPUT.
--raw-output Print stripped keys (without additional text or comments)
--entropy-level VALUE Manages required strenght of password (more info down below)
Everything is similar to age-keygen`
Mostly similar to age-keygen
Required password strenght can be changes via --entropy-level flag. Possible values
high, medium (default), low, verylow, stupid and numbers from 1 to 4 (inclusive).
Each word or number is mapped following this list:
- high (or 4) - 44 characters
- medium (or 3) - 22 characters
- low (or 2) - 12 characters
- verylow (or 1) - 8 characters
- stupid - no limit
`
func main() {
log.SetFlags(0)
flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s\n", usage) }
flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s", usage) }
var (
rawOutput bool
outputFile string
rawOutput bool
outputFile string
entropyLevel string
)
flag.BoolVar(&rawOutput, "raw-output", false, "Print stripped keys (without additional text or comments)")
flag.StringVar(&outputFile, "o", "", "Write the result to the file at path OUTPUT")
flag.StringVar(&outputFile, "output", "", "Write the result to the file at path OUTPUT")
flag.StringVar(&entropyLevel, "entropy-level", "medium", "Manages required strenght of password. Read more in --help")
flag.Parse()
eLevel, err := parseEntropyLevel(entropyLevel)
if err != nil {
errorf("error while parsing --entropy-level argument: %s\n", err)
}
passbytes, err := getPasswordBytes()
if err != nil {
errorf("Failed to get password, error: %s\n", err)
}
valid := isEntropyValid(passbytes, eLevel)
if !valid {
errorf("You should choose stroger password!!! (or change entropy level, read more with --help)\n")
}
sum := sha256.Sum256(passbytes)
@ -82,6 +106,32 @@ func main() {
}
}
func parseEntropyLevel(entropyLevel string) (int, error) {
if i, err := strconv.Atoi(entropyLevel); err == nil {
if i == 0 {
return 0, errors.New("No such entropy level `0`, try `stupid`")
} else if 1 <= i && i <= 4 {
return i, nil
} else {
return 0, errors.New("Wrong entropy level `" + strconv.Itoa(i) + "`, level should be within range 1 to 4")
}
}
//if it is not number, let's try words
levelWords := [...]string{"stupid", "verylow", "low", "medium", "high"}
idx := slices.Index(levelWords[:], entropyLevel)
if idx == -1 {
return 0, errors.New("Such entropy level does not exists: " + entropyLevel + "\nMay be misstyped?")
}
return idx, nil
}
func isEntropyValid(passbytes []byte, entropyLevel int) bool {
lengthsMap := [...]int{0, 8, 12, 22, 44}
return len(passbytes) >= lengthsMap[entropyLevel]
}
func getPasswordBytes() ([]byte, error) {
if term.IsTerminal(int(os.Stdin.Fd())) {
fmt.Fprintf(os.Stderr, "Enter password: ")
@ -129,5 +179,5 @@ func newX25519IdentityFromScalar(secretKey []byte) (*age.X25519Identity, error)
}
func errorf(format string, v ...interface{}) {
log.Fatalf("age-gen-passphrase ERROR: "+format, v...)
log.Fatalf("age-passgen ERROR: "+format, v...)
}

2
go.mod
View File

@ -1,4 +1,4 @@
module github.com/akulij/age-gen-passphrase
module github.com/akulij/age-passgen
go 1.22.2