1
2
3
4
5 package pbkdf2
6
7 import (
8 "crypto/internal/fips140"
9 "crypto/internal/fips140/hmac"
10 "errors"
11 "hash"
12 )
13
14
15
16
17
18
19 func divRoundUp(x, y int) int {
20 return int((int64(x) + int64(y) - 1) / int64(y))
21 }
22
23 func Key[Hash hash.Hash](h func() Hash, password string, salt []byte, iter, keyLength int) ([]byte, error) {
24 setServiceIndicator(salt, keyLength)
25
26 if keyLength <= 0 {
27 return nil, errors.New("pkbdf2: keyLength must be larger than 0")
28 }
29
30 prf := hmac.New(h, []byte(password))
31 hmac.MarkAsUsedInKDF(prf)
32 hashLen := prf.Size()
33 numBlocks := divRoundUp(keyLength, hashLen)
34 const maxBlocks = int64(1<<32 - 1)
35 if keyLength+hashLen < keyLength || int64(numBlocks) > maxBlocks {
36 return nil, errors.New("pbkdf2: keyLength too long")
37 }
38
39 var buf [4]byte
40 dk := make([]byte, 0, numBlocks*hashLen)
41 U := make([]byte, hashLen)
42 for block := 1; block <= numBlocks; block++ {
43
44
45
46 prf.Reset()
47 prf.Write(salt)
48 buf[0] = byte(block >> 24)
49 buf[1] = byte(block >> 16)
50 buf[2] = byte(block >> 8)
51 buf[3] = byte(block)
52 prf.Write(buf[:4])
53 dk = prf.Sum(dk)
54 T := dk[len(dk)-hashLen:]
55 copy(U, T)
56
57
58 for n := 2; n <= iter; n++ {
59 prf.Reset()
60 prf.Write(U)
61 U = U[:0]
62 U = prf.Sum(U)
63 for x := range U {
64 T[x] ^= U[x]
65 }
66 }
67 }
68 return dk[:keyLength], nil
69 }
70
71 func setServiceIndicator(salt []byte, keyLength int) {
72
73
74
75
76
77 if len(salt) < 128/8 {
78 fips140.RecordNonApproved()
79 }
80
81
82
83 if keyLength < 112/8 {
84 fips140.RecordNonApproved()
85 }
86
87 fips140.RecordApproved()
88 }
89
View as plain text