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 #include <openthread/config.h>
30 
31 #include "common/debug.hpp"
32 #include "crypto/aes_ccm.hpp"
33 
34 #include "test_platform.h"
35 #include "test_util.hpp"
36 
37 /**
38  * Verifies test vectors from IEEE 802.15.4-2006 Annex C Section C.2.1
39  */
TestMacBeaconFrame(void)40 void TestMacBeaconFrame(void)
41 {
42     uint8_t key[] = {
43         0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
44     };
45 
46     uint8_t test[] = {0x08, 0xD0, 0x84, 0x21, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE,
47                       0xAC, 0x02, 0x05, 0x00, 0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52,
48                       0x53, 0x54, 0x22, 0x3B, 0xC1, 0xEC, 0x84, 0x1A, 0xB5, 0x53};
49 
50     uint8_t encrypted[] = {0x08, 0xD0, 0x84, 0x21, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE,
51                            0xAC, 0x02, 0x05, 0x00, 0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52,
52                            0x53, 0x54, 0x22, 0x3B, 0xC1, 0xEC, 0x84, 0x1A, 0xB5, 0x53};
53 
54     uint8_t decrypted[] = {0x08, 0xD0, 0x84, 0x21, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE,
55                            0xAC, 0x02, 0x05, 0x00, 0x00, 0x00, 0x55, 0xCF, 0x00, 0x00, 0x51, 0x52,
56                            0x53, 0x54, 0x22, 0x3B, 0xC1, 0xEC, 0x84, 0x1A, 0xB5, 0x53};
57 
58     otInstance        *instance = testInitInstance();
59     ot::Crypto::AesCcm aesCcm;
60     uint32_t           headerLength  = sizeof(test) - 8;
61     uint32_t           payloadLength = 0;
62     uint8_t            tagLength     = 8;
63 
64     uint8_t nonce[] = {
65         0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02,
66     };
67 
68     VerifyOrQuit(instance != nullptr);
69 
70     aesCcm.SetKey(key, sizeof(key));
71     aesCcm.Init(headerLength, payloadLength, tagLength, nonce, sizeof(nonce));
72     aesCcm.Header(test, headerLength);
73     VerifyOrQuit(aesCcm.GetTagLength() == tagLength);
74     aesCcm.Finalize(test + headerLength);
75 
76     VerifyOrQuit(memcmp(test, encrypted, sizeof(encrypted)) == 0);
77 
78     aesCcm.Init(headerLength, payloadLength, tagLength, nonce, sizeof(nonce));
79     aesCcm.Header(test, headerLength);
80     VerifyOrQuit(aesCcm.GetTagLength() == tagLength);
81     aesCcm.Finalize(test + headerLength);
82 
83     VerifyOrQuit(memcmp(test, decrypted, sizeof(decrypted)) == 0);
84 
85     testFreeInstance(instance);
86 }
87 
88 /**
89  * Verifies test vectors from IEEE 802.15.4-2006 Annex C Section C.2.3
90  */
TestMacCommandFrame(void)91 void TestMacCommandFrame(void)
92 {
93     uint8_t key[] = {
94         0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
95     };
96 
97     uint8_t test[] = {
98         0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC,
99         0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00,
100         0x00, 0x00, 0x01, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101     };
102 
103     static constexpr uint32_t kHeaderLength  = 29;
104     static constexpr uint32_t kPayloadLength = 1;
105     static constexpr uint8_t  kTagLength     = 8;
106 
107     uint8_t encrypted[] = {
108         0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC,
109         0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00,
110         0x00, 0x00, 0x01, 0xD8, 0x4F, 0xDE, 0x52, 0x90, 0x61, 0xF9, 0xC6, 0xF1,
111     };
112 
113     uint8_t decrypted[] = {
114         0x2B, 0xDC, 0x84, 0x21, 0x43, 0x02, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC,
115         0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xDE, 0xAC, 0x06, 0x05, 0x00,
116         0x00, 0x00, 0x01, 0xCE, 0x4F, 0xDE, 0x52, 0x90, 0x61, 0xF9, 0xC6, 0xF1,
117     };
118 
119     uint8_t nonce[] = {
120         0xAC, 0xDE, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
121     };
122 
123     uint8_t tag[kTagLength];
124 
125     ot::Instance      *instance = testInitInstance();
126     ot::Message       *message;
127     ot::Crypto::AesCcm aesCcm;
128 
129     VerifyOrQuit(instance != nullptr);
130 
131     aesCcm.SetKey(key, sizeof(key));
132     aesCcm.Init(kHeaderLength, kPayloadLength, kTagLength, nonce, sizeof(nonce));
133     aesCcm.Header(test, kHeaderLength);
134     aesCcm.Payload(test + kHeaderLength, test + kHeaderLength, kPayloadLength, ot::Crypto::AesCcm::kEncrypt);
135     VerifyOrQuit(aesCcm.GetTagLength() == kTagLength);
136     aesCcm.Finalize(test + kHeaderLength + kPayloadLength);
137     VerifyOrQuit(memcmp(test, encrypted, sizeof(encrypted)) == 0);
138 
139     aesCcm.Init(kHeaderLength, kPayloadLength, kTagLength, nonce, sizeof(nonce));
140     aesCcm.Header(test, kHeaderLength);
141     aesCcm.Payload(test + kHeaderLength, test + kHeaderLength, kPayloadLength, ot::Crypto::AesCcm::kDecrypt);
142     VerifyOrQuit(aesCcm.GetTagLength() == kTagLength);
143     aesCcm.Finalize(test + kHeaderLength + kPayloadLength);
144 
145     VerifyOrQuit(memcmp(test, decrypted, sizeof(decrypted)) == 0);
146 
147     // Verify encryption/decryption in place within a message.
148 
149     message = instance->Get<ot::MessagePool>().Allocate(ot::Message::kTypeIp6);
150     VerifyOrQuit(message != nullptr);
151 
152     SuccessOrQuit(message->AppendBytes(test, kHeaderLength + kPayloadLength));
153 
154     aesCcm.Init(kHeaderLength, kPayloadLength, kTagLength, nonce, sizeof(nonce));
155     aesCcm.Header(test, kHeaderLength);
156 
157     aesCcm.Payload(*message, kHeaderLength, kPayloadLength, ot::Crypto::AesCcm::kEncrypt);
158     VerifyOrQuit(aesCcm.GetTagLength() == kTagLength);
159     aesCcm.Finalize(tag);
160     SuccessOrQuit(message->Append(tag));
161     VerifyOrQuit(message->GetLength() == sizeof(encrypted));
162     VerifyOrQuit(message->Compare(0, encrypted));
163 
164     aesCcm.Init(kHeaderLength, kPayloadLength, kTagLength, nonce, sizeof(nonce));
165     aesCcm.Header(test, kHeaderLength);
166     aesCcm.Payload(*message, kHeaderLength, kPayloadLength, ot::Crypto::AesCcm::kDecrypt);
167 
168     VerifyOrQuit(message->GetLength() == sizeof(encrypted));
169     VerifyOrQuit(message->Compare(0, decrypted));
170 
171     message->Free();
172     testFreeInstance(instance);
173 }
174 
175 /**
176  * Verifies in-place encryption/decryption.
177  *
178  */
TestInPlaceAesCcmProcessing(void)179 void TestInPlaceAesCcmProcessing(void)
180 {
181     static constexpr uint16_t kTagLength    = 4;
182     static constexpr uint32_t kHeaderLength = 19;
183 
184     static const uint8_t kKey[] = {
185         0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
186     };
187 
188     static const uint8_t kNonce[] = {
189         0xac, 0xde, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
190     };
191 
192     static uint16_t kMessageLengths[] = {30, 400, 800};
193 
194     uint8_t tag[kTagLength];
195     uint8_t header[kHeaderLength];
196 
197     ot::Crypto::AesCcm aesCcm;
198     ot::Instance      *instance = testInitInstance();
199     ot::Message       *message;
200     ot::Message       *messageClone;
201 
202     VerifyOrQuit(instance != nullptr);
203 
204     message = instance->Get<ot::MessagePool>().Allocate(ot::Message::kTypeIp6);
205     VerifyOrQuit(message != nullptr);
206 
207     aesCcm.SetKey(kKey, sizeof(kKey));
208 
209     for (uint16_t msgLength : kMessageLengths)
210     {
211         printf("msgLength %d\n", msgLength);
212 
213         SuccessOrQuit(message->SetLength(0));
214 
215         for (uint16_t i = msgLength; i != 0; i--)
216         {
217             SuccessOrQuit(message->Append<uint8_t>(i & 0xff));
218         }
219 
220         messageClone = message->Clone();
221         VerifyOrQuit(messageClone != nullptr);
222         VerifyOrQuit(messageClone->GetLength() == msgLength);
223 
224         SuccessOrQuit(message->Read(0, header));
225 
226         // Encrypt in place
227         aesCcm.Init(kHeaderLength, msgLength - kHeaderLength, kTagLength, kNonce, sizeof(kNonce));
228         aesCcm.Header(header);
229         aesCcm.Payload(*message, kHeaderLength, msgLength - kHeaderLength, ot::Crypto::AesCcm::kEncrypt);
230 
231         // Append the tag
232         aesCcm.Finalize(tag);
233         SuccessOrQuit(message->Append(tag));
234 
235         VerifyOrQuit(message->GetLength() == msgLength + kTagLength);
236 
237         // Decrpt in place
238         aesCcm.Init(kHeaderLength, msgLength - kHeaderLength, kTagLength, kNonce, sizeof(kNonce));
239         aesCcm.Header(header);
240         aesCcm.Payload(*message, kHeaderLength, msgLength - kHeaderLength, ot::Crypto::AesCcm::kDecrypt);
241 
242         // Check the tag against what is the message
243         aesCcm.Finalize(tag);
244         VerifyOrQuit(message->Compare(msgLength, tag));
245 
246         // Check that decrypted message is the same as original (cloned) message
247         VerifyOrQuit(message->CompareBytes(0, *messageClone, 0, msgLength));
248 
249         messageClone->Free();
250     }
251 
252     message->Free();
253     testFreeInstance(instance);
254 }
255 
main(void)256 int main(void)
257 {
258     TestMacBeaconFrame();
259     TestMacCommandFrame();
260     TestInPlaceAesCcmProcessing();
261     printf("All tests passed\n");
262     return 0;
263 }
264