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