1 /*
2 * Copyright (c) 2016, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements AES-CCM.
32 */
33
34 #include "aes_ccm.hpp"
35
36 #include <limits.h>
37
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/encoding.hpp"
41
42 namespace ot {
43 namespace Crypto {
44
SetKey(const uint8_t * aKey,uint16_t aKeyLength)45 void AesCcm::SetKey(const uint8_t *aKey, uint16_t aKeyLength)
46 {
47 mEcb.SetKey(aKey, CHAR_BIT * aKeyLength);
48 }
49
SetKey(const Mac::Key & aMacKey)50 void AesCcm::SetKey(const Mac::Key &aMacKey)
51 {
52 SetKey(aMacKey.GetKey(), Mac::Key::kSize);
53 }
54
Init(uint32_t aHeaderLength,uint32_t aPlainTextLength,uint8_t aTagLength,const void * aNonce,uint8_t aNonceLength)55 void AesCcm::Init(uint32_t aHeaderLength,
56 uint32_t aPlainTextLength,
57 uint8_t aTagLength,
58 const void *aNonce,
59 uint8_t aNonceLength)
60 {
61 const uint8_t *nonceBytes = reinterpret_cast<const uint8_t *>(aNonce);
62 uint8_t blockLength = 0;
63 uint32_t len;
64 uint8_t L;
65 uint8_t i;
66
67 // Tag length must be even and within [kMinTagLength, kMaxTagLength]
68 OT_ASSERT(((aTagLength & 0x1) == 0) && (kMinTagLength <= aTagLength) && (aTagLength <= kMaxTagLength));
69
70 L = 0;
71
72 for (len = aPlainTextLength; len; len >>= 8)
73 {
74 L++;
75 }
76
77 if (L <= 1)
78 {
79 L = 2;
80 }
81
82 if (aNonceLength > 13)
83 {
84 aNonceLength = 13;
85 }
86
87 // increase L to match nonce len
88 if (L < (15 - aNonceLength))
89 {
90 L = 15 - aNonceLength;
91 }
92
93 // decrease nonceLength to match L
94 if (aNonceLength > (15 - L))
95 {
96 aNonceLength = 15 - L;
97 }
98
99 // setup initial block
100
101 // write flags
102 mBlock[0] = (static_cast<uint8_t>((aHeaderLength != 0) << 6) | static_cast<uint8_t>(((aTagLength - 2) >> 1) << 3) |
103 static_cast<uint8_t>(L - 1));
104
105 // write nonce
106 memcpy(&mBlock[1], nonceBytes, aNonceLength);
107
108 // write len
109 len = aPlainTextLength;
110
111 for (i = sizeof(mBlock) - 1; i > aNonceLength; i--)
112 {
113 mBlock[i] = len & 0xff;
114 len >>= 8;
115 }
116
117 // encrypt initial block
118 mEcb.Encrypt(mBlock, mBlock);
119
120 // process header
121 if (aHeaderLength > 0)
122 {
123 // process length
124 if (aHeaderLength < (65536U - 256U))
125 {
126 mBlock[blockLength++] ^= aHeaderLength >> 8;
127 mBlock[blockLength++] ^= aHeaderLength >> 0;
128 }
129 else
130 {
131 mBlock[blockLength++] ^= 0xff;
132 mBlock[blockLength++] ^= 0xfe;
133 mBlock[blockLength++] ^= aHeaderLength >> 24;
134 mBlock[blockLength++] ^= aHeaderLength >> 16;
135 mBlock[blockLength++] ^= aHeaderLength >> 8;
136 mBlock[blockLength++] ^= aHeaderLength >> 0;
137 }
138 }
139
140 // init counter
141 mCtr[0] = L - 1;
142 memcpy(&mCtr[1], nonceBytes, aNonceLength);
143 memset(&mCtr[aNonceLength + 1], 0, sizeof(mCtr) - aNonceLength - 1);
144
145 mNonceLength = aNonceLength;
146 mHeaderLength = aHeaderLength;
147 mHeaderCur = 0;
148 mPlainTextLength = aPlainTextLength;
149 mPlainTextCur = 0;
150 mBlockLength = blockLength;
151 mCtrLength = sizeof(mCtrPad);
152 mTagLength = aTagLength;
153 }
154
Header(const void * aHeader,uint32_t aHeaderLength)155 void AesCcm::Header(const void *aHeader, uint32_t aHeaderLength)
156 {
157 const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(aHeader);
158
159 OT_ASSERT(mHeaderCur + aHeaderLength <= mHeaderLength);
160
161 // process header
162 for (unsigned i = 0; i < aHeaderLength; i++)
163 {
164 if (mBlockLength == sizeof(mBlock))
165 {
166 mEcb.Encrypt(mBlock, mBlock);
167 mBlockLength = 0;
168 }
169
170 mBlock[mBlockLength++] ^= headerBytes[i];
171 }
172
173 mHeaderCur += aHeaderLength;
174
175 if (mHeaderCur == mHeaderLength)
176 {
177 // process remainder
178 if (mBlockLength != 0)
179 {
180 mEcb.Encrypt(mBlock, mBlock);
181 }
182
183 mBlockLength = 0;
184 }
185 }
186
Payload(void * aPlainText,void * aCipherText,uint32_t aLength,Mode aMode)187 void AesCcm::Payload(void *aPlainText, void *aCipherText, uint32_t aLength, Mode aMode)
188 {
189 uint8_t *plaintextBytes = reinterpret_cast<uint8_t *>(aPlainText);
190 uint8_t *ciphertextBytes = reinterpret_cast<uint8_t *>(aCipherText);
191 uint8_t byte;
192
193 OT_ASSERT(mPlainTextCur + aLength <= mPlainTextLength);
194
195 for (unsigned i = 0; i < aLength; i++)
196 {
197 if (mCtrLength == 16)
198 {
199 for (int j = sizeof(mCtr) - 1; j > mNonceLength; j--)
200 {
201 if (++mCtr[j])
202 {
203 break;
204 }
205 }
206
207 mEcb.Encrypt(mCtr, mCtrPad);
208 mCtrLength = 0;
209 }
210
211 if (aMode == kEncrypt)
212 {
213 byte = plaintextBytes[i];
214 ciphertextBytes[i] = byte ^ mCtrPad[mCtrLength++];
215 }
216 else
217 {
218 byte = ciphertextBytes[i] ^ mCtrPad[mCtrLength++];
219 plaintextBytes[i] = byte;
220 }
221
222 if (mBlockLength == sizeof(mBlock))
223 {
224 mEcb.Encrypt(mBlock, mBlock);
225 mBlockLength = 0;
226 }
227
228 mBlock[mBlockLength++] ^= byte;
229 }
230
231 mPlainTextCur += aLength;
232
233 if (mPlainTextCur >= mPlainTextLength)
234 {
235 if (mBlockLength != 0)
236 {
237 mEcb.Encrypt(mBlock, mBlock);
238 }
239
240 // reset counter
241 memset(&mCtr[mNonceLength + 1], 0, sizeof(mCtr) - mNonceLength - 1);
242 }
243 }
244
Finalize(void * aTag)245 void AesCcm::Finalize(void *aTag)
246 {
247 uint8_t *tagBytes = reinterpret_cast<uint8_t *>(aTag);
248
249 OT_ASSERT(mPlainTextCur == mPlainTextLength);
250
251 mEcb.Encrypt(mCtr, mCtrPad);
252
253 for (int i = 0; i < mTagLength; i++)
254 {
255 tagBytes[i] = mBlock[i] ^ mCtrPad[i];
256 }
257 }
258
GenerateNonce(const Mac::ExtAddress & aAddress,uint32_t aFrameCounter,uint8_t aSecurityLevel,uint8_t * aNonce)259 void AesCcm::GenerateNonce(const Mac::ExtAddress &aAddress,
260 uint32_t aFrameCounter,
261 uint8_t aSecurityLevel,
262 uint8_t * aNonce)
263 {
264 memcpy(aNonce, aAddress.m8, sizeof(Mac::ExtAddress));
265 aNonce += sizeof(Mac::ExtAddress);
266
267 Encoding::BigEndian::WriteUint32(aFrameCounter, aNonce);
268 aNonce += sizeof(uint32_t);
269
270 aNonce[0] = aSecurityLevel;
271 }
272
273 } // namespace Crypto
274 } // namespace ot
275