Team Fortress 2 Source Code as on 22/4/2020
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.

100 lines
3.3 KiB

  1. // hkdf.h - written and placed in public domain by Jeffrey Walton. Copyright assigned to Crypto++ project.
  2. #ifndef CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H
  3. #define CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H
  4. #include "cryptlib.h"
  5. #include "hrtimer.h"
  6. #include "secblock.h"
  7. #include "hmac.h"
  8. NAMESPACE_BEGIN(CryptoPP)
  9. //! abstract base class for key derivation function
  10. class KeyDerivationFunction
  11. {
  12. public:
  13. //! maximum number of bytes which can be produced under a secuirty context
  14. virtual size_t MaxDerivedKeyLength() const =0;
  15. virtual bool Usesinfo() const =0;
  16. //! derive a key from secret
  17. virtual unsigned int DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, const byte* info=NULL, size_t infoLen=0) const =0;
  18. virtual ~KeyDerivationFunction() {}
  19. };
  20. //! General, multipurpose KDF from RFC 5869. T should be a HashTransformation class
  21. //! https://eprint.iacr.org/2010/264 and https://tools.ietf.org/html/rfc5869
  22. template <class T>
  23. class HKDF : public KeyDerivationFunction
  24. {
  25. public:
  26. static const char* StaticAlgorithmName () {
  27. static const std::string name(std::string("HKDF(") + std::string(T::StaticAlgorithmName()) + std::string(")"));
  28. return name.c_str();
  29. }
  30. size_t MaxDerivedKeyLength() const {return static_cast<size_t>(T::DIGESTSIZE) * 255;}
  31. bool Usesinfo() const {return true;}
  32. unsigned int DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const;
  33. protected:
  34. // If salt is missing (NULL), then use the NULL vector. Missing is different than EMPTY (0 length). The length
  35. // of s_NullVector used depends on the Hash function. SHA-256 will use 32 bytes of s_NullVector.
  36. typedef byte NullVectorType[T::DIGESTSIZE];
  37. static const NullVectorType& GetNullVector() {
  38. static const NullVectorType s_NullVector = {0};
  39. return s_NullVector;
  40. }
  41. };
  42. template <class T>
  43. unsigned int HKDF<T>::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const byte *salt, size_t saltLen, const byte* info, size_t infoLen) const
  44. {
  45. static const size_t DIGEST_SIZE = static_cast<size_t>(T::DIGESTSIZE);
  46. const unsigned int req = static_cast<unsigned int>(derivedLen);
  47. assert(secret && secretLen);
  48. assert(derived && derivedLen);
  49. assert(derivedLen <= MaxDerivedKeyLength());
  50. if (derivedLen > MaxDerivedKeyLength())
  51. throw InvalidArgument("HKDF: derivedLen must be less than or equal to MaxDerivedKeyLength");
  52. HMAC<T> hmac;
  53. FixedSizeSecBlock<byte, DIGEST_SIZE> prk, buffer;
  54. // Extract
  55. const byte* key = (salt ? salt : GetNullVector());
  56. const size_t klen = (salt ? saltLen : DIGEST_SIZE);
  57. hmac.SetKey(key, klen);
  58. hmac.CalculateDigest(prk, secret, secretLen);
  59. // Expand
  60. hmac.SetKey(prk.data(), prk.size());
  61. byte block = 0;
  62. while (derivedLen > 0)
  63. {
  64. if (block++) {hmac.Update(buffer, buffer.size());}
  65. if (info && infoLen) {hmac.Update(info, infoLen);}
  66. hmac.CalculateDigest(buffer, &block, 1);
  67. #if CRYPTOPP_MSC_VERSION
  68. const size_t segmentLen = STDMIN(derivedLen, DIGEST_SIZE);
  69. memcpy_s(derived, segmentLen, buffer, segmentLen);
  70. #else
  71. const size_t segmentLen = STDMIN(derivedLen, DIGEST_SIZE);
  72. std::memcpy(derived, buffer, segmentLen);
  73. #endif
  74. derived += segmentLen;
  75. derivedLen -= segmentLen;
  76. }
  77. return req;
  78. }
  79. NAMESPACE_END
  80. #endif // CRYPTOPP_HASH_KEY_DERIVATION_FUNCTION_H