decred.org/dcrwallet/v3@v3.1.0/kdf/kdf.go (about) 1 // Copyright (c) 2020 The Decred developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package kdf 6 7 import ( 8 "encoding/binary" 9 "errors" 10 "io" 11 "runtime" 12 13 "golang.org/x/crypto/argon2" 14 ) 15 16 // Argon2idParams describes the difficulty and parallelism requirements for the 17 // Argin2id KDF. 18 type Argon2idParams struct { 19 Salt [16]byte 20 Time uint32 21 Memory uint32 22 Threads uint8 23 } 24 25 // NewArgon2idParams returns the minimum recommended parameters for the Argon2id 26 // KDF with a random salt. Randomness is read from rand. 27 // 28 // The time and memory parameters may be increased by an application when stronger 29 // security requirements are desired, and additional memory is available. 30 func NewArgon2idParams(rand io.Reader) (*Argon2idParams, error) { 31 ncpu := runtime.NumCPU() 32 if ncpu > 256 { 33 ncpu = 256 34 } 35 p := &Argon2idParams{ 36 Time: 1, 37 Memory: 256 * 1024, // 256 MiB 38 Threads: uint8(ncpu), 39 } 40 _, err := rand.Read(p.Salt[:]) 41 return p, err 42 } 43 44 // MarshaledLen is the length of the marshaled KDF parameters. 45 const MarshaledLen = 25 46 47 // MarshalBinary implements encoding.BinaryMarshaler. 48 // The returned byte slice has length MarshaledLen. 49 func (p *Argon2idParams) MarshalBinary() ([]byte, error) { 50 b := make([]byte, MarshaledLen) 51 copy(b, p.Salt[:]) 52 binary.LittleEndian.PutUint32(b[16:16+4], p.Time) 53 binary.LittleEndian.PutUint32(b[16+4:16+8], p.Memory) 54 b[16+8] = p.Threads 55 return b, nil 56 } 57 58 // UnmarshalBinary implements encoding.BinaryUnmarshaler. 59 func (p *Argon2idParams) UnmarshalBinary(data []byte) error { 60 if len(data) != MarshaledLen { 61 return errors.New("invalid marshaled Argon2id parameters") 62 } 63 copy(p.Salt[:], data) 64 p.Time = binary.LittleEndian.Uint32(data[16:]) 65 p.Memory = binary.LittleEndian.Uint32(data[16+4:]) 66 p.Threads = data[16+8] 67 return nil 68 } 69 70 // DeriveKey derives a key of len bytes from a passphrase and KDF parameters. 71 func DeriveKey(password []byte, p *Argon2idParams, len uint32) []byte { 72 defer runtime.GC() 73 return argon2.IDKey(password, p.Salt[:], p.Time, p.Memory, p.Threads, len) 74 }