Crypto++
|
00001 // modes.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 00005 #ifndef CRYPTOPP_IMPORTS 00006 00007 #include "modes.h" 00008 00009 #ifndef NDEBUG 00010 #include "des.h" 00011 #endif 00012 00013 NAMESPACE_BEGIN(CryptoPP) 00014 00015 #ifndef NDEBUG 00016 void Modes_TestInstantiations() 00017 { 00018 CFB_Mode<DES>::Encryption m0; 00019 CFB_Mode<DES>::Decryption m1; 00020 OFB_Mode<DES>::Encryption m2; 00021 CTR_Mode<DES>::Encryption m3; 00022 ECB_Mode<DES>::Encryption m4; 00023 CBC_Mode<DES>::Encryption m5; 00024 } 00025 #endif 00026 00027 void CFB_ModePolicy::Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) 00028 { 00029 assert(m_cipher->IsForwardTransformation()); // CFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt 00030 assert(m_feedbackSize == BlockSize()); 00031 00032 unsigned int s = BlockSize(); 00033 if (dir == ENCRYPTION) 00034 { 00035 m_cipher->ProcessAndXorBlock(m_register, input, output); 00036 m_cipher->AdvancedProcessBlocks(output, input+s, output+s, (iterationCount-1)*s, 0); 00037 memcpy(m_register, output+(iterationCount-1)*s, s); 00038 } 00039 else 00040 { 00041 memcpy(m_temp, input+(iterationCount-1)*s, s); // make copy first in case of in-place decryption 00042 m_cipher->AdvancedProcessBlocks(input, input+s, output+s, (iterationCount-1)*s, BlockTransformation::BT_ReverseDirection); 00043 m_cipher->ProcessAndXorBlock(m_register, input, output); 00044 memcpy(m_register, m_temp, s); 00045 } 00046 } 00047 00048 void CFB_ModePolicy::TransformRegister() 00049 { 00050 assert(m_cipher->IsForwardTransformation()); // CFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt 00051 m_cipher->ProcessBlock(m_register, m_temp); 00052 unsigned int updateSize = BlockSize()-m_feedbackSize; 00053 memmove_s(m_register, m_register.size(), m_register+m_feedbackSize, updateSize); 00054 memcpy_s(m_register+updateSize, m_register.size()-updateSize, m_temp, m_feedbackSize); 00055 } 00056 00057 void CFB_ModePolicy::CipherResynchronize(const byte *iv, size_t length) 00058 { 00059 assert(length == BlockSize()); 00060 CopyOrZero(m_register, iv, length); 00061 TransformRegister(); 00062 } 00063 00064 void CFB_ModePolicy::SetFeedbackSize(unsigned int feedbackSize) 00065 { 00066 if (feedbackSize > BlockSize()) 00067 throw InvalidArgument("CFB_Mode: invalid feedback size"); 00068 m_feedbackSize = feedbackSize ? feedbackSize : BlockSize(); 00069 } 00070 00071 void CFB_ModePolicy::ResizeBuffers() 00072 { 00073 CipherModeBase::ResizeBuffers(); 00074 m_temp.New(BlockSize()); 00075 } 00076 00077 void OFB_ModePolicy::WriteKeystream(byte *keystreamBuffer, size_t iterationCount) 00078 { 00079 assert(m_cipher->IsForwardTransformation()); // OFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt 00080 unsigned int s = BlockSize(); 00081 m_cipher->ProcessBlock(m_register, keystreamBuffer); 00082 if (iterationCount > 1) 00083 m_cipher->AdvancedProcessBlocks(keystreamBuffer, NULL, keystreamBuffer+s, s*(iterationCount-1), 0); 00084 memcpy(m_register, keystreamBuffer+s*(iterationCount-1), s); 00085 } 00086 00087 void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) 00088 { 00089 assert(length == BlockSize()); 00090 CopyOrZero(m_register, iv, length); 00091 } 00092 00093 void CTR_ModePolicy::SeekToIteration(lword iterationCount) 00094 { 00095 int carry=0; 00096 for (int i=BlockSize()-1; i>=0; i--) 00097 { 00098 unsigned int sum = m_register[i] + byte(iterationCount) + carry; 00099 m_counterArray[i] = (byte) sum; 00100 carry = sum >> 8; 00101 iterationCount >>= 8; 00102 } 00103 } 00104 00105 void CTR_ModePolicy::IncrementCounterBy256() 00106 { 00107 IncrementCounterByOne(m_counterArray, BlockSize()-1); 00108 } 00109 00110 void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) 00111 { 00112 assert(m_cipher->IsForwardTransformation()); // CTR mode needs the "encrypt" direction of the underlying block cipher, even to decrypt 00113 unsigned int s = BlockSize(); 00114 unsigned int inputIncrement = input ? s : 0; 00115 00116 while (iterationCount) 00117 { 00118 byte lsb = m_counterArray[s-1]; 00119 size_t blocks = UnsignedMin(iterationCount, 256U-lsb); 00120 m_cipher->AdvancedProcessBlocks(m_counterArray, input, output, blocks*s, BlockTransformation::BT_InBlockIsCounter|BlockTransformation::BT_AllowParallel); 00121 if ((m_counterArray[s-1] = lsb + (byte)blocks) == 0) 00122 IncrementCounterBy256(); 00123 00124 output += blocks*s; 00125 input += blocks*inputIncrement; 00126 iterationCount -= blocks; 00127 } 00128 } 00129 00130 void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) 00131 { 00132 assert(length == BlockSize()); 00133 CopyOrZero(m_register, iv, length); 00134 m_counterArray = m_register; 00135 } 00136 00137 void BlockOrientedCipherModeBase::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) 00138 { 00139 m_cipher->SetKey(key, length, params); 00140 ResizeBuffers(); 00141 if (IsResynchronizable()) 00142 { 00143 size_t ivLength; 00144 const byte *iv = GetIVAndThrowIfInvalid(params, ivLength); 00145 Resynchronize(iv, (int)ivLength); 00146 } 00147 } 00148 00149 void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t length) 00150 { 00151 assert(length%BlockSize()==0); 00152 m_cipher->AdvancedProcessBlocks(inString, NULL, outString, length, BlockTransformation::BT_AllowParallel); 00153 } 00154 00155 void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length) 00156 { 00157 if (!length) 00158 return; 00159 assert(length%BlockSize()==0); 00160 00161 unsigned int blockSize = BlockSize(); 00162 m_cipher->AdvancedProcessBlocks(inString, m_register, outString, blockSize, BlockTransformation::BT_XorInput); 00163 if (length > blockSize) 00164 m_cipher->AdvancedProcessBlocks(inString+blockSize, outString, outString+blockSize, length-blockSize, BlockTransformation::BT_XorInput); 00165 memcpy(m_register, outString + length - blockSize, blockSize); 00166 } 00167 00168 void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length) 00169 { 00170 if (length <= BlockSize()) 00171 { 00172 if (!m_stolenIV) 00173 throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing"); 00174 00175 // steal from IV 00176 memcpy(outString, m_register, length); 00177 outString = m_stolenIV; 00178 } 00179 else 00180 { 00181 // steal from next to last block 00182 xorbuf(m_register, inString, BlockSize()); 00183 m_cipher->ProcessBlock(m_register); 00184 inString += BlockSize(); 00185 length -= BlockSize(); 00186 memcpy(outString+BlockSize(), m_register, length); 00187 } 00188 00189 // output last full ciphertext block 00190 xorbuf(m_register, inString, length); 00191 m_cipher->ProcessBlock(m_register); 00192 memcpy(outString, m_register, BlockSize()); 00193 } 00194 00195 void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t length) 00196 { 00197 if (!length) 00198 return; 00199 assert(length%BlockSize()==0); 00200 00201 unsigned int blockSize = BlockSize(); 00202 memcpy(m_temp, inString+length-blockSize, blockSize); // save copy now in case of in-place decryption 00203 if (length > blockSize) 00204 m_cipher->AdvancedProcessBlocks(inString+blockSize, inString, outString+blockSize, length-blockSize, BlockTransformation::BT_ReverseDirection|BlockTransformation::BT_AllowParallel); 00205 m_cipher->ProcessAndXorBlock(inString, m_register, outString); 00206 m_register.swap(m_temp); 00207 } 00208 00209 void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length) 00210 { 00211 const byte *pn, *pn1; 00212 bool stealIV = length <= BlockSize(); 00213 00214 if (stealIV) 00215 { 00216 pn = inString; 00217 pn1 = m_register; 00218 } 00219 else 00220 { 00221 pn = inString + BlockSize(); 00222 pn1 = inString; 00223 length -= BlockSize(); 00224 } 00225 00226 // decrypt last partial plaintext block 00227 memcpy(m_temp, pn1, BlockSize()); 00228 m_cipher->ProcessBlock(m_temp); 00229 xorbuf(m_temp, pn, length); 00230 00231 if (stealIV) 00232 memcpy(outString, m_temp, length); 00233 else 00234 { 00235 memcpy(outString+BlockSize(), m_temp, length); 00236 // decrypt next to last plaintext block 00237 memcpy(m_temp, pn, length); 00238 m_cipher->ProcessBlock(m_temp); 00239 xorbuf(outString, m_temp, m_register, BlockSize()); 00240 } 00241 } 00242 00243 NAMESPACE_END 00244 00245 #endif