Crypto++
|
00001 // ccm.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 00005 #ifndef CRYPTOPP_IMPORTS 00006 00007 #include "ccm.h" 00008 00009 NAMESPACE_BEGIN(CryptoPP) 00010 00011 void CCM_Base::SetKeyWithoutResync(const byte *userKey, size_t keylength, const NameValuePairs ¶ms) 00012 { 00013 BlockCipher &blockCipher = AccessBlockCipher(); 00014 00015 blockCipher.SetKey(userKey, keylength, params); 00016 00017 if (blockCipher.BlockSize() != REQUIRED_BLOCKSIZE) 00018 throw InvalidArgument(AlgorithmName() + ": block size of underlying block cipher is not 16"); 00019 00020 m_digestSize = params.GetIntValueWithDefault(Name::DigestSize(), DefaultDigestSize()); 00021 if (m_digestSize % 2 > 0 || m_digestSize < 4 || m_digestSize > 16) 00022 throw InvalidArgument(AlgorithmName() + ": DigestSize must be 4, 6, 8, 10, 12, 14, or 16"); 00023 00024 m_buffer.Grow(2*REQUIRED_BLOCKSIZE); 00025 m_L = 8; 00026 } 00027 00028 void CCM_Base::Resync(const byte *iv, size_t len) 00029 { 00030 BlockCipher &cipher = AccessBlockCipher(); 00031 00032 m_L = REQUIRED_BLOCKSIZE-1-(int)len; 00033 assert(m_L >= 2); 00034 if (m_L > 8) 00035 m_L = 8; 00036 00037 m_buffer[0] = byte(m_L-1); // flag 00038 memcpy(m_buffer+1, iv, len); 00039 memset(m_buffer+1+len, 0, REQUIRED_BLOCKSIZE-1-len); 00040 00041 if (m_state >= State_IVSet) 00042 m_ctr.Resynchronize(m_buffer, REQUIRED_BLOCKSIZE); 00043 else 00044 m_ctr.SetCipherWithIV(cipher, m_buffer); 00045 00046 m_ctr.Seek(REQUIRED_BLOCKSIZE); 00047 m_aadLength = 0; 00048 m_messageLength = 0; 00049 } 00050 00051 void CCM_Base::UncheckedSpecifyDataLengths(lword headerLength, lword messageLength, lword footerLength) 00052 { 00053 if (m_state != State_IVSet) 00054 throw BadState(AlgorithmName(), "SpecifyDataLengths", "or after State_IVSet"); 00055 00056 m_aadLength = headerLength; 00057 m_messageLength = messageLength; 00058 00059 byte *cbcBuffer = CBC_Buffer(); 00060 const BlockCipher &cipher = GetBlockCipher(); 00061 00062 cbcBuffer[0] = byte(64*(headerLength>0) + 8*((m_digestSize-2)/2) + (m_L-1)); // flag 00063 PutWord<word64>(true, BIG_ENDIAN_ORDER, cbcBuffer+REQUIRED_BLOCKSIZE-8, m_messageLength); 00064 memcpy(cbcBuffer+1, m_buffer+1, REQUIRED_BLOCKSIZE-1-m_L); 00065 cipher.ProcessBlock(cbcBuffer); 00066 00067 if (headerLength>0) 00068 { 00069 assert(m_bufferedDataLength == 0); 00070 00071 if (headerLength < ((1<<16) - (1<<8))) 00072 { 00073 PutWord<word16>(true, BIG_ENDIAN_ORDER, m_buffer, (word16)headerLength); 00074 m_bufferedDataLength = 2; 00075 } 00076 else if (headerLength < (W64LIT(1)<<32)) 00077 { 00078 m_buffer[0] = 0xff; 00079 m_buffer[1] = 0xfe; 00080 PutWord<word32>(false, BIG_ENDIAN_ORDER, m_buffer+2, (word32)headerLength); 00081 m_bufferedDataLength = 6; 00082 } 00083 else 00084 { 00085 m_buffer[0] = 0xff; 00086 m_buffer[1] = 0xff; 00087 PutWord<word64>(false, BIG_ENDIAN_ORDER, m_buffer+2, headerLength); 00088 m_bufferedDataLength = 10; 00089 } 00090 } 00091 } 00092 00093 size_t CCM_Base::AuthenticateBlocks(const byte *data, size_t len) 00094 { 00095 byte *cbcBuffer = CBC_Buffer(); 00096 const BlockCipher &cipher = GetBlockCipher(); 00097 return cipher.AdvancedProcessBlocks(cbcBuffer, data, cbcBuffer, len, BlockTransformation::BT_DontIncrementInOutPointers|BlockTransformation::BT_XorInput); 00098 } 00099 00100 void CCM_Base::AuthenticateLastHeaderBlock() 00101 { 00102 byte *cbcBuffer = CBC_Buffer(); 00103 const BlockCipher &cipher = GetBlockCipher(); 00104 00105 if (m_aadLength != m_totalHeaderLength) 00106 throw InvalidArgument(AlgorithmName() + ": header length doesn't match that given in SpecifyDataLengths"); 00107 00108 if (m_bufferedDataLength > 0) 00109 { 00110 xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); 00111 cipher.ProcessBlock(cbcBuffer); 00112 m_bufferedDataLength = 0; 00113 } 00114 } 00115 00116 void CCM_Base::AuthenticateLastConfidentialBlock() 00117 { 00118 byte *cbcBuffer = CBC_Buffer(); 00119 const BlockCipher &cipher = GetBlockCipher(); 00120 00121 if (m_messageLength != m_totalMessageLength) 00122 throw InvalidArgument(AlgorithmName() + ": message length doesn't match that given in SpecifyDataLengths"); 00123 00124 if (m_bufferedDataLength > 0) 00125 { 00126 xorbuf(cbcBuffer, m_buffer, m_bufferedDataLength); 00127 cipher.ProcessBlock(cbcBuffer); 00128 m_bufferedDataLength = 0; 00129 } 00130 } 00131 00132 void CCM_Base::AuthenticateLastFooterBlock(byte *mac, size_t macSize) 00133 { 00134 m_ctr.Seek(0); 00135 m_ctr.ProcessData(mac, CBC_Buffer(), macSize); 00136 } 00137 00138 NAMESPACE_END 00139 00140 #endif