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