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 *
180 */
TestInPlaceAesCcmProcessing(void)181 void TestInPlaceAesCcmProcessing(void)
182 {
183 static constexpr uint16_t kTagLength = 4;
184 static constexpr uint32_t kHeaderLength = 19;
185
186 static const uint8_t kKey[] = {
187 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
188 };
189
190 static const uint8_t kNonce[] = {
191 0xac, 0xde, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x06,
192 };
193
194 static uint16_t kMessageLengths[] = {30, 400, 800};
195
196 uint8_t tag[kTagLength];
197 uint8_t header[kHeaderLength];
198
199 Crypto::AesCcm aesCcm;
200 Instance *instance = testInitInstance();
201 Message *message;
202 Message *messageClone;
203
204 VerifyOrQuit(instance != nullptr);
205
206 message = instance->Get<MessagePool>().Allocate(Message::kTypeIp6);
207 VerifyOrQuit(message != nullptr);
208
209 aesCcm.SetKey(kKey, sizeof(kKey));
210
211 for (uint16_t msgLength : kMessageLengths)
212 {
213 printf("msgLength %d\n", msgLength);
214
215 SuccessOrQuit(message->SetLength(0));
216
217 for (uint16_t i = msgLength; i != 0; i--)
218 {
219 SuccessOrQuit(message->Append<uint8_t>(i & 0xff));
220 }
221
222 messageClone = message->Clone();
223 VerifyOrQuit(messageClone != nullptr);
224 VerifyOrQuit(messageClone->GetLength() == msgLength);
225
226 SuccessOrQuit(message->Read(0, header));
227
228 // Encrypt in place
229 aesCcm.Init(kHeaderLength, msgLength - kHeaderLength, kTagLength, kNonce, sizeof(kNonce));
230 aesCcm.Header(header);
231 aesCcm.Payload(*message, kHeaderLength, msgLength - kHeaderLength, Crypto::AesCcm::kEncrypt);
232
233 // Append the tag
234 aesCcm.Finalize(tag);
235 SuccessOrQuit(message->Append(tag));
236
237 VerifyOrQuit(message->GetLength() == msgLength + kTagLength);
238
239 // Decrypt in place
240 aesCcm.Init(kHeaderLength, msgLength - kHeaderLength, kTagLength, kNonce, sizeof(kNonce));
241 aesCcm.Header(header);
242 aesCcm.Payload(*message, kHeaderLength, msgLength - kHeaderLength, Crypto::AesCcm::kDecrypt);
243
244 // Check the tag against what is the message
245 aesCcm.Finalize(tag);
246 VerifyOrQuit(message->Compare(msgLength, tag));
247
248 // Check that decrypted message is the same as original (cloned) message
249 VerifyOrQuit(message->CompareBytes(0, *messageClone, 0, msgLength));
250
251 messageClone->Free();
252 }
253
254 message->Free();
255 testFreeInstance(instance);
256 }
257
258 } // namespace ot
259
main(void)260 int main(void)
261 {
262 ot::TestMacBeaconFrame();
263 ot::TestMacCommandFrame();
264 ot::TestInPlaceAesCcmProcessing();
265 printf("All tests passed\n");
266 return 0;
267 }
268