pbkdf2.go (2483B)
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 // import "golang.org/x/crypto/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 prf := hmac.New(h, password) 44 hashLen := prf.Size() 45 numBlocks := (keyLen + hashLen - 1) / hashLen 46 47 var buf [4]byte 48 dk := make([]byte, 0, numBlocks*hashLen) 49 U := make([]byte, hashLen) 50 for block := 1; block <= numBlocks; block++ { 51 // N.B.: || means concatenation, ^ means XOR 52 // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter 53 // U_1 = PRF(password, salt || uint(i)) 54 prf.Reset() 55 prf.Write(salt) 56 buf[0] = byte(block >> 24) 57 buf[1] = byte(block >> 16) 58 buf[2] = byte(block >> 8) 59 buf[3] = byte(block) 60 prf.Write(buf[:4]) 61 dk = prf.Sum(dk) 62 T := dk[len(dk)-hashLen:] 63 copy(U, T) 64 65 // U_n = PRF(password, U_(n-1)) 66 for n := 2; n <= iter; n++ { 67 prf.Reset() 68 prf.Write(U) 69 U = U[:0] 70 U = prf.Sum(U) 71 for x := range U { 72 T[x] ^= U[x] 73 } 74 } 75 } 76 return dk[:keyLen] 77 }