thashgen.go - hashcrush - Compute Argon2id hashes
(HTM) git clone git://git.z3bra.org/hashcrush.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
thashgen.go (2591B)
---
1 /*
2 * Copyright: this software is in the public domain
3 *
4 * Generate argon2id hashes from a given password
5 * Salt may be provided, or generated randomly
6 * Output format:
7 *
8 * $argon2<T>[$v=<num>]$m=<num>,t=<num>,p=<num>$<hex>$<hex>
9 *
10 * by wgs
11 */
12
13 package main
14
15 import (
16 "crypto/rand"
17 "encoding/base64"
18 "flag"
19 "fmt"
20 "log"
21 "os"
22
23 "golang.org/x/crypto/chacha20poly1305"
24 "golang.org/x/crypto/argon2"
25 "golang.org/x/term"
26 )
27
28 const (
29 // recommended for memory constrained environments, as per RFC9106
30 argon2id_memory_cost = 65536 // 64 Kib
31 argon2id_time_cost = 3
32 argon2id_threads = 4
33 argon2id_salt_len = 16
34 )
35
36 func usage() {
37 fmt.Printf("usage: %s [-hed] [-b size] [-j thread] [-t time] [-m memory] [-p pass] [-s salt] [-f file]\n", os.Args[0])
38 os.Exit(2)
39 }
40
41 func deriv(pw []byte, key *[]byte, time, mem, job uint32, salt []byte) {
42 klen := len(*key)
43 *key = argon2.IDKey(pw, salt, time, mem, uint8(job), uint32(klen))
44 }
45
46 func main() {
47 var err error
48 var salt [16]byte
49 var key, pass []byte
50 var password, saltfile string
51
52 var time uint64
53 var memory uint64
54 var jobnum uint64
55
56 key = make([]byte, chacha20poly1305.KeySize)
57
58 flag.StringVar(&password, "p", "", "Password")
59 flag.StringVar(&saltfile, "s", "", "Read salt from file")
60
61 // argon2id parameters
62 flag.Uint64Var(&memory, "m", argon2id_memory_cost, "Memory cost")
63 flag.Uint64Var(&time, "t", argon2id_time_cost, "Time cost")
64 flag.Uint64Var(&jobnum, "j", argon2id_threads, "Parallel threads")
65
66 flag.Usage = usage
67 flag.Parse()
68
69 args := flag.Args()
70 if len(args) > 0 {
71 usage()
72 }
73
74 pass = []byte(password)
75
76 // Prompt user for password if provided password is empty
77 if len(pass) == 0 {
78 tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0644)
79 if err != nil {
80 log.Fatal(err)
81 }
82 defer tty.Close()
83 fmt.Fprint(tty, "password:")
84 pass, _ = term.ReadPassword(int(tty.Fd()))
85 fmt.Fprintln(tty, "")
86 }
87
88 if len(saltfile) > 0 {
89 // Read salt from any manually specified file…
90 f, err := os.Open(saltfile)
91 if err != nil {
92 log.Fatal(err)
93 }
94 _, err = f.Read(salt[:])
95 f.Close()
96 } else {
97 // … or generate a random one
98 _, err = rand.Read(salt[:])
99 if err != nil {
100 log.Fatal(err)
101 }
102 }
103
104 deriv(pass, &key, uint32(time), uint32(memory), uint32(jobnum), salt[:])
105
106 b64_s := base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(salt[:])
107 b64_k := base64.StdEncoding.WithPadding(base64.NoPadding).EncodeToString(key[:])
108
109 fmt.Printf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s\n", argon2.Version, memory, time, jobnum, b64_s, b64_k)
110 }