/* * Copyright: this software is in the public domain * * Generate argon2id hashes from a given password * Salt may be provided, or generated randomly * Output format: * * $argon2[$v=]$m=,t=,p=$$ * * by wgs */ package main import ( "crypto/rand" "encoding/base64" "flag" "fmt" "log" "os" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/argon2" "golang.org/x/term" ) const ( // recommended for memory constrained environments, as per RFC9106 argon2id_memory_cost = 65536 // 64 Kib argon2id_time_cost = 3 argon2id_threads = 4 argon2id_salt_len = 16 ) func usage() { fmt.Printf("usage: %s [-hed] [-b size] [-j thread] [-t time] [-m memory] [-p pass] [-s salt] [-f file]\n", os.Args[0]) os.Exit(2) } func deriv(pw []byte, key *[]byte, time, mem, job uint32, salt []byte) { klen := len(*key) *key = argon2.IDKey(pw, salt, time, mem, uint8(job), uint32(klen)) } func main() { var err error var salt [16]byte var key, pass []byte var password, saltfile string var time uint64 var memory uint64 var jobnum uint64 key = make([]byte, chacha20poly1305.KeySize) flag.StringVar(&password, "p", "", "Password") flag.StringVar(&saltfile, "s", "", "Read salt from file") // argon2id parameters flag.Uint64Var(&memory, "m", argon2id_memory_cost, "Memory cost") flag.Uint64Var(&time, "t", argon2id_time_cost, "Time cost") flag.Uint64Var(&jobnum, "j", argon2id_threads, "Parallel threads") flag.Usage = usage flag.Parse() args := flag.Args() if len(args) > 0 { usage() } pass = []byte(password) // Prompt user for password if provided password is empty if len(pass) == 0 { tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0644) if err != nil { log.Fatal(err) } defer tty.Close() fmt.Fprint(tty, "password:") pass, _ = term.ReadPassword(int(tty.Fd())) fmt.Fprintln(tty, "") } if len(saltfile) > 0 { // Read salt from any manually specified file… f, err := os.Open(saltfile) if err != nil { log.Fatal(err) } _, err = f.Read(salt[:]) f.Close() } else { // … or generate a random one _, err = rand.Read(salt[:]) if err != nil { log.Fatal(err) } } deriv(pass, &key, uint32(time), uint32(memory), uint32(jobnum), salt[:]) b64_s := base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(salt[:]) b64_k := base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(key[:]) fmt.Printf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s\n", argon2.Version, memory, time, jobnum, b64_s, b64_k) }