1 // Copyright 2021 by David A. Golden. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 // Package pbkdf2 implements password-based key derivation using the PBKDF2 8 // algorithm described in RFC 2898 and RFC 8018. 9 // 10 // It provides a drop-in replacement for `golang.org/x/crypto/pbkdf2`, with 11 // the following benefits: 12 // 13 // - Released as a module with semantic versioning 14 // 15 // - Does not pull in dependencies for unrelated `x/crypto/*` packages 16 // 17 // - Supports Go 1.9+ 18 // 19 // See https://tools.ietf.org/html/rfc8018#section-4 for security considerations 20 // in the selection of a salt and iteration count. 21 package pbkdf2 22 23 import ( 24 "crypto/hmac" 25 "encoding/binary" 26 "hash" 27 ) 28 29 // Key generates a derived key from a password using the PBKDF2 algorithm. The 30 // inputs include salt bytes, the iteration count, desired key length, and a 31 // constructor for a hashing function. For example, for a 32-byte key using 32 // SHA-256: 33 // 34 // key := Key([]byte("trustNo1"), salt, 10000, 32, sha256.New) 35 func Key(password, salt []byte, iterCount, keyLen int, h func() hash.Hash) []byte { 36 prf := hmac.New(h, password) 37 hLen := prf.Size() 38 numBlocks := keyLen / hLen 39 // Get an extra block if keyLen is not an even number of hLen blocks. 40 if keyLen%hLen > 0 { 41 numBlocks++ 42 } 43 44 Ti := make([]byte, hLen) 45 Uj := make([]byte, hLen) 46 dk := make([]byte, 0, hLen*numBlocks) 47 buf := make([]byte, 4) 48 49 for i := uint32(1); i <= uint32(numBlocks); i++ { 50 // Initialize Uj for j == 1 from salt and block index. 51 // Initialize Ti = U1. 52 binary.BigEndian.PutUint32(buf, i) 53 prf.Reset() 54 prf.Write(salt) 55 prf.Write(buf) 56 Uj = Uj[:0] 57 Uj = prf.Sum(Uj) 58 59 // Ti = U1 ^ U2 ^ ... ^ Ux 60 copy(Ti, Uj) 61 for j := 2; j <= iterCount; j++ { 62 prf.Reset() 63 prf.Write(Uj) 64 Uj = Uj[:0] 65 Uj = prf.Sum(Uj) 66 for k := range Uj { 67 Ti[k] ^= Uj[k] 68 } 69 } 70 71 // DK = concat(T1, T2, ... Tn) 72 dk = append(dk, Ti...) 73 } 74 75 return dk[0:keyLen] 76 } 77