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.

161 lines
5.9 KiB

  1. // pssr.cpp - written and placed in the public domain by Wei Dai
  2. #include "pch.h"
  3. #include "pssr.h"
  4. #include "misc.h"
  5. #include <functional>
  6. NAMESPACE_BEGIN(CryptoPP)
  7. // more in dll.cpp
  8. template<> const byte EMSA2HashId<RIPEMD160>::id = 0x31;
  9. template<> const byte EMSA2HashId<RIPEMD128>::id = 0x32;
  10. template<> const byte EMSA2HashId<Whirlpool>::id = 0x37;
  11. #ifndef CRYPTOPP_IMPORTS
  12. size_t PSSR_MEM_Base::MinRepresentativeBitLength(size_t hashIdentifierLength, size_t digestLength) const
  13. {
  14. size_t saltLen = SaltLen(digestLength);
  15. size_t minPadLen = MinPadLen(digestLength);
  16. return 9 + 8*(minPadLen + saltLen + digestLength + hashIdentifierLength);
  17. }
  18. size_t PSSR_MEM_Base::MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const
  19. {
  20. if (AllowRecovery())
  21. return SaturatingSubtract(representativeBitLength, MinRepresentativeBitLength(hashIdentifierLength, digestLength)) / 8;
  22. return 0;
  23. }
  24. bool PSSR_MEM_Base::IsProbabilistic() const
  25. {
  26. return SaltLen(1) > 0;
  27. }
  28. bool PSSR_MEM_Base::AllowNonrecoverablePart() const
  29. {
  30. return true;
  31. }
  32. bool PSSR_MEM_Base::RecoverablePartFirst() const
  33. {
  34. return false;
  35. }
  36. void PSSR_MEM_Base::ComputeMessageRepresentative(RandomNumberGenerator &rng,
  37. const byte *recoverableMessage, size_t recoverableMessageLength,
  38. HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty,
  39. byte *representative, size_t representativeBitLength) const
  40. {
  41. CRYPTOPP_UNUSED(rng), CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(recoverableMessageLength);
  42. CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier);
  43. assert(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize()));
  44. const size_t u = hashIdentifier.second + 1;
  45. const size_t representativeByteLength = BitsToBytes(representativeBitLength);
  46. const size_t digestSize = hash.DigestSize();
  47. const size_t saltSize = SaltLen(digestSize);
  48. byte *const h = representative + representativeByteLength - u - digestSize;
  49. SecByteBlock digest(digestSize), salt(saltSize);
  50. hash.Final(digest);
  51. rng.GenerateBlock(salt, saltSize);
  52. // compute H = hash of M'
  53. byte c[8];
  54. PutWord(false, BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength));
  55. PutWord(false, BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3));
  56. hash.Update(c, 8);
  57. hash.Update(recoverableMessage, recoverableMessageLength);
  58. hash.Update(digest, digestSize);
  59. hash.Update(salt, saltSize);
  60. hash.Final(h);
  61. // compute representative
  62. GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize, false);
  63. byte *xorStart = representative + representativeByteLength - u - digestSize - salt.size() - recoverableMessageLength - 1;
  64. xorStart[0] ^= 1;
  65. if (recoverableMessage && recoverableMessageLength)
  66. xorbuf(xorStart + 1, recoverableMessage, recoverableMessageLength);
  67. xorbuf(xorStart + 1 + recoverableMessageLength, salt, salt.size());
  68. if (hashIdentifier.first && hashIdentifier.second)
  69. {
  70. memcpy(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second);
  71. representative[representativeByteLength - 1] = 0xcc;
  72. }
  73. else
  74. {
  75. representative[representativeByteLength - 1] = 0xbc;
  76. }
  77. if (representativeBitLength % 8 != 0)
  78. representative[0] = (byte)Crop(representative[0], representativeBitLength % 8);
  79. }
  80. DecodingResult PSSR_MEM_Base::RecoverMessageFromRepresentative(
  81. HashTransformation &hash, HashIdentifier hashIdentifier, bool messageEmpty,
  82. byte *representative, size_t representativeBitLength,
  83. byte *recoverableMessage) const
  84. {
  85. CRYPTOPP_UNUSED(recoverableMessage), CRYPTOPP_UNUSED(messageEmpty), CRYPTOPP_UNUSED(hashIdentifier);
  86. assert(representativeBitLength >= MinRepresentativeBitLength(hashIdentifier.second, hash.DigestSize()));
  87. const size_t u = hashIdentifier.second + 1;
  88. const size_t representativeByteLength = BitsToBytes(representativeBitLength);
  89. const size_t digestSize = hash.DigestSize();
  90. const size_t saltSize = SaltLen(digestSize);
  91. const byte *const h = representative + representativeByteLength - u - digestSize;
  92. SecByteBlock digest(digestSize);
  93. hash.Final(digest);
  94. DecodingResult result(0);
  95. bool &valid = result.isValidCoding;
  96. size_t &recoverableMessageLength = result.messageLength;
  97. valid = (representative[representativeByteLength - 1] == (hashIdentifier.second ? 0xcc : 0xbc)) && valid;
  98. if (hashIdentifier.first && hashIdentifier.second)
  99. valid = VerifyBufsEqual(representative + representativeByteLength - u, hashIdentifier.first, hashIdentifier.second) && valid;
  100. GetMGF().GenerateAndMask(hash, representative, representativeByteLength - u - digestSize, h, digestSize);
  101. if (representativeBitLength % 8 != 0)
  102. representative[0] = (byte)Crop(representative[0], representativeBitLength % 8);
  103. // extract salt and recoverableMessage from DB = 00 ... || 01 || M || salt
  104. byte *salt = representative + representativeByteLength - u - digestSize - saltSize;
  105. byte *M = std::find_if(representative, salt-1, std::bind2nd(std::not_equal_to<byte>(), byte(0)));
  106. recoverableMessageLength = salt-M-1;
  107. if (*M == 0x01 &&
  108. (size_t)(M - representative - (representativeBitLength % 8 != 0)) >= MinPadLen(digestSize) &&
  109. recoverableMessageLength <= MaxRecoverableLength(representativeBitLength, hashIdentifier.second, digestSize))
  110. {
  111. if (recoverableMessage)
  112. memcpy(recoverableMessage, M+1, recoverableMessageLength);
  113. }
  114. else
  115. {
  116. recoverableMessageLength = 0;
  117. valid = false;
  118. }
  119. // verify H = hash of M'
  120. byte c[8];
  121. PutWord(false, BIG_ENDIAN_ORDER, c, (word32)SafeRightShift<29>(recoverableMessageLength));
  122. PutWord(false, BIG_ENDIAN_ORDER, c+4, word32(recoverableMessageLength << 3));
  123. hash.Update(c, 8);
  124. hash.Update(recoverableMessage, recoverableMessageLength);
  125. hash.Update(digest, digestSize);
  126. hash.Update(salt, saltSize);
  127. valid = hash.Verify(h) && valid;
  128. if (!AllowRecovery() && valid && recoverableMessageLength != 0)
  129. {throw NotImplemented("PSSR_MEM: message recovery disabled");}
  130. return result;
  131. }
  132. #endif
  133. NAMESPACE_END