Scott Baker | 8487c5d | 2019-10-18 12:49:46 -0700 | [diff] [blame] | 1 | // Copyright 2012 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | /* |
| 6 | Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC |
| 7 | 2898 / PKCS #5 v2.0. |
| 8 | |
| 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 |
| 11 | a secure encryption key based on the password. |
| 12 | |
| 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 |
| 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 |
| 17 | pbkdf2.Key. |
| 18 | */ |
| 19 | package pbkdf2 |
| 20 | |
| 21 | import ( |
| 22 | "crypto/hmac" |
| 23 | "hash" |
| 24 | ) |
| 25 | |
| 26 | // Key derives a key from the password, salt and iteration count, returning a |
| 27 | // []byte of length keylen that can be used as cryptographic key. The key is |
| 28 | // derived based on the method described as PBKDF2 with the HMAC variant using |
| 29 | // the supplied hash function. |
| 30 | // |
| 31 | // For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you |
| 32 | // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by |
| 33 | // doing: |
| 34 | // |
| 35 | // dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) |
| 36 | // |
| 37 | // Remember to get a good random salt. At least 8 bytes is recommended by the |
| 38 | // RFC. |
| 39 | // |
| 40 | // Using a higher iteration count will increase the cost of an exhaustive |
| 41 | // search but will also make derivation proportionally slower. |
| 42 | func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { |
| 43 | return Key64(password, salt, int64(iter), int64(keyLen), h) |
| 44 | } |
| 45 | |
| 46 | // Key64 derives a key from the password, salt and iteration count, returning a |
| 47 | // []byte of length keylen that can be used as cryptographic key. Key64 uses |
| 48 | // int64 for the iteration count and key length to allow larger values. |
| 49 | // The key is derived based on the method described as PBKDF2 with the HMAC |
| 50 | // variant using the supplied hash function. |
| 51 | // |
| 52 | // For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you |
| 53 | // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by |
| 54 | // doing: |
| 55 | // |
| 56 | // dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) |
| 57 | // |
| 58 | // Remember to get a good random salt. At least 8 bytes is recommended by the |
| 59 | // RFC. |
| 60 | // |
| 61 | // Using a higher iteration count will increase the cost of an exhaustive |
| 62 | // search but will also make derivation proportionally slower. |
| 63 | func Key64(password, salt []byte, iter, keyLen int64, h func() hash.Hash) []byte { |
| 64 | prf := hmac.New(h, password) |
| 65 | hashLen := int64(prf.Size()) |
| 66 | numBlocks := (keyLen + hashLen - 1) / hashLen |
| 67 | |
| 68 | var buf [4]byte |
| 69 | dk := make([]byte, 0, numBlocks*hashLen) |
| 70 | U := make([]byte, hashLen) |
| 71 | for block := int64(1); block <= numBlocks; block++ { |
| 72 | // N.B.: || means concatenation, ^ means XOR |
| 73 | // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter |
| 74 | // U_1 = PRF(password, salt || uint(i)) |
| 75 | prf.Reset() |
| 76 | prf.Write(salt) |
| 77 | buf[0] = byte(block >> 24) |
| 78 | buf[1] = byte(block >> 16) |
| 79 | buf[2] = byte(block >> 8) |
| 80 | buf[3] = byte(block) |
| 81 | prf.Write(buf[:4]) |
| 82 | dk = prf.Sum(dk) |
| 83 | T := dk[int64(len(dk))-hashLen:] |
| 84 | copy(U, T) |
| 85 | |
| 86 | // U_n = PRF(password, U_(n-1)) |
| 87 | for n := int64(2); n <= iter; n++ { |
| 88 | prf.Reset() |
| 89 | prf.Write(U) |
| 90 | U = U[:0] |
| 91 | U = prf.Sum(U) |
| 92 | for x := range U { |
| 93 | T[x] ^= U[x] |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | return dk[:keyLen] |
| 98 | } |