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.

280 lines
8.2 KiB

  1. // modes.cpp - written and placed in the public domain by Wei Dai
  2. #include "pch.h"
  3. #ifndef CRYPTOPP_IMPORTS
  4. #include "modes.h"
  5. #include "misc.h"
  6. #ifndef NDEBUG
  7. #include "des.h"
  8. #endif
  9. NAMESPACE_BEGIN(CryptoPP)
  10. #if !defined(NDEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING)
  11. void Modes_TestInstantiations()
  12. {
  13. CFB_Mode<DES>::Encryption m0;
  14. CFB_Mode<DES>::Decryption m1;
  15. OFB_Mode<DES>::Encryption m2;
  16. CTR_Mode<DES>::Encryption m3;
  17. ECB_Mode<DES>::Encryption m4;
  18. CBC_Mode<DES>::Encryption m5;
  19. }
  20. #endif
  21. // Thanks to Zireael, http://github.com/weidai11/cryptopp/pull/46
  22. #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
  23. void CipherModeBase::ResizeBuffers()
  24. {
  25. m_register.New(m_cipher->BlockSize());
  26. }
  27. #endif
  28. void CFB_ModePolicy::Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount)
  29. {
  30. assert(input);
  31. assert(output);
  32. assert(m_cipher->IsForwardTransformation()); // CFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
  33. assert(m_feedbackSize == BlockSize());
  34. const unsigned int s = BlockSize();
  35. if (dir == ENCRYPTION)
  36. {
  37. m_cipher->ProcessAndXorBlock(m_register, input, output);
  38. if (iterationCount > 1)
  39. m_cipher->AdvancedProcessBlocks(output, input+s, output+s, (iterationCount-1)*s, 0);
  40. memcpy(m_register, output+(iterationCount-1)*s, s);
  41. }
  42. else
  43. {
  44. memcpy(m_temp, input+(iterationCount-1)*s, s); // make copy first in case of in-place decryption
  45. if (iterationCount > 1)
  46. m_cipher->AdvancedProcessBlocks(input, input+s, output+s, (iterationCount-1)*s, BlockTransformation::BT_ReverseDirection);
  47. m_cipher->ProcessAndXorBlock(m_register, input, output);
  48. memcpy(m_register, m_temp, s);
  49. }
  50. }
  51. void CFB_ModePolicy::TransformRegister()
  52. {
  53. assert(m_cipher->IsForwardTransformation()); // CFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
  54. m_cipher->ProcessBlock(m_register, m_temp);
  55. unsigned int updateSize = BlockSize()-m_feedbackSize;
  56. memmove_s(m_register, m_register.size(), m_register+m_feedbackSize, updateSize);
  57. memcpy_s(m_register+updateSize, m_register.size()-updateSize, m_temp, m_feedbackSize);
  58. }
  59. void CFB_ModePolicy::CipherResynchronize(const byte *iv, size_t length)
  60. {
  61. assert(length == BlockSize());
  62. CopyOrZero(m_register, iv, length);
  63. TransformRegister();
  64. }
  65. void CFB_ModePolicy::SetFeedbackSize(unsigned int feedbackSize)
  66. {
  67. if (feedbackSize > BlockSize())
  68. throw InvalidArgument("CFB_Mode: invalid feedback size");
  69. m_feedbackSize = feedbackSize ? feedbackSize : BlockSize();
  70. }
  71. void CFB_ModePolicy::ResizeBuffers()
  72. {
  73. CipherModeBase::ResizeBuffers();
  74. m_temp.New(BlockSize());
  75. }
  76. void OFB_ModePolicy::WriteKeystream(byte *keystreamBuffer, size_t iterationCount)
  77. {
  78. assert(m_cipher->IsForwardTransformation()); // OFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
  79. unsigned int s = BlockSize();
  80. m_cipher->ProcessBlock(m_register, keystreamBuffer);
  81. if (iterationCount > 1)
  82. m_cipher->AdvancedProcessBlocks(keystreamBuffer, NULL, keystreamBuffer+s, s*(iterationCount-1), 0);
  83. memcpy(m_register, keystreamBuffer+s*(iterationCount-1), s);
  84. }
  85. void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
  86. {
  87. CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
  88. assert(length == BlockSize());
  89. CopyOrZero(m_register, iv, length);
  90. }
  91. void CTR_ModePolicy::SeekToIteration(lword iterationCount)
  92. {
  93. int carry=0;
  94. for (int i=BlockSize()-1; i>=0; i--)
  95. {
  96. unsigned int sum = m_register[i] + byte(iterationCount) + carry;
  97. m_counterArray[i] = (byte) sum;
  98. carry = sum >> 8;
  99. iterationCount >>= 8;
  100. }
  101. }
  102. void CTR_ModePolicy::IncrementCounterBy256()
  103. {
  104. IncrementCounterByOne(m_counterArray, BlockSize()-1);
  105. }
  106. void CTR_ModePolicy::OperateKeystream(KeystreamOperation /*operation*/, byte *output, const byte *input, size_t iterationCount)
  107. {
  108. assert(m_cipher->IsForwardTransformation()); // CTR mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
  109. unsigned int s = BlockSize();
  110. unsigned int inputIncrement = input ? s : 0;
  111. while (iterationCount)
  112. {
  113. byte lsb = m_counterArray[s-1];
  114. size_t blocks = UnsignedMin(iterationCount, 256U-lsb);
  115. m_cipher->AdvancedProcessBlocks(m_counterArray, input, output, blocks*s, BlockTransformation::BT_InBlockIsCounter|BlockTransformation::BT_AllowParallel);
  116. if ((m_counterArray[s-1] = lsb + (byte)blocks) == 0)
  117. IncrementCounterBy256();
  118. output += blocks*s;
  119. input += blocks*inputIncrement;
  120. iterationCount -= blocks;
  121. }
  122. }
  123. void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
  124. {
  125. CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length);
  126. assert(length == BlockSize());
  127. CopyOrZero(m_register, iv, length);
  128. m_counterArray = m_register;
  129. }
  130. void BlockOrientedCipherModeBase::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
  131. {
  132. m_cipher->SetKey(key, length, params);
  133. ResizeBuffers();
  134. if (IsResynchronizable())
  135. {
  136. size_t ivLength;
  137. const byte *iv = GetIVAndThrowIfInvalid(params, ivLength);
  138. Resynchronize(iv, (int)ivLength);
  139. }
  140. }
  141. // Thanks to Zireael, http://github.com/weidai11/cryptopp/pull/46
  142. #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
  143. void BlockOrientedCipherModeBase::ResizeBuffers()
  144. {
  145. CipherModeBase::ResizeBuffers();
  146. m_buffer.New(BlockSize());
  147. }
  148. #endif
  149. void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t length)
  150. {
  151. assert(length%BlockSize()==0);
  152. m_cipher->AdvancedProcessBlocks(inString, NULL, outString, length, BlockTransformation::BT_AllowParallel);
  153. }
  154. void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length)
  155. {
  156. if (!length)
  157. return;
  158. assert(length%BlockSize()==0);
  159. unsigned int blockSize = BlockSize();
  160. m_cipher->AdvancedProcessBlocks(inString, m_register, outString, blockSize, BlockTransformation::BT_XorInput);
  161. if (length > blockSize)
  162. m_cipher->AdvancedProcessBlocks(inString+blockSize, outString, outString+blockSize, length-blockSize, BlockTransformation::BT_XorInput);
  163. memcpy(m_register, outString + length - blockSize, blockSize);
  164. }
  165. void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
  166. {
  167. if (length <= BlockSize())
  168. {
  169. if (!m_stolenIV)
  170. throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing");
  171. // steal from IV
  172. memcpy(outString, m_register, length);
  173. outString = m_stolenIV;
  174. }
  175. else
  176. {
  177. // steal from next to last block
  178. xorbuf(m_register, inString, BlockSize());
  179. m_cipher->ProcessBlock(m_register);
  180. inString += BlockSize();
  181. length -= BlockSize();
  182. memcpy(outString+BlockSize(), m_register, length);
  183. }
  184. // output last full ciphertext block
  185. xorbuf(m_register, inString, length);
  186. m_cipher->ProcessBlock(m_register);
  187. memcpy(outString, m_register, BlockSize());
  188. }
  189. // Thanks to Zireael, http://github.com/weidai11/cryptopp/pull/46
  190. #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
  191. void CBC_Decryption::ResizeBuffers()
  192. {
  193. BlockOrientedCipherModeBase::ResizeBuffers();
  194. m_temp.New(BlockSize());
  195. }
  196. #endif
  197. void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t length)
  198. {
  199. if (!length)
  200. return;
  201. assert(length%BlockSize()==0);
  202. unsigned int blockSize = BlockSize();
  203. memcpy(m_temp, inString+length-blockSize, blockSize); // save copy now in case of in-place decryption
  204. if (length > blockSize)
  205. m_cipher->AdvancedProcessBlocks(inString+blockSize, inString, outString+blockSize, length-blockSize, BlockTransformation::BT_ReverseDirection|BlockTransformation::BT_AllowParallel);
  206. m_cipher->ProcessAndXorBlock(inString, m_register, outString);
  207. m_register.swap(m_temp);
  208. }
  209. void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
  210. {
  211. const byte *pn, *pn1;
  212. bool stealIV = length <= BlockSize();
  213. if (stealIV)
  214. {
  215. pn = inString;
  216. pn1 = m_register;
  217. }
  218. else
  219. {
  220. pn = inString + BlockSize();
  221. pn1 = inString;
  222. length -= BlockSize();
  223. }
  224. // decrypt last partial plaintext block
  225. memcpy(m_temp, pn1, BlockSize());
  226. m_cipher->ProcessBlock(m_temp);
  227. xorbuf(m_temp, pn, length);
  228. if (stealIV)
  229. memcpy(outString, m_temp, length);
  230. else
  231. {
  232. memcpy(outString+BlockSize(), m_temp, length);
  233. // decrypt next to last plaintext block
  234. memcpy(m_temp, pn, length);
  235. m_cipher->ProcessBlock(m_temp);
  236. xorbuf(outString, m_temp, m_register, BlockSize());
  237. }
  238. }
  239. NAMESPACE_END
  240. #endif