// ccm.cpp - originally 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 ¶ms) { 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; CRYPTOPP_ASSERT(m_L >= 2); if (m_L > 8) m_L = 8; m_buffer[0] = byte(m_L-1); // flag std::memcpy(m_buffer+1, iv, len); std::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(true, BIG_ENDIAN_ORDER, cbcBuffer+REQUIRED_BLOCKSIZE-8, m_messageLength); std::memcpy(cbcBuffer+1, m_buffer+1, REQUIRED_BLOCKSIZE-1-m_L); cipher.ProcessBlock(cbcBuffer); if (headerLength>0) { CRYPTOPP_ASSERT(m_bufferedDataLength == 0); if (headerLength < ((1<<16) - (1<<8))) { PutWord(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(false, BIG_ENDIAN_ORDER, m_buffer+2, (word32)headerLength); m_bufferedDataLength = 6; } else { m_buffer[0] = 0xff; m_buffer[1] = 0xff; PutWord(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