Skip to content

Commit e92eb31

Browse files
committed
Update StreamTransformation and ProcessLastBlock
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. The return value of ProcessLastBlock() indicates how many bytes were written to outString. A filter driving data will send outString and returned length to an AttachedTransformation() for additional processing.
1 parent bebdc8b commit e92eb31

File tree

5 files changed

+88
-40
lines changed

5 files changed

+88
-40
lines changed

cryptlib.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ unsigned int HashTransformation::OptimalDataAlignment() const
213213
return GetAlignmentOf<word32>();
214214
}
215215

216+
#if 0
216217
void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
217218
{
218219
CRYPTOPP_ASSERT(MinLastBlockSize() == 0); // this function should be overridden otherwise
@@ -222,6 +223,22 @@ void StreamTransformation::ProcessLastBlock(byte *outString, const byte *inStrin
222223
else if (length != 0)
223224
throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block");
224225
}
226+
#endif
227+
228+
size_t StreamTransformation::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength)
229+
{
230+
// this function should be overridden otherwise
231+
CRYPTOPP_ASSERT(MinLastBlockSize() == 0);
232+
233+
if (inLength == MandatoryBlockSize())
234+
{
235+
ProcessData(outString, inString, inLength);
236+
return inLength;
237+
}
238+
else if (inLength != 0)
239+
throw NotImplemented(AlgorithmName() + ": this object doesn't support a special last block");
240+
return 0;
241+
}
225242

226243
void AuthenticatedSymmetricCipher::SpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength)
227244
{

cryptlib.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -871,18 +871,37 @@ class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE StreamTransformation : public Algorithm
871871

872872
//! \brief Encrypt or decrypt the last block of data
873873
//! \param outString the output byte buffer
874+
//! \param outLength the size of the output byte buffer, in bytes
874875
//! \param inString the input byte buffer
875-
//! \param length the size of the input and output byte buffers, in bytes
876-
//! ProcessLastBlock is used when the last block of data is special.
877-
//! Currently the only use of this function is CBC-CTS mode.
878-
virtual void ProcessLastBlock(byte *outString, const byte *inString, size_t length);
876+
//! \param inLength the size of the input byte buffer, in bytes
877+
//! \returns the number of bytes used in outString
878+
//! ProcessLastBlock is used when the last block of data is special and the
879+
//! cipher text may expand larger than input data length. The current implementation provides
880+
//! an output buffer with a size <tt>inLength+2*MandatoryBlockSize()</tt>. This member function
881+
//! is used by CBC-CTS and OCB modes.
882+
//! \sa IsLastBlockSpecial
883+
virtual size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength);
879884

880885
//! \brief Provides the size of the last block
881886
//! \returns the minimum size of the last block
882887
//! \details MinLastBlockSize() returns the minimum size of the last block. 0 indicates the last
883888
//! block is not special.
884889
virtual unsigned int MinLastBlockSize() const {return 0;}
885890

891+
//! \brief Determines if the last block receives special processing
892+
//! \returns true if the last block reveives special processing, false otherwise.
893+
//! \details Some authenticated encryption modes have needs that are not expressed well
894+
//! with MandatoryBlockSize() and MinLastBlockSize(). When IsLastBlockSpecial() returns
895+
//! true three things happen. First, standard block cipher padding is not applied.
896+
//! Second, the ProcessLastBlock() is used that provides inString and outString lengths.
897+
//! Third, outString is larger than inString by <tt>2*MandatoryBlockSize()</tt>. That is,
898+
//! there's a reserve available when processing the last block.
899+
//! \details The return value of ProcessLastBlock() indicates how many bytes were written
900+
//! to outString. A filter driving data will send <tt>outString</tt> and <tt>outLength</tt>
901+
//! to an <tt>AttachedTransformation()</tt> for additional processing.
902+
//! \sa ProcessLastBlock
903+
virtual bool IsLastBlockSpecial() const {return false;}
904+
886905
//! \brief Encrypt or decrypt a string of bytes
887906
//! \param inoutString the string to process
888907
//! \param length the size of the inoutString, in bytes

