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