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     Key cryptoKey;
48 
49     cryptoKey.Set(aKey, aKeyLength);
50     SetKey(cryptoKey);
51 }
52 
SetKey(const Mac::KeyMaterial & aMacKey)53 void AesCcm::SetKey(const Mac::KeyMaterial &aMacKey)
54 {
55     Key cryptoKey;
56 
57     aMacKey.ConvertToCryptoKey(cryptoKey);
58     SetKey(cryptoKey);
59 }
60 
Init(uint32_t aHeaderLength,uint32_t aPlainTextLength,uint8_t aTagLength,const void * aNonce,uint8_t aNonceLength)61 void AesCcm::Init(uint32_t    aHeaderLength,
62                   uint32_t    aPlainTextLength,
63                   uint8_t     aTagLength,
64                   const void *aNonce,
65                   uint8_t     aNonceLength)
66 {
67     const uint8_t *nonceBytes  = reinterpret_cast<const uint8_t *>(aNonce);
68     uint8_t        blockLength = 0;
69     uint32_t       len;
70     uint8_t        L;
71     uint8_t        i;
72 
73     // Tag length must be even and within [kMinTagLength, kMaxTagLength]
74     OT_ASSERT(((aTagLength & 0x1) == 0) && (kMinTagLength <= aTagLength) && (aTagLength <= kMaxTagLength));
75 
76     L = 0;
77 
78     for (len = aPlainTextLength; len; len >>= 8)
79     {
80         L++;
81     }
82 
83     if (L <= 1)
84     {
85         L = 2;
86     }
87 
88     if (aNonceLength > 13)
89     {
90         aNonceLength = 13;
91     }
92 
93     // increase L to match nonce len
94     if (L < (15 - aNonceLength))
95     {
96         L = 15 - aNonceLength;
97     }
98 
99     // decrease nonceLength to match L
100     if (aNonceLength > (15 - L))
101     {
102         aNonceLength = 15 - L;
103     }
104 
105     // setup initial block
106 
107     // write flags
108     mBlock[0] = (static_cast<uint8_t>((aHeaderLength != 0) << 6) | static_cast<uint8_t>(((aTagLength - 2) >> 1) << 3) |
109                  static_cast<uint8_t>(L - 1));
110 
111     // write nonce
112     memcpy(&mBlock[1], nonceBytes, aNonceLength);
113 
114     // write len
115     len = aPlainTextLength;
116 
117     for (i = sizeof(mBlock) - 1; i > aNonceLength; i--)
118     {
119         mBlock[i] = len & 0xff;
120         len >>= 8;
121     }
122 
123     // encrypt initial block
124     mEcb.Encrypt(mBlock, mBlock);
125 
126     // process header
127     if (aHeaderLength > 0)
128     {
129         // process length
130         if (aHeaderLength < (65536U - 256U))
131         {
132             mBlock[blockLength++] ^= aHeaderLength >> 8;
133             mBlock[blockLength++] ^= aHeaderLength >> 0;
134         }
135         else
136         {
137             mBlock[blockLength++] ^= 0xff;
138             mBlock[blockLength++] ^= 0xfe;
139             mBlock[blockLength++] ^= aHeaderLength >> 24;
140             mBlock[blockLength++] ^= aHeaderLength >> 16;
141             mBlock[blockLength++] ^= aHeaderLength >> 8;
142             mBlock[blockLength++] ^= aHeaderLength >> 0;
143         }
144     }
145 
146     // init counter
147     mCtr[0] = L - 1;
148     memcpy(&mCtr[1], nonceBytes, aNonceLength);
149     memset(&mCtr[aNonceLength + 1], 0, sizeof(mCtr) - aNonceLength - 1);
150 
151     mNonceLength     = aNonceLength;
152     mHeaderLength    = aHeaderLength;
153     mHeaderCur       = 0;
154     mPlainTextLength = aPlainTextLength;
155     mPlainTextCur    = 0;
156     mBlockLength     = blockLength;
157     mCtrLength       = sizeof(mCtrPad);
158     mTagLength       = aTagLength;
159 }
160 
Header(const void * aHeader,uint32_t aHeaderLength)161 void AesCcm::Header(const void *aHeader, uint32_t aHeaderLength)
162 {
163     const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(aHeader);
164 
165     OT_ASSERT(mHeaderCur + aHeaderLength <= mHeaderLength);
166 
167     // process header
168     for (unsigned i = 0; i < aHeaderLength; i++)
169     {
170         if (mBlockLength == sizeof(mBlock))
171         {
172             mEcb.Encrypt(mBlock, mBlock);
173             mBlockLength = 0;
174         }
175 
176         mBlock[mBlockLength++] ^= headerBytes[i];
177     }
178 
179     mHeaderCur += aHeaderLength;
180 
181     if (mHeaderCur == mHeaderLength)
182     {
183         // process remainder
184         if (mBlockLength != 0)
185         {
186             mEcb.Encrypt(mBlock, mBlock);
187         }
188 
189         mBlockLength = 0;
190     }
191 }
192 
Payload(void * aPlainText,void * aCipherText,uint32_t aLength,Mode aMode)193 void AesCcm::Payload(void *aPlainText, void *aCipherText, uint32_t aLength, Mode aMode)
194 {
195     uint8_t *plaintextBytes  = reinterpret_cast<uint8_t *>(aPlainText);
196     uint8_t *ciphertextBytes = reinterpret_cast<uint8_t *>(aCipherText);
197     uint8_t  byte;
198 
199     OT_ASSERT(mPlainTextCur + aLength <= mPlainTextLength);
200 
201     for (unsigned i = 0; i < aLength; i++)
202     {
203         if (mCtrLength == 16)
204         {
205             for (int j = sizeof(mCtr) - 1; j > mNonceLength; j--)
206             {
207                 if (++mCtr[j])
208                 {
209                     break;
210                 }
211             }
212 
213             mEcb.Encrypt(mCtr, mCtrPad);
214             mCtrLength = 0;
215         }
216 
217         if (aMode == kEncrypt)
218         {
219             byte               = plaintextBytes[i];
220             ciphertextBytes[i] = byte ^ mCtrPad[mCtrLength++];
221         }
222         else
223         {
224             byte              = ciphertextBytes[i] ^ mCtrPad[mCtrLength++];
225             plaintextBytes[i] = byte;
226         }
227 
228         if (mBlockLength == sizeof(mBlock))
229         {
230             mEcb.Encrypt(mBlock, mBlock);
231             mBlockLength = 0;
232         }
233 
234         mBlock[mBlockLength++] ^= byte;
235     }
236 
237     mPlainTextCur += aLength;
238 
239     if (mPlainTextCur >= mPlainTextLength)
240     {
241         if (mBlockLength != 0)
242         {
243             mEcb.Encrypt(mBlock, mBlock);
244         }
245 
246         // reset counter
247         memset(&mCtr[mNonceLength + 1], 0, sizeof(mCtr) - mNonceLength - 1);
248     }
249 }
250 
251 #if !OPENTHREAD_RADIO
Payload(Message & aMessage,uint16_t aOffset,uint16_t aLength,Mode aMode)252 void AesCcm::Payload(Message &aMessage, uint16_t aOffset, uint16_t aLength, Mode aMode)
253 {
254     Message::MutableChunk chunk;
255 
256     aMessage.GetFirstChunk(aOffset, aLength, chunk);
257 
258     while (chunk.GetLength() > 0)
259     {
260         Payload(chunk.GetBytes(), chunk.GetBytes(), chunk.GetLength(), aMode);
261         aMessage.GetNextChunk(aLength, chunk);
262     }
263 }
264 #endif
265 
Finalize(void * aTag)266 void AesCcm::Finalize(void *aTag)
267 {
268     uint8_t *tagBytes = reinterpret_cast<uint8_t *>(aTag);
269 
270     OT_ASSERT(mPlainTextCur == mPlainTextLength);
271 
272     mEcb.Encrypt(mCtr, mCtrPad);
273 
274     for (int i = 0; i < mTagLength; i++)
275     {
276         tagBytes[i] = mBlock[i] ^ mCtrPad[i];
277     }
278 }
279 
GenerateNonce(const Mac::ExtAddress & aAddress,uint32_t aFrameCounter,uint8_t aSecurityLevel,uint8_t * aNonce)280 void AesCcm::GenerateNonce(const Mac::ExtAddress &aAddress,
281                            uint32_t               aFrameCounter,
282                            uint8_t                aSecurityLevel,
283                            uint8_t               *aNonce)
284 {
285     memcpy(aNonce, aAddress.m8, sizeof(Mac::ExtAddress));
286     aNonce += sizeof(Mac::ExtAddress);
287 
288     Encoding::BigEndian::WriteUint32(aFrameCounter, aNonce);
289     aNonce += sizeof(uint32_t);
290 
291     aNonce[0] = aSecurityLevel;
292 }
293 
294 } // namespace Crypto
295 } // namespace ot
296