1// ccm.cpp - written and placed in the public domain by Wei Dai 2 3#include "pch.h" 4 5#ifndef CRYPTOPP_IMPORTS 6 7#include "ccm.h" 8 9NAMESPACE_BEGIN(CryptoPP) 10 11void CCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) 12{ 13 BlockCipher &blockCipher = AccessBlockCipher(); 14 15 blockCipher.SetKey(userKey, keylength, params); 16 17 if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE) 18 throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16"); 19 20 m_digestSize = params.GetIntValueWithDefault(Name::DigestSize(), DefaultDigestSize()); 21 if (m_digestSize % 2 > 0 || m_digestSize < 4 || m_digestSize > 16) 22 throw InvalidArgument(AlgorithmName() + ": DigestSize must be 4, 6, 8, 10, 12, 14, or 16"); 23 24 m_buffer.Grow(2*REQUIRED_BLOCKSIZE); 25 m_L = 8; 26} 27 28void CCM_Base::Resync(const byte *iv, size_t len) 29{ 30 BlockCipher &cipher = AccessBlockCipher(); 31 32 m_L = REQUIRED_BLOCKSIZE-1-(int)len; 33 assert(m_L >= 2); 34 if (m_L > 8) 35 m_L = 8; 36 37 m_buffer[0] = byte(m_L-1); // flag 38 memcpy(m_buffer+1, iv, len); 39 memset(m_buffer+1+len, 0, REQUIRED_BLOCKSIZE-1-len); 40 41 if (m_state >= State_IVSet) 42 m_ctr.Resynchronize(m_buffer, REQUIRED_BLOCKSIZE); 43 else 44 m_ctr.SetCipherWithIV(cipher, m_buffer); 45 46 m_ctr.Seek(REQUIRED_BLOCKSIZE); 47 m_aadLength = 0; 48 m_messageLength = 0; 49} 50 51void CCM_Base::UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) 52{ 53 if (m_state != State_IVSet) 54 throw BadState(AlgorithmName(), "SpecifyDataLengths", "or after State_IVSet"); 55 56 m_aadLength = headerLength; 57 m_messageLength = messageLength; 58 59 byte *cbcBuffer = CBC_Buffer(); 60 const BlockCipher &cipher = GetBlockCipher(); 61 62 cbcBuffer[0] = byte(64*(headerLength>0) + 8*((m_digestSize-2)/2) + (m_L-1)); // flag 63 PutWord<word64>(true, BIG_ENDIAN_ORDER, cbcBuffer+REQUIRED_BLOCKSIZE-8, m_messageLength); 64 memcpy(cbcBuffer+1, m_buffer+1, REQUIRED_BLOCKSIZE-1-m_L); 65 cipher.ProcessBlock(cbcBuffer); 66 67 if (headerLength>0) 68 { 69 assert(m_bufferedDataLength == 0); 70 71 if (headerLength < ((1<<16) - (1<<8))) 72 { 73 PutWord<word16>(true, BIG_ENDIAN_ORDER, m_buffer, (word16)headerLength); 74 m_bufferedDataLength = 2; 75 } 76 else if (headerLength < (W64LIT(1)<<32)) 77 { 78 m_buffer[0] = 0xff; 79 m_buffer[1] = 0xfe; 80 PutWord<word32>(false, BIG_ENDIAN_ORDER, m_buffer+2, (word32)headerLength); 81 m_bufferedDataLength = 6; 82 } 83 else 84 { 85 m_buffer[0] = 0xff; 86 m_buffer[1] = 0xff; 87 PutWord<word64>(false, BIG_ENDIAN_ORDER, m_buffer+2, headerLength); 88 m_bufferedDataLength = 10; 89 } 90 } 91} 92 93size_t CCM_Base::AuthenticateBlocks(const byte *data, size_t len) 94{ 95 byte *cbcBuffer = CBC_Buffer(); 96 const BlockCipher &cipher = GetBlockCipher(); 97 return cipher.AdvancedProcessBlocks(cbcBuffer, data, cbcBuffer, len, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 98} 99 100void CCM_Base::AuthenticateLastHeaderBlock() 101{ 102 byte *cbcBuffer = CBC_Buffer(); 103 const BlockCipher &cipher = GetBlockCipher(); 104 105 if (m_aadLength != m_totalHeaderLength) 106 throw InvalidArgument(AlgorithmName() + ": header length doesn't match that given in SpecifyDataLengths"); 107 108 if (m_bufferedDataLength > 0) 109 { 110 xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); 111 cipher.ProcessBlock(cbcBuffer); 112 m_bufferedDataLength = 0; 113 } 114} 115 116void CCM_Base::AuthenticateLastConfidentialBlock() 117{ 118 byte *cbcBuffer = CBC_Buffer(); 119 const BlockCipher &cipher = GetBlockCipher(); 120 121 if (m_messageLength != m_totalMessageLength) 122 throw InvalidArgument(AlgorithmName() + ": message length doesn't match that given in SpecifyDataLengths"); 123 124 if (m_bufferedDataLength > 0) 125 { 126 xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); 127 cipher.ProcessBlock(cbcBuffer); 128 m_bufferedDataLength = 0; 129 } 130} 131 132void CCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) 133{ 134 m_ctr.Seek(0); 135 m_ctr.ProcessData(mac, CBC_Buffer(), macSize); 136} 137 138NAMESPACE_END 139 140#endif 141