Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
6.3 KiB

  1. // pwdbased.h - written and placed in the public domain by Wei Dai
  2. #ifndef CRYPTOPP_PWDBASED_H
  3. #define CRYPTOPP_PWDBASED_H
  4. #include "cryptlib.h"
  5. #include "hmac.h"
  6. #include "hrtimer.h"
  7. #include "integer.h"
  8. NAMESPACE_BEGIN(CryptoPP)
  9. //! abstract base class for password based key derivation function
  10. class PasswordBasedKeyDerivationFunction
  11. {
  12. public:
  13. virtual size_t MaxDerivedKeyLength() const =0;
  14. virtual bool UsesPurposeByte() const =0;
  15. //! derive key from password
  16. /*! If timeInSeconds != 0, will iterate until time elapsed, as measured by ThreadUserTimer
  17. Returns actual iteration count, which is equal to iterations if timeInSeconds == 0, and not less than iterations otherwise. */
  18. virtual unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const =0;
  19. };
  20. //! PBKDF1 from PKCS #5, T should be a HashTransformation class
  21. template <class T>
  22. class PKCS5_PBKDF1 : public PasswordBasedKeyDerivationFunction
  23. {
  24. public:
  25. size_t MaxDerivedKeyLength() const {return T::DIGESTSIZE;}
  26. bool UsesPurposeByte() const {return false;}
  27. // PKCS #5 says PBKDF1 should only take 8-byte salts. This implementation allows salts of any length.
  28. unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
  29. };
  30. //! PBKDF2 from PKCS #5, T should be a HashTransformation class
  31. template <class T>
  32. class PKCS5_PBKDF2_HMAC : public PasswordBasedKeyDerivationFunction
  33. {
  34. public:
  35. size_t MaxDerivedKeyLength() const {return 0xffffffffU;} // should multiply by T::DIGESTSIZE, but gets overflow that way
  36. bool UsesPurposeByte() const {return false;}
  37. unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds=0) const;
  38. };
  39. /*
  40. class PBKDF2Params
  41. {
  42. public:
  43. SecByteBlock m_salt;
  44. unsigned int m_interationCount;
  45. ASNOptional<ASNUnsignedWrapper<word32> > m_keyLength;
  46. };
  47. */
  48. template <class T>
  49. unsigned int PKCS5_PBKDF1<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
  50. {
  51. assert(derivedLen <= MaxDerivedKeyLength());
  52. assert(iterations > 0 || timeInSeconds > 0);
  53. if (!iterations)
  54. iterations = 1;
  55. T hash;
  56. hash.Update(password, passwordLen);
  57. hash.Update(salt, saltLen);
  58. SecByteBlock buffer(hash.DigestSize());
  59. hash.Final(buffer);
  60. unsigned int i;
  61. ThreadUserTimer timer;
  62. if (timeInSeconds)
  63. timer.StartTimer();
  64. for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
  65. hash.CalculateDigest(buffer, buffer, buffer.size());
  66. memcpy(derived, buffer, derivedLen);
  67. return i;
  68. }
  69. template <class T>
  70. unsigned int PKCS5_PBKDF2_HMAC<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
  71. {
  72. assert(derivedLen <= MaxDerivedKeyLength());
  73. assert(iterations > 0 || timeInSeconds > 0);
  74. if (!iterations)
  75. iterations = 1;
  76. HMAC<T> hmac(password, passwordLen);
  77. SecByteBlock buffer(hmac.DigestSize());
  78. ThreadUserTimer timer;
  79. unsigned int i=1;
  80. while (derivedLen > 0)
  81. {
  82. hmac.Update(salt, saltLen);
  83. unsigned int j;
  84. for (j=0; j<4; j++)
  85. {
  86. byte b = byte(i >> ((3-j)*8));
  87. hmac.Update(&b, 1);
  88. }
  89. hmac.Final(buffer);
  90. size_t segmentLen = STDMIN(derivedLen, buffer.size());
  91. memcpy(derived, buffer, segmentLen);
  92. if (timeInSeconds)
  93. {
  94. timeInSeconds = timeInSeconds / ((derivedLen + buffer.size() - 1) / buffer.size());
  95. timer.StartTimer();
  96. }
  97. for (j=1; j<iterations || (timeInSeconds && (j%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); j++)
  98. {
  99. hmac.CalculateDigest(buffer, buffer, buffer.size());
  100. xorbuf(derived, buffer, segmentLen);
  101. }
  102. if (timeInSeconds)
  103. {
  104. iterations = j;
  105. timeInSeconds = 0;
  106. }
  107. derived += segmentLen;
  108. derivedLen -= segmentLen;
  109. i++;
  110. }
  111. return iterations;
  112. }
  113. //! PBKDF from PKCS #12, appendix B, T should be a HashTransformation class
  114. template <class T>
  115. class PKCS12_PBKDF : public PasswordBasedKeyDerivationFunction
  116. {
  117. public:
  118. size_t MaxDerivedKeyLength() const {return size_t(0)-1;}
  119. bool UsesPurposeByte() const {return true;}
  120. unsigned int DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const;
  121. };
  122. template <class T>
  123. unsigned int PKCS12_PBKDF<T>::DeriveKey(byte *derived, size_t derivedLen, byte purpose, const byte *password, size_t passwordLen, const byte *salt, size_t saltLen, unsigned int iterations, double timeInSeconds) const
  124. {
  125. assert(derivedLen <= MaxDerivedKeyLength());
  126. assert(iterations > 0 || timeInSeconds > 0);
  127. if (!iterations)
  128. iterations = 1;
  129. const size_t v = T::BLOCKSIZE; // v is in bytes rather than bits as in PKCS #12
  130. const size_t DLen = v, SLen = RoundUpToMultipleOf(saltLen, v);
  131. const size_t PLen = RoundUpToMultipleOf(passwordLen, v), ILen = SLen + PLen;
  132. SecByteBlock buffer(DLen + SLen + PLen);
  133. byte *D = buffer, *S = buffer+DLen, *P = buffer+DLen+SLen, *I = S;
  134. memset(D, purpose, DLen);
  135. size_t i;
  136. for (i=0; i<SLen; i++)
  137. S[i] = salt[i % saltLen];
  138. for (i=0; i<PLen; i++)
  139. P[i] = password[i % passwordLen];
  140. T hash;
  141. SecByteBlock Ai(T::DIGESTSIZE), B(v);
  142. ThreadUserTimer timer;
  143. while (derivedLen > 0)
  144. {
  145. hash.CalculateDigest(Ai, buffer, buffer.size());
  146. if (timeInSeconds)
  147. {
  148. timeInSeconds = timeInSeconds / ((derivedLen + Ai.size() - 1) / Ai.size());
  149. timer.StartTimer();
  150. }
  151. for (i=1; i<iterations || (timeInSeconds && (i%128!=0 || timer.ElapsedTimeAsDouble() < timeInSeconds)); i++)
  152. hash.CalculateDigest(Ai, Ai, Ai.size());
  153. if (timeInSeconds)
  154. {
  155. iterations = (unsigned int)i;
  156. timeInSeconds = 0;
  157. }
  158. for (i=0; i<B.size(); i++)
  159. B[i] = Ai[i % Ai.size()];
  160. Integer B1(B, B.size());
  161. ++B1;
  162. for (i=0; i<ILen; i+=v)
  163. (Integer(I+i, v) + B1).Encode(I+i, v);
  164. size_t segmentLen = STDMIN(derivedLen, Ai.size());
  165. memcpy(derived, Ai, segmentLen);
  166. derived += segmentLen;
  167. derivedLen -= segmentLen;
  168. }
  169. return iterations;
  170. }
  171. NAMESPACE_END
  172. #endif