diff --git a/cryptlib.cpp b/cryptlib.cpp index 162a9b81..41461c61 100644 --- a/cryptlib.cpp +++ b/cryptlib.cpp @@ -213,6 +213,7 @@ unsigned int HashTransformation::OptimalDataAlignment() const return GetAlignmentOf(); } +#if 0 void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inString, size_t length) { CRYPTOPP_ASSERT(MinLastBlockSize() == 0); // this function should be overridden otherwise @@ -222,6 +223,22 @@ void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inStrin else if (length != 0) throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block"); } +#endif + +size_t StreamTransformation::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) +{ + // this function should be overridden otherwise + CRYPTOPP_ASSERT(MinLastBlockSize() == 0); + + if (inLength == MandatoryBlockSize()) + { + ProcessData(outString, inString, inLength); + return inLength; + } + else if (inLength != 0) + throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block"); + return 0; +} void AuthenticatedSymmetricCipher::SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) { diff --git a/cryptlib.h b/cryptlib.h index adf2c7fc..1725305e 100644 --- a/cryptlib.h +++ b/cryptlib.h @@ -871,11 +871,16 @@ public: //! \brief Encrypt or decrypt the last block of data //! \param outString the output byte buffer + //! \param outLength the size of the output byte buffer, in bytes //! \param inString the input byte buffer - //! \param length the size of the input and output byte buffers, in bytes - //! ProcessLastBlock is used when the last block of data is special. - //! Currently the only use of this function is CBC-CTS mode. - virtual void ProcessLastBlock(byte *outString, const byte *inString, size_t length); + //! \param inLength the size of the input byte buffer, in bytes + //! \returns the number of bytes used in outString + //! ProcessLastBlock is used when the last block of data is special and the + //! cipher text may expand larger than input data length. The current implementation provides + //! an output buffer with a size inLength+2*MandatoryBlockSize(). This member function + //! is used by CBC-CTS and OCB modes. + //! \sa IsLastBlockSpecial + virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); //! \brief Provides the size of the last block //! \returns the minimum size of the last block @@ -883,6 +888,20 @@ public: //! block is not special. virtual unsigned int MinLastBlockSize() const {return 0;} + //! \brief Determines if the last block receives special processing + //! \returns true if the last block reveives special processing, false otherwise. + //! \details Some authenticated encryption modes have needs that are not expressed well + //! with MandatoryBlockSize() and MinLastBlockSize(). When IsLastBlockSpecial() returns + //! true three things happen. First, standard block cipher padding is not applied. + //! Second, the ProcessLastBlock() is used that provides inString and outString lengths. + //! Third, outString is larger than inString by 2*MandatoryBlockSize(). That is, + //! there's a reserve available when processing the last block. + //! \details The return value of ProcessLastBlock() indicates how many bytes were written + //! to outString. A filter driving data will send outString and outLength + //! to an AttachedTransformation() for additional processing. + //! \sa ProcessLastBlock + virtual bool IsLastBlockSpecial() const {return false;} + //! \brief Encrypt or decrypt a string of bytes //! \param inoutString the string to process //! \param length the size of the inoutString, in bytes diff --git a/filters.cpp b/filters.cpp index e4ffe2ca..98f3bd7a 100644 --- a/filters.cpp +++ b/filters.cpp @@ -687,6 +687,15 @@ void StreamTransformationFilter::LastPut(const byte *inString, size_t length) { byte *space = NULLPTR; + if (m_cipher.IsLastBlockSpecial()) + { + size_t reserve = 2*m_cipher.MandatoryBlockSize(); + space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, length+reserve); + length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length); + AttachedTransformation()->Put(space, length); + return; + } + switch (m_padding) { case NO_PADDING: @@ -694,17 +703,18 @@ void StreamTransformationFilter::LastPut(const byte *inString, size_t length) if (length > 0) { size_t minLastBlockSize = m_cipher.MinLastBlockSize(); + size_t reserve = 2*m_cipher.MandatoryBlockSize(); bool isForwardTransformation = m_cipher.IsForwardTransformation(); if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize)) { // do padding size_t blockSize = STDMAX(minLastBlockSize, (size_t)m_cipher.MandatoryBlockSize()); - space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, blockSize); + space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, blockSize+reserve); if (inString) {memcpy(space, inString, length);} memset(space + length, 0, blockSize - length); - m_cipher.ProcessLastBlock(space, space, blockSize); - AttachedTransformation()->Put(space, blockSize); + size_t used = m_cipher.ProcessLastBlock(space, blockSize+reserve, space, blockSize); + AttachedTransformation()->Put(space, used); } else { @@ -716,9 +726,9 @@ void StreamTransformationFilter::LastPut(const byte *inString, size_t length) throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size"); } - space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, m_optimalBufferSize); - m_cipher.ProcessLastBlock(space, inString, length); - AttachedTransformation()->Put(space, length); + space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, m_optimalBufferSize+reserve); + size_t used = m_cipher.ProcessLastBlock(space, length+reserve, inString, length); + AttachedTransformation()->Put(space, used); } } break; diff --git a/modes.cpp b/modes.cpp index 0d9849ce..5738b403 100644 --- a/modes.cpp +++ b/modes.cpp @@ -174,8 +174,7 @@ void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t lengt void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length) { - if (!length) - return; + if (!length) return; CRYPTOPP_ASSERT(length%BlockSize()==0); unsigned int blockSize = BlockSize(); @@ -185,15 +184,17 @@ void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t l memcpy(m_register, outString + length - blockSize, blockSize); } -void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length) +size_t CBC_CTS_Encryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) { - if (length <= BlockSize()) + CRYPTOPP_UNUSED(outLength); + size_t used = inLength; + if (inLength <= BlockSize()) { if (!m_stolenIV) throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing"); // steal from IV - memcpy(outString, m_register, length); + memcpy(outString, m_register, inLength); outString = m_stolenIV; } else @@ -202,14 +203,16 @@ void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, xorbuf(m_register, inString, BlockSize()); m_cipher->ProcessBlock(m_register); inString += BlockSize(); - length -= BlockSize(); - memcpy(outString+BlockSize(), m_register, length); + inLength -= BlockSize(); + memcpy(outString+BlockSize(), m_register, inLength); } // output last full ciphertext block - xorbuf(m_register, inString, length); + xorbuf(m_register, inString, inLength); m_cipher->ProcessBlock(m_register); memcpy(outString, m_register, BlockSize()); + + return used; } void CBC_Decryption::ResizeBuffers() @@ -232,38 +235,44 @@ void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t l m_register.swap(m_temp); } -void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length) +size_t CBC_CTS_Decryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) { - const byte *pn, *pn1; - bool stealIV = length <= BlockSize(); + CRYPTOPP_UNUSED(outLength); + const byte *pn1, *pn2; + bool stealIV = inLength <= BlockSize(); + size_t used = inLength; if (stealIV) { - pn = inString; - pn1 = m_register; + pn1 = inString; + pn2 = m_register; } else { - pn = inString + BlockSize(); - pn1 = inString; - length -= BlockSize(); + pn1 = inString + BlockSize(); + pn2 = inString; + inLength -= BlockSize(); } // decrypt last partial plaintext block - memcpy(m_temp, pn1, BlockSize()); + memcpy(m_temp, pn2, BlockSize()); m_cipher->ProcessBlock(m_temp); - xorbuf(m_temp, pn, length); + xorbuf(m_temp, pn1, inLength); if (stealIV) - memcpy(outString, m_temp, length); + { + memcpy(outString, m_temp, inLength); + } else { - memcpy(outString+BlockSize(), m_temp, length); + memcpy(outString+BlockSize(), m_temp, inLength); // decrypt next to last plaintext block - memcpy(m_temp, pn, length); + memcpy(m_temp, pn1, inLength); m_cipher->ProcessBlock(m_temp); xorbuf(outString, m_temp, m_register, BlockSize()); } + + return used; } NAMESPACE_END diff --git a/modes.h b/modes.h index 2dbe5357..687f245d 100644 --- a/modes.h +++ b/modes.h @@ -255,7 +255,7 @@ public: void SetStolenIV(byte *iv) {m_stolenIV = iv;} unsigned int MinLastBlockSize() const {return BlockSize()+1;} - void ProcessLastBlock(byte *outString, const byte *inString, size_t length); + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); protected: void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) @@ -287,7 +287,7 @@ class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption { public: unsigned int MinLastBlockSize() const {return BlockSize()+1;} - void ProcessLastBlock(byte *outString, const byte *inString, size_t length); + size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength); }; //! \class CipherModeFinalTemplate_CipherHolder @@ -476,13 +476,6 @@ struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation typedef CipherModeFinalTemplate_ExternalCipher Decryption; }; -//#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY -//typedef CFB_Mode_ExternalCipher::Encryption CFBEncryption; -//typedef CFB_Mode_ExternalCipher::Decryption CFBDecryption; -//typedef OFB_Mode_ExternalCipher::Encryption OFB; -//typedef CTR_Mode_ExternalCipher::Encryption CounterMode; -//#endif - NAMESPACE_END // Issue 340