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