12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- // Copyright 2021 by David A. Golden. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you may
- // not use this file except in compliance with the License. You may obtain
- // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
-
- // Package pbkdf2 implements password-based key derivation using the PBKDF2
- // algorithm described in RFC 2898 and RFC 8018.
- //
- // It provides a drop-in replacement for `golang.org/x/crypto/pbkdf2`, with
- // the following benefits:
- //
- // - Released as a module with semantic versioning
- //
- // - Does not pull in dependencies for unrelated `x/crypto/*` packages
- //
- // - Supports Go 1.9+
- //
- // See https://tools.ietf.org/html/rfc8018#section-4 for security considerations
- // in the selection of a salt and iteration count.
- package pbkdf2
-
- import (
- "crypto/hmac"
- "encoding/binary"
- "hash"
- )
-
- // Key generates a derived key from a password using the PBKDF2 algorithm. The
- // inputs include salt bytes, the iteration count, desired key length, and a
- // constructor for a hashing function. For example, for a 32-byte key using
- // SHA-256:
- //
- // key := Key([]byte("trustNo1"), salt, 10000, 32, sha256.New)
- func Key(password, salt []byte, iterCount, keyLen int, h func() hash.Hash) []byte {
- prf := hmac.New(h, password)
- hLen := prf.Size()
- numBlocks := keyLen / hLen
- // Get an extra block if keyLen is not an even number of hLen blocks.
- if keyLen%hLen > 0 {
- numBlocks++
- }
-
- Ti := make([]byte, hLen)
- Uj := make([]byte, hLen)
- dk := make([]byte, 0, hLen*numBlocks)
- buf := make([]byte, 4)
-
- for i := uint32(1); i <= uint32(numBlocks); i++ {
- // Initialize Uj for j == 1 from salt and block index.
- // Initialize Ti = U1.
- binary.BigEndian.PutUint32(buf, i)
- prf.Reset()
- prf.Write(salt)
- prf.Write(buf)
- Uj = Uj[:0]
- Uj = prf.Sum(Uj)
-
- // Ti = U1 ^ U2 ^ ... ^ Ux
- copy(Ti, Uj)
- for j := 2; j <= iterCount; j++ {
- prf.Reset()
- prf.Write(Uj)
- Uj = Uj[:0]
- Uj = prf.Sum(Uj)
- for k := range Uj {
- Ti[k] ^= Uj[k]
- }
- }
-
- // DK = concat(T1, T2, ... Tn)
- dk = append(dk, Ti...)
- }
-
- return dk[0:keyLen]
- }
|