- Main Page
- Namespaces
- Classes
- Files

# modes.cpp

    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         memcpy_s(m_register, m_register.size(), iv, BlockSize());
    00060         TransformRegister();
    00061 }
    00062
    00063 void CFB_ModePolicy::SetFeedbackSize(unsigned int feedbackSize)
    00064 {
    00065         if (feedbackSize > BlockSize())
    00066                 throw InvalidArgument("CFB_Mode: invalid feedback size");
    00067         m_feedbackSize = feedbackSize ? feedbackSize : BlockSize();
    00068 }
    00069
    00070 void CFB_ModePolicy::ResizeBuffers()
    00071 {
    00072         CipherModeBase::ResizeBuffers();
    00073         m_temp.New(BlockSize());
    00074 }
    00075
    00076 void OFB_ModePolicy::WriteKeystream(byte *keystreamBuffer, size_t iterationCount)
    00077 {
    00078         assert(m_cipher->IsForwardTransformation());    // OFB mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
    00079         unsigned int s = BlockSize();
    00080         m_cipher->ProcessBlock(m_register, keystreamBuffer);
    00081         if (iterationCount > 1)
    00082                 m_cipher->AdvancedProcessBlocks(keystreamBuffer, NULL, keystreamBuffer+s, s*(iterationCount-1), 0);
    00083         memcpy(m_register, keystreamBuffer+s*(iterationCount-1), s);
    00084 }
    00085
    00086 void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
    00087 {
    00088         CopyOrZero(m_register, iv, length);
    00089 }
    00090
    00091 void CTR_ModePolicy::SeekToIteration(lword iterationCount)
    00092 {
    00093         int carry=0;
    00094         for (int i=BlockSize()-1; i>=0; i--)
    00095         {
    00096                 unsigned int sum = m_register[i] + byte(iterationCount) + carry;
    00097                 m_counterArray[i] = (byte) sum;
    00098                 carry = sum >> 8;
    00099                 iterationCount >>= 8;
    00100         }
    00101 }
    00102
    00103 void CTR_ModePolicy::IncrementCounterBy256()
    00104 {
    00105         IncrementCounterByOne(m_counterArray, BlockSize()-1);
    00106 }
    00107
    00108 void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
    00109 {
    00110         assert(m_cipher->IsForwardTransformation());    // CTR mode needs the "encrypt" direction of the underlying block cipher, even to decrypt
    00111         unsigned int s = BlockSize();
    00112         unsigned int inputIncrement = input ? s : 0;
    00113
    00114         while (iterationCount)
    00115         {
    00116                 byte lsb = m_counterArray[s-1];
    00117                 size_t blocks = UnsignedMin(iterationCount, 256U-lsb);
    00118                 m_cipher->AdvancedProcessBlocks(m_counterArray, input, output, blocks*s, BlockTransformation::BT_InBlockIsCounter);
    00119                 if ((m_counterArray[s-1] = lsb + (byte)blocks) == 0)
    00120                         IncrementCounterBy256();
    00121
    00122                 output += blocks*s;
    00123                 input += blocks*inputIncrement;
    00124                 iterationCount -= blocks;
    00125         }
    00126 }
    00127
    00128 void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
    00129 {
    00130         assert(length == BlockSize());
    00131         CopyOrZero(m_register, iv, length);
    00132         m_counterArray = m_register;
    00133 }
    00134
    00135 void BlockOrientedCipherModeBase::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
    00136 {
    00137         m_cipher->SetKey(key, length, params);
    00138         ResizeBuffers();
    00139         if (IsResynchronizable())
    00140         {
    00141                 size_t ivLength;
    00142                 const byte *iv = GetIVAndThrowIfInvalid(params, ivLength);
    00143                 Resynchronize(iv, (int)ivLength);
    00144         }
    00145 }
    00146
    00147 void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t length)
    00148 {
    00149         assert(length%BlockSize()==0);
    00150         m_cipher->AdvancedProcessBlocks(inString, NULL, outString, length, 0);
    00151 }
    00152
    00153 void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length)
    00154 {
    00155         if (!length)
    00156                 return;
    00157         assert(length%BlockSize()==0);
    00158
    00159         unsigned int blockSize = BlockSize();
    00160         m_cipher->AdvancedProcessBlocks(inString, m_register, outString, blockSize, BlockTransformation::BT_XorInput);
    00161         if (length > blockSize)
    00162                 m_cipher->AdvancedProcessBlocks(inString+blockSize, outString, outString+blockSize, length-blockSize, BlockTransformation::BT_XorInput);
    00163         memcpy(m_register, outString + length - blockSize, blockSize);
    00164 }
    00165
    00166 void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
    00167 {
    00168         if (length <= BlockSize())
    00169         {
    00170                 if (!m_stolenIV)
    00171                         throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing");
    00172
    00173                 // steal from IV
    00174                 memcpy(outString, m_register, length);
    00175                 outString = m_stolenIV;
    00176         }
    00177         else
    00178         {
    00179                 // steal from next to last block
    00180                 xorbuf(m_register, inString, BlockSize());
    00181                 m_cipher->ProcessBlock(m_register);
    00182                 inString += BlockSize();
    00183                 length -= BlockSize();
    00184                 memcpy(outString+BlockSize(), m_register, length);
    00185         }
    00186
    00187         // output last full ciphertext block
    00188         xorbuf(m_register, inString, length);
    00189         m_cipher->ProcessBlock(m_register);
    00190         memcpy(outString, m_register, BlockSize());
    00191 }
    00192
    00193 void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t length)
    00194 {
    00195         if (!length)
    00196                 return;
    00197         assert(length%BlockSize()==0);
    00198
    00199         unsigned int blockSize = BlockSize();
    00200         memcpy(m_temp, inString+length-blockSize, blockSize);   // save copy now in case of in-place decryption
    00201         if (length > blockSize)
    00202                 m_cipher->AdvancedProcessBlocks(inString+blockSize, inString, outString+blockSize, length-blockSize, BlockTransformation::BT_ReverseDirection);
    00203         m_cipher->ProcessAndXorBlock(inString, m_register, outString);
    00204         m_register.swap(m_temp);
    00205 }
    00206
    00207 void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
    00208 {
    00209         const byte *pn, *pn1;
    00210         bool stealIV = length <= BlockSize();
    00211
    00212         if (stealIV)
    00213         {
    00214                 pn = inString;
    00215                 pn1 = m_register;
    00216         }
    00217         else
    00218         {
    00219                 pn = inString + BlockSize();
    00220                 pn1 = inString;
    00221                 length -= BlockSize();
    00222         }
    00223
    00224         // decrypt last partial plaintext block
    00225         memcpy(m_temp, pn1, BlockSize());
    00226         m_cipher->ProcessBlock(m_temp);
    00227         xorbuf(m_temp, pn, length);
    00228
    00229         if (stealIV)
    00230                 memcpy(outString, m_temp, length);
    00231         else
    00232         {
    00233                 memcpy(outString+BlockSize(), m_temp, length);
    00234                 // decrypt next to last plaintext block
    00235                 memcpy(m_temp, pn, length);
    00236                 m_cipher->ProcessBlock(m_temp);
    00237                 xorbuf(outString, m_temp, m_register, BlockSize());
    00238         }
    00239 }
    00240
    00241 NAMESPACE_END
    00242
    00243 #endif