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