// cbc.cpp - written and placed in the public domain by Wei Dai #include "pch.h" #include "cbc.h" NAMESPACE_BEGIN(CryptoPP) CBCRawEncryptor::CBCRawEncryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(0, S, 0, outQueue) { } void CBCRawEncryptor::NextPut(const byte *inString, unsigned int) { xorbuf(reg, inString, S); cipher.ProcessBlock(reg); AttachedTransformation()->Put(reg, S); } void CBCRawEncryptor::LastPut(const byte *inString, unsigned int length) { assert(length < S); if (length > 0) { xorbuf(reg, inString, length); cipher.ProcessBlock(reg); AttachedTransformation()->Put(reg, S); } } CBCRawDecryptor::CBCRawDecryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(0, S, 0, outQueue) { } void CBCRawDecryptor::NextPut(const byte *inString, unsigned int) { cipher.ProcessBlock(inString, buffer); xorbuf(buffer, reg, S); AttachedTransformation()->Put(buffer, S); memcpy(reg, inString, S); } void CBCRawDecryptor::LastPut(const byte *inString, unsigned int length) { } CBCPaddedEncryptor::CBCPaddedEncryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(0, S, 0, outQueue) { } void CBCPaddedEncryptor::NextPut(const byte *inString, unsigned int) { xorbuf(reg, inString, S); cipher.ProcessBlock(reg); AttachedTransformation()->Put(reg, S); } void CBCPaddedEncryptor::LastPut(const byte *inString, unsigned int length) { // pad last block assert(length < S); xorbuf(reg, inString, length); byte pad = S-length; for (unsigned int i=0; iPut(reg, S); } CBCPaddedDecryptor::CBCPaddedDecryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(0, S, S, outQueue) { } void CBCPaddedDecryptor::NextPut(const byte *inString, unsigned int) { cipher.ProcessBlock(inString, buffer); xorbuf(buffer, reg, S); AttachedTransformation()->Put(buffer, S); memcpy(reg, inString, S); } void CBCPaddedDecryptor::LastPut(const byte *inString, unsigned int length) { if (length >= S) { cipher.ProcessBlock(inString, buffer); xorbuf(buffer, reg, S); if (buffer[S-1] > S) buffer[S-1] = 0; // something's wrong with the padding AttachedTransformation()->Put(buffer, S-buffer[S-1]); } } // ******************************************************** CBC_CTS_Encryptor::CBC_CTS_Encryptor(const BlockTransformation &cipher, byte *IV, BufferedTransformation *outQueue, bool stealIV) : CipherMode(cipher, IV), FilterWithBufferedInput(S, S, 1, outQueue), m_iv(stealIV ? IV : NULL) { } CBC_CTS_Encryptor::CBC_CTS_Encryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(S, S, 1, outQueue), m_iv(NULL) { } void CBC_CTS_Encryptor::FirstPut(const byte *inString) { xorbuf(reg, inString, S); cipher.ProcessBlock(reg); } void CBC_CTS_Encryptor::NextPut(const byte *inString, unsigned int) { AttachedTransformation()->Put(reg, S); xorbuf(reg, inString, S); cipher.ProcessBlock(reg); } void CBC_CTS_Encryptor::LastPut(const byte *inString, unsigned int length) { assert(length <= S); if (length == 0) return; if (!DidFirstPut() && !m_iv) { xorbuf(reg, inString, length); cipher.ProcessBlock(reg); length = 0; } // output last full ciphertext block first memcpy(buffer, reg, S); xorbuf(reg, inString, length); cipher.ProcessBlock(reg); if (!DidFirstPut() && m_iv) memcpy(m_iv, reg, S); else AttachedTransformation()->Put(reg, S); // steal ciphertext from next to last block AttachedTransformation()->Put(buffer, STDMAX(1U, length)); } CBC_CTS_Decryptor::CBC_CTS_Decryptor(const BlockTransformation &cipher, const byte *IV, BufferedTransformation *outQueue) : CipherMode(cipher, IV), FilterWithBufferedInput(0, S, S+1, outQueue) { } void CBC_CTS_Decryptor::NextPut(const byte *inString, unsigned int) { cipher.ProcessBlock(inString, buffer); xorbuf(buffer, reg, S); memcpy(reg, inString, S); AttachedTransformation()->Put(buffer, S); } void CBC_CTS_Decryptor::LastPut(const byte *inString, unsigned int length) { assert(length <= 2*S); if (length == 0) return; const byte *pn, *pn1; bool stealIV; if (length < S+1) { pn = inString; pn1 = reg; stealIV = true; } else { pn = inString + S; pn1 = inString; length -= S; stealIV = false; } SecByteBlock temp(S); // decrypt last partial plaintext block cipher.ProcessBlock(pn1, temp); xorbuf(temp, pn, length); // decrypt next to last plaintext block memcpy(buffer, pn, length); memcpy(buffer+length, temp+length, S-length); cipher.ProcessBlock(buffer); xorbuf(buffer, reg, S); if (!stealIV) AttachedTransformation()->Put(buffer, S); AttachedTransformation()->Put(temp, length); } NAMESPACE_END