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