LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 /* | 5 /* |
6 Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC | 6 Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC |
7 2898 / PKCS #5 v2.0. | 7 2898 / PKCS #5 v2.0. |
8 | 8 |
9 A key derivation function is useful when encrypting data based on a password | 9 A key derivation function is useful when encrypting data based on a password |
10 or any other not-fully-random data. It uses a pseudorandom function to derive | 10 or any other not-fully-random data. It uses a pseudorandom function to derive |
11 a secure encryption key based on the password. | 11 a secure encryption key based on the password. |
12 | 12 |
13 While v2.0 of the standard defines only one pseudorandom function to use, | 13 While v2.0 of the standard defines only one pseudorandom function to use, |
14 HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved | 14 HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved |
15 Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To | 15 Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To |
16 choose, you can pass the `New` functions from the different SHA packages to | 16 choose, you can pass the `New` functions from the different SHA packages to |
17 pbkdf2.New: | 17 pbkdf2.Key. |
18 | |
19 » kdf := pbkdf2.New(sha1.New) | |
20 | |
21 The above gets you a HMAC-SHA-1 based PBKDF2 key derivation function. To use | |
22 it, get a good random salt: | |
23 | |
24 » // A random salt of at least 8 bytes long is recommended | |
25 » salt := make([]byte, 8) | |
26 » _, err := rand.Read(salt)» // this is crypto/rand | |
27 » if err != nil { | |
28 » » panic(err) | |
29 » } | |
30 | |
31 Now you can get a derived key for e.g. AES-256 by doing: | |
32 | |
33 » // AES-256 has a 32-byte key | |
34 » dk := kdf([]byte("some password"), salt, 4096, 32) | |
35 | |
36 Using a higher iteration count will increase the cost of exhaustive search and | |
37 therefor increases security, but choosing one that's too high might make key | |
38 derivation take longer. | |
39 */ | 18 */ |
40 package pbkdf2 | 19 package pbkdf2 |
41 | 20 |
42 import ( | 21 import ( |
43 "crypto/hmac" | 22 "crypto/hmac" |
44 "encoding/binary" | 23 "encoding/binary" |
45 "hash" | 24 "hash" |
46 ) | 25 ) |
47 | 26 |
48 // New creates a Password-Based Key Derivation Function based on HMAC with the | 27 // Key derives a key from the password, salt and iteration count, returning a |
49 // given hashing function. New(sha1.New) will create a key derivation function | 28 // []byte of length keylen that can be used as cryptographic key. The key is |
50 // using HMAC-SHA-1 as pseudo-random function, which is the only option given | 29 // derived based on the method described as PBKDF2 with the HMAC variant using |
51 // in v2.0 of the standard. | 30 // the supplied hash function. |
52 // | 31 // |
53 // The returned function takes four arguments; first two of type []byte and | 32 // For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you |
54 // another two of type int: a password P, salt S, iteration count c and the | 33 // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by |
55 // value dkLen. It returns a derived key dkLen bytes long. | 34 // doing: |
56 func New(h func() hash.Hash) func(P, S []byte, c, dkLen int) []byte { | 35 // |
57 » return func(P, S []byte, c, dkLen int) []byte { | 36 // » dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) |
58 » » PRF := hmac.New(h, P) | 37 // |
59 » » hLen := PRF.Size() | 38 // Remember to get a good random salt. At least 8 bytes is recommended by the |
60 » » l := (dkLen + hLen - 1) / hLen | 39 // RFC. |
| 40 // |
| 41 // Using a higher iteration count will increase the cost of an exhaustive |
| 42 // search but will also make derivation proportionally slower. |
| 43 func Key(password, salt []byte, iter, keylen int, h func() hash.Hash) []byte { |
| 44 » prf := hmac.New(h, password) |
| 45 » hashlen := prf.Size() |
| 46 » nblock := (keylen + hashlen - 1) / hashlen |
61 | 47 |
62 » » DK := make([]byte, 0, dkLen) | 48 » var buf [4]byte |
63 » » for block := 1; block <= l; block += 1 { | 49 » dk := make([]byte, 0, keylen) |
64 » » » // for each block T_i = U_1 ^ U_2 ^ ... ^ U_c | 50 » for block := 1; block <= nblock; block++ { |
65 » » » // U_1 = PRF(P, S || uint(i)) | 51 » » // N.B.: || means concatenation, ^ means XOR |
66 » » » PRF.Reset() | 52 » » // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter |
67 » » » PRF.Write(S) | 53 » » // U_1 = PRF(password, salt || uint(i)) |
68 » » » binary.Write(PRF, binary.BigEndian, uint32(block)) | 54 » » prf.Reset() |
69 » » » U := PRF.Sum(nil) | 55 » » prf.Write(salt) |
70 » » » T := U | 56 » » binary.BigEndian.PutUint32(buf[:], uint32(block)) |
| 57 » » prf.Write(buf[:4]) |
| 58 » » U := prf.Sum(nil) |
| 59 » » T := U |
71 | 60 |
72 » » » // U_n = PRF(P, U_(n-1)) | 61 » » // U_n = PRF(password, U_(n-1)) |
73 » » » for n := 2; n <= c; n += 1 { | 62 » » for n := 2; n <= iter; n++ { |
74 » » » » PRF.Reset() | 63 » » » prf.Reset() |
75 » » » » PRF.Write(U) | 64 » » » prf.Write(U) |
76 » » » » U = PRF.Sum(nil) | 65 » » » U = prf.Sum(nil) |
77 » » » » for x := range U { | 66 » » » for x := range U { |
78 » » » » » T[x] ^= U[x] | 67 » » » » T[x] ^= U[x] |
79 » » » » } | |
80 } | 68 } |
81 // Derived key = T_1 || T_2 || ... || T_l | |
82 // N.B.: || means concatenation | |
83 DK = append(DK, T...) | |
84 } | 69 } |
85 » » return DK[:dkLen] | 70 » » // Derived key = T_1 || T_2 || ... || T_l |
| 71 » » dk = append(dk, T...) |
86 } | 72 } |
| 73 return dk[:keylen] |
87 } | 74 } |
LEFT | RIGHT |