pbkdf2.go 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
  6. 2898 / PKCS #5 v2.0.
  7. A key derivation function is useful when encrypting data based on a password
  8. or any other not-fully-random data. It uses a pseudorandom function to derive
  9. a secure encryption key based on the password.
  10. While v2.0 of the standard defines only one pseudorandom function to use,
  11. HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
  12. Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
  13. choose, you can pass the `New` functions from the different SHA packages to
  14. pbkdf2.Key.
  15. */
  16. package pbkdf2
  17. import (
  18. "crypto/hmac"
  19. "hash"
  20. )
  21. // Key derives a key from the password, salt and iteration count, returning a
  22. // []byte of length keylen that can be used as cryptographic key. The key is
  23. // derived based on the method described as PBKDF2 with the HMAC variant using
  24. // the supplied hash function.
  25. //
  26. // For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
  27. // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
  28. // doing:
  29. //
  30. // dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
  31. //
  32. // Remember to get a good random salt. At least 8 bytes is recommended by the
  33. // RFC.
  34. //
  35. // Using a higher iteration count will increase the cost of an exhaustive
  36. // search but will also make derivation proportionally slower.
  37. func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
  38. return Key64(password, salt, int64(iter), int64(keyLen), h)
  39. }
  40. // Key64 derives a key from the password, salt and iteration count, returning a
  41. // []byte of length keylen that can be used as cryptographic key. Key64 uses
  42. // int64 for the iteration count and key length to allow larger values.
  43. // The key is derived based on the method described as PBKDF2 with the HMAC
  44. // variant using the supplied hash function.
  45. //
  46. // For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
  47. // can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
  48. // doing:
  49. //
  50. // dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
  51. //
  52. // Remember to get a good random salt. At least 8 bytes is recommended by the
  53. // RFC.
  54. //
  55. // Using a higher iteration count will increase the cost of an exhaustive
  56. // search but will also make derivation proportionally slower.
  57. func Key64(password, salt []byte, iter, keyLen int64, h func() hash.Hash) []byte {
  58. prf := hmac.New(h, password)
  59. hashLen := int64(prf.Size())
  60. numBlocks := (keyLen + hashLen - 1) / hashLen
  61. var buf [4]byte
  62. dk := make([]byte, 0, numBlocks*hashLen)
  63. U := make([]byte, hashLen)
  64. for block := int64(1); block <= numBlocks; block++ {
  65. // N.B.: || means concatenation, ^ means XOR
  66. // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
  67. // U_1 = PRF(password, salt || uint(i))
  68. prf.Reset()
  69. prf.Write(salt)
  70. buf[0] = byte(block >> 24)
  71. buf[1] = byte(block >> 16)
  72. buf[2] = byte(block >> 8)
  73. buf[3] = byte(block)
  74. prf.Write(buf[:4])
  75. dk = prf.Sum(dk)
  76. T := dk[int64(len(dk))-hashLen:]
  77. copy(U, T)
  78. // U_n = PRF(password, U_(n-1))
  79. for n := int64(2); n <= iter; n++ {
  80. prf.Reset()
  81. prf.Write(U)
  82. U = U[:0]
  83. U = prf.Sum(U)
  84. for x := range U {
  85. T[x] ^= U[x]
  86. }
  87. }
  88. }
  89. return dk[:keyLen]
  90. }