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