filters.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -687,24 +687,34 @@ void StreamTransformationFilter::LastPut(const byte *inString, size_t length)
687687
{
688688
byte *space = NULLPTR;
689689

690+
if (m_cipher.IsLastBlockSpecial())
691+
{
692+
size_t reserve = 2*m_cipher.MandatoryBlockSize();
693+
space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, length+reserve);
694+
length = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
695+
AttachedTransformation()->Put(space, length);
696+
return;
697+
}
698+
690699
switch (m_padding)
691700
{
692701
case NO_PADDING:
693702
case ZEROS_PADDING:
694703
if (length > 0)
695704
{
696705
size_t minLastBlockSize = m_cipher.MinLastBlockSize();
706+
size_t reserve = 2*m_cipher.MandatoryBlockSize();
697707
bool isForwardTransformation = m_cipher.IsForwardTransformation();
698708

699709
if (isForwardTransformation && m_padding == ZEROS_PADDING && (minLastBlockSize == 0 || length < minLastBlockSize))
700710
{
701711
// do padding
702712
size_t blockSize = STDMAX(minLastBlockSize, (size_t)m_cipher.MandatoryBlockSize());
703-
space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, blockSize);
713+
space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, blockSize+reserve);
704714
if (inString) {memcpy(space, inString, length);}
705715
memset(space + length, 0, blockSize - length);
706-
m_cipher.ProcessLastBlock(space, space, blockSize);
707-
AttachedTransformation()->Put(space, blockSize);
716+
size_t used = m_cipher.ProcessLastBlock(space, blockSize+reserve, space, blockSize);
717+
AttachedTransformation()->Put(space, used);
708718
}
709719
else
710720
{
@@ -716,9 +726,9 @@ void StreamTransformationFilter::LastPut(const byte *inString, size_t length)
716726
throw InvalidCiphertext("StreamTransformationFilter: ciphertext length is not a multiple of block size");
717727
}
718728

719-
space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, m_optimalBufferSize);
720-
m_cipher.ProcessLastBlock(space, inString, length);
721-
AttachedTransformation()->Put(space, length);
729+
space = HelpCreatePutSpace(*AttachedTransformation(), DEFAULT_CHANNEL, length, m_optimalBufferSize+reserve);
730+
size_t used = m_cipher.ProcessLastBlock(space, length+reserve, inString, length);
731+
AttachedTransformation()->Put(space, used);
722732
}
723733
}
724734
break;

modes.cpp

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,7 @@ void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t lengt
174174

175175
void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length)
176176
{
177-
if (!length)
178-
return;
177+
if (!length) return;
179178
CRYPTOPP_ASSERT(length%BlockSize()==0);
180179

181180
unsigned int blockSize = BlockSize();
@@ -185,15 +184,17 @@ void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t l
185184
memcpy(m_register, outString + length - blockSize, blockSize);
186185
}
187186

188-
void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
187+
size_t CBC_CTS_Encryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength)
189188
{
190-
if (length <= BlockSize())
189+
CRYPTOPP_UNUSED(outLength);
190+
size_t used = inLength;
191+
if (inLength <= BlockSize())
191192
{
192193
if (!m_stolenIV)
193194
throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing");
194195

195196
// steal from IV
196-
memcpy(outString, m_register, length);
197+
memcpy(outString, m_register, inLength);
197198
outString = m_stolenIV;
198199
}
199200
else
@@ -202,14 +203,16 @@ void CBC_CTS_Encryption::ProcessLastBlock(byte *outString, const byte *inString,
202203
xorbuf(m_register, inString, BlockSize());
203204
m_cipher->ProcessBlock(m_register);
204205
inString += BlockSize();
205-
length -= BlockSize();
206-
memcpy(outString+BlockSize(), m_register, length);
206+
inLength -= BlockSize();
207+
memcpy(outString+BlockSize(), m_register, inLength);
207208
}
208209

209210
// output last full ciphertext block
210-
xorbuf(m_register, inString, length);
211+
xorbuf(m_register, inString, inLength);
211212
m_cipher->ProcessBlock(m_register);
212213
memcpy(outString, m_register, BlockSize());
214+
215+
return used;
213216
}
214217

215218
void CBC_Decryption::ResizeBuffers()
@@ -232,38 +235,44 @@ void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t l
232235
m_register.swap(m_temp);
233236
}
234237

235-
void CBC_CTS_Decryption::ProcessLastBlock(byte *outString, const byte *inString, size_t length)
238+
size_t CBC_CTS_Decryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength)
236239
{
237-
const byte *pn, *pn1;
238-
bool stealIV = length <= BlockSize();
240+
CRYPTOPP_UNUSED(outLength);
241+
const byte *pn1, *pn2;
242+
bool stealIV = inLength <= BlockSize();
243+
size_t used = inLength;
239244

240245
if (stealIV)
241246
{
242-
pn = inString;
243-
pn1 = m_register;
247+
pn1 = inString;
248+
pn2 = m_register;
244249
}
245250
else
246251
{
247-
pn = inString + BlockSize();
248-
pn1 = inString;
249-
length -= BlockSize();
252+
pn1 = inString + BlockSize();
253+
pn2 = inString;
254+
inLength -= BlockSize();
250255
}
251256

252257
// decrypt last partial plaintext block
253-
memcpy(m_temp, pn1, BlockSize());
258+
memcpy(m_temp, pn2, BlockSize());
254259
m_cipher->ProcessBlock(m_temp);
255-
xorbuf(m_temp, pn, length);
260+
xorbuf(m_temp, pn1, inLength);
256261

257262
if (stealIV)
258-
memcpy(outString, m_temp, length);
263+
{
264+
memcpy(outString, m_temp, inLength);
265+
}
259266
else
260267
{
261-
memcpy(outString+BlockSize(), m_temp, length);
268+
memcpy(outString+BlockSize(), m_temp, inLength);
262269
// decrypt next to last plaintext block
263-
memcpy(m_temp, pn, length);
270+
memcpy(m_temp, pn1, inLength);
264271
m_cipher->ProcessBlock(m_temp);
265272
xorbuf(outString, m_temp, m_register, BlockSize());
266273
}
274+
275+
return used;
267276
}
268277

269278
NAMESPACE_END

modes.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Encryption : public CBC_Encryption
255255

256256
void SetStolenIV(byte *iv) {m_stolenIV = iv;}
257257
unsigned int MinLastBlockSize() const {return BlockSize()+1;}
258-
void ProcessLastBlock(byte *outString, const byte *inString, size_t length);
258+
size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength);
259259

260260
protected:
261261
void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
@@ -287,7 +287,7 @@ class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE CBC_CTS_Decryption : public CBC_Decryption
287287
{
288288
public:
289289
unsigned int MinLastBlockSize() const {return BlockSize()+1;}
290-
void ProcessLastBlock(byte *outString, const byte *inString, size_t length);
290+
size_t ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength);
291291
};
292292

293293
//! \class CipherModeFinalTemplate_CipherHolder
@@ -476,13 +476,6 @@ struct CBC_CTS_Mode_ExternalCipher : public CipherModeDocumentation
476476
typedef CipherModeFinalTemplate_ExternalCipher<CBC_CTS_Decryption> Decryption;
477477
};
478478

479-
//#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY
480-
//typedef CFB_Mode_ExternalCipher::Encryption CFBEncryption;
481-
//typedef CFB_Mode_ExternalCipher::Decryption CFBDecryption;
482-
//typedef OFB_Mode_ExternalCipher::Encryption OFB;
483-
//typedef CTR_Mode_ExternalCipher::Encryption CounterMode;
484-
//#endif
485-
486479
NAMESPACE_END
487480

488481
// Issue 340

0 commit comments

Comments
 (0)