ccm.cpp
// ccm.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "ccm.h"
NAMESPACE_BEGIN(CryptoPP)
void CCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs &params)
{
BlockCipher &blockCipher = AccessBlockCipher();
blockCipher.SetKey(userKey, keylength, params);
if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE)
throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16");
m_digestSize = params.GetIntValueWithDefault(Name::DigestSize(), DefaultDigestSize());
if (m_digestSize % 2 > 0 || m_digestSize < 4 || m_digestSize > 16)
throw InvalidArgument(AlgorithmName() + ": DigestSize must be 4, 6, 8, 10, 12, 14, or 16");
m_buffer.Grow(2*REQUIRED_BLOCKSIZE);
m_L = 8;
}
void CCM_Base::Resync(const byte *iv, size_t len)
{
BlockCipher &cipher = AccessBlockCipher();
m_L = REQUIRED_BLOCKSIZE-1-(int)len;
assert(m_L >= 2);
if (m_L > 8)
m_L = 8;
m_buffer[0] = byte(m_L-1); // flag
memcpy(m_buffer+1, iv, len);
memset(m_buffer+1+len, 0, REQUIRED_BLOCKSIZE-1-len);
if (m_state >= State_IVSet)
m_ctr.Resynchronize(m_buffer, REQUIRED_BLOCKSIZE);
else
m_ctr.SetCipherWithIV(cipher, m_buffer);
m_ctr.Seek(REQUIRED_BLOCKSIZE);
m_aadLength = 0;
m_messageLength = 0;
}
void CCM_Base::UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword /*footerLength*/)
{
if (m_state != State_IVSet)
throw BadState(AlgorithmName(), "SpecifyDataLengths", "or after State_IVSet");
m_aadLength = headerLength;
m_messageLength = messageLength;
byte *cbcBuffer = CBC_Buffer();
const BlockCipher &cipher = GetBlockCipher();
cbcBuffer[0] = byte(64*(headerLength>0) + 8*((m_digestSize-2)/2) + (m_L-1)); // flag
PutWord<word64>(true, BIG_ENDIAN_ORDER, cbcBuffer+REQUIRED_BLOCKSIZE-8, m_messageLength);
memcpy(cbcBuffer+1, m_buffer+1, REQUIRED_BLOCKSIZE-1-m_L);
cipher.ProcessBlock(cbcBuffer);
if (headerLength>0)
{
assert(m_bufferedDataLength == 0);
if (headerLength < ((1<<16) - (1<<8)))
{
PutWord<word16>(true, BIG_ENDIAN_ORDER, m_buffer, (word16)headerLength);
m_bufferedDataLength = 2;
}
else if (headerLength < (W64LIT(1)<<32))
{
m_buffer[0] = 0xff;
m_buffer[1] = 0xfe;
PutWord<word32>(false, BIG_ENDIAN_ORDER, m_buffer+2, (word32)headerLength);
m_bufferedDataLength = 6;
}
else
{
m_buffer[0] = 0xff;
m_buffer[1] = 0xff;
PutWord<word64>(false, BIG_ENDIAN_ORDER, m_buffer+2, headerLength);
m_bufferedDataLength = 10;
}
}
}
size_t CCM_Base::AuthenticateBlocks(const byte *data, size_t len)
{
byte *cbcBuffer = CBC_Buffer();
const BlockCipher &cipher = GetBlockCipher();
return cipher.AdvancedProcessBlocks(cbcBuffer, data, cbcBuffer, len, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput);
}
void CCM_Base::AuthenticateLastHeaderBlock()
{
byte *cbcBuffer = CBC_Buffer();
const BlockCipher &cipher = GetBlockCipher();
if (m_aadLength != m_totalHeaderLength)
throw InvalidArgument(AlgorithmName() + ": header length doesn't match that given in SpecifyDataLengths");
if (m_bufferedDataLength > 0)
{
xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength);
cipher.ProcessBlock(cbcBuffer);
m_bufferedDataLength = 0;
}
}
void CCM_Base::AuthenticateLastConfidentialBlock()
{
byte *cbcBuffer = CBC_Buffer();
const BlockCipher &cipher = GetBlockCipher();
if (m_messageLength != m_totalMessageLength)
throw InvalidArgument(AlgorithmName() + ": message length doesn't match that given in SpecifyDataLengths");
if (m_bufferedDataLength > 0)
{
xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength);
cipher.ProcessBlock(cbcBuffer);
m_bufferedDataLength = 0;
}
}
void CCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize)
{
m_ctr.Seek(0);
m_ctr.ProcessData(mac, CBC_Buffer(), macSize);
}
NAMESPACE_END
#endif
NameValuePairs::GetIntValueWithDefault
int GetIntValueWithDefault(const char *name, int defaultValue) const
Get a named value with type int, with default.
Definition: cryptlib.h:380
Name::DigestSize
const char * DigestSize()
int, in bytes
Definition: argnames.h:78
InvalidArgument
An invalid argument was detected.
Definition: cryptlib.h:182
AdditiveCipherTemplate::Resynchronize
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:126
SimpleKeyingInterface::SetKey
virtual void SetKey(const byte *key, size_t length, const NameValuePairs &params=g_nullNameValuePairs)
Sets or reset the key of this object.
Definition: cryptlib.cpp:101
BlockTransformation::BT_DontIncrementInOutPointers
should not modify block pointers
Definition: cryptlib.h:789
BlockCipher
Interface for one direction (encryption or decryption) of a block cipher.
Definition: cryptlib.h:1091
AdditiveCipherTemplate::Seek
void Seek(lword position)
Seeks to a random position in the stream.
Definition: strciphr.cpp:135
BlockTransformation::BlockSize
virtual unsigned int BlockSize() const =0
Provides the block size of the cipher.
AdditiveCipherTemplate::ProcessData
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:67
BlockTransformation::AdvancedProcessBlocks
virtual size_t AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
Encrypt and xor multiple blocks using additional flags.
Definition: cryptlib.cpp:182
BlockTransformation::ProcessBlock
void ProcessBlock(const byte *inBlock, byte *outBlock) const
Encrypt or decrypt a block.
Definition: cryptlib.h:751
BIG_ENDIAN_ORDER
byte order is big-endian
Definition: cryptlib.h:127
CCM_Base::AlgorithmName
std::string AlgorithmName() const
Provides the name of this algorithm.
Definition: ccm.h:26
xorbuf
void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:28
CryptoPP
Crypto++ library namespace.
ccm.h
CCM block cipher mode of operation.
NameValuePairs
Interface for retrieving values given their names.
Definition: cryptlib.h:277