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