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  }