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 }