// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package argon2 implements the key derivation function Argon2. // Argon2 was selected as the winner of the Password Hashing Competition and can // be used to derive cryptographic keys from passwords. // // For a detailed specification of Argon2 see [1]. // // If you aren't sure which function you need, use Argon2id (IDKey) and // the parameter recommendations for your scenario. // // # Argon2i // // Argon2i (implemented by Key) is the side-channel resistant version of Argon2. // It uses data-independent memory access, which is preferred for password // hashing and password-based key derivation. Argon2i requires more passes over // memory than Argon2id to protect from trade-off attacks. The recommended // parameters (taken from [2]) for non-interactive operations are time=3 and to // use the maximum available memory. // // # Argon2id // // Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining // Argon2i and Argon2d. It uses data-independent memory access for the first // half of the first iteration over the memory and data-dependent memory access // for the rest. Argon2id is side-channel resistant and provides better brute- // force cost savings due to time-memory tradeoffs than Argon2i. The recommended // parameters for non-interactive operations (taken from [2]) are time=1 and to // use the maximum available memory. // // [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf // [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
package argon2 import ( ) // The Argon2 version implemented by this package. const Version = 0x13 const ( argon2d = iota argon2i argon2id ) // Key derives a key from the password, salt, and cost parameters using Argon2i // returning a byte slice of length keyLen that can be used as cryptographic // key. The CPU cost and parallelism degree must be greater than zero. // // For example, you can get a derived key for e.g. AES-256 (which needs a // 32-byte key) by doing: // // key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32) // // The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number. // If using that amount of memory (32 MB) is not possible in some contexts then // the time parameter can be increased to compensate. // // The time parameter specifies the number of passes over the memory and the // memory parameter specifies the size of the memory in KiB. For example // memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be // adjusted to the number of available CPUs. The cost parameters should be // increased as memory latency and CPU parallelism increases. Remember to get a // good random salt. func (, []byte, , uint32, uint8, uint32) []byte { return deriveKey(argon2i, , , nil, nil, , , , ) } // IDKey derives a key from the password, salt, and cost parameters using // Argon2id returning a byte slice of length keyLen that can be used as // cryptographic key. The CPU cost and parallelism degree must be greater than // zero. // // For example, you can get a derived key for e.g. AES-256 (which needs a // 32-byte key) by doing: // // key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32) // // The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number. // If using that amount of memory (64 MB) is not possible in some contexts then // the time parameter can be increased to compensate. // // The time parameter specifies the number of passes over the memory and the // memory parameter specifies the size of the memory in KiB. For example // memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be // adjusted to the numbers of available CPUs. The cost parameters should be // increased as memory latency and CPU parallelism increases. Remember to get a // good random salt. func (, []byte, , uint32, uint8, uint32) []byte { return deriveKey(argon2id, , , nil, nil, , , , ) } func ( int, , , , []byte, , uint32, uint8, uint32) []byte { if < 1 { panic("argon2: number of rounds too small") } if < 1 { panic("argon2: parallelism degree too low") } := initHash(, , , , , , uint32(), , ) = / (syncPoints * uint32()) * (syncPoints * uint32()) if < 2*syncPoints*uint32() { = 2 * syncPoints * uint32() } := initBlocks(&, , uint32()) processBlocks(, , , uint32(), ) return extractKey(, , uint32(), ) } const ( blockLength = 128 syncPoints = 4 ) type block [blockLength]uint64 func (, , , []byte, , , , uint32, int) [blake2b.Size + 8]byte { var ( [blake2b.Size + 8]byte [24]byte [4]byte ) , := blake2b.New512(nil) binary.LittleEndian.PutUint32([0:4], ) binary.LittleEndian.PutUint32([4:8], ) binary.LittleEndian.PutUint32([8:12], ) binary.LittleEndian.PutUint32([12:16], ) binary.LittleEndian.PutUint32([16:20], uint32(Version)) binary.LittleEndian.PutUint32([20:24], uint32()) .Write([:]) binary.LittleEndian.PutUint32([:], uint32(len())) .Write([:]) .Write() binary.LittleEndian.PutUint32([:], uint32(len())) .Write([:]) .Write() binary.LittleEndian.PutUint32([:], uint32(len())) .Write([:]) .Write() binary.LittleEndian.PutUint32([:], uint32(len())) .Write([:]) .Write() .Sum([:0]) return } func ( *[blake2b.Size + 8]byte, , uint32) []block { var [1024]byte := make([]block, ) for := uint32(0); < ; ++ { := * ( / ) binary.LittleEndian.PutUint32([blake2b.Size+4:], ) binary.LittleEndian.PutUint32([blake2b.Size:], 0) blake2bHash([:], [:]) for := range [+0] { [+0][] = binary.LittleEndian.Uint64([*8:]) } binary.LittleEndian.PutUint32([blake2b.Size:], 1) blake2bHash([:], [:]) for := range [+1] { [+1][] = binary.LittleEndian.Uint64([*8:]) } } return } func ( []block, , , uint32, int) { := / := / syncPoints := func(, , uint32, *sync.WaitGroup) { var , , block if == argon2i || ( == argon2id && == 0 && < syncPoints/2) { [0] = uint64() [1] = uint64() [2] = uint64() [3] = uint64() [4] = uint64() [5] = uint64() } := uint32(0) if == 0 && == 0 { = 2 // we have already generated the first two blocks if == argon2i || == argon2id { [6]++ processBlock(&, &, &) processBlock(&, &, &) } } := * + * + var uint64 for < { := - 1 if == 0 && == 0 { += // last block in lane } if == argon2i || ( == argon2id && == 0 && < syncPoints/2) { if %blockLength == 0 { [6]++ processBlock(&, &, &) processBlock(&, &, &) } = [%blockLength] } else { = [][0] } := indexAlpha(, , , , , , , ) processBlockXOR(&[], &[], &[]) , = +1, +1 } .Done() } for := uint32(0); < ; ++ { for := uint32(0); < syncPoints; ++ { var sync.WaitGroup for := uint32(0); < ; ++ { .Add(1) go (, , , &) } .Wait() } } } func ( []block, , , uint32) []byte { := / for := uint32(0); < -1; ++ { for , := range [(*)+-1] { [-1][] ^= } } var [1024]byte for , := range [-1] { binary.LittleEndian.PutUint64([*8:], ) } := make([]byte, ) blake2bHash(, [:]) return } func ( uint64, , , , , , , uint32) uint32 { := uint32(>>32) % if == 0 && == 0 { = } , := 3*, ((+1)%syncPoints)* if == { += } if == 0 { , = *, 0 if == 0 || == { += } } if == 0 || == { -- } return phi(, uint64(), uint64(), , ) } func (, , uint64, , uint32) uint32 { := & 0xFFFFFFFF = ( * ) >> 32 = ( * ) >> 32 return * + uint32((+-(+1))%uint64()) }