• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <stdio.h>
16 
17 #include <algorithm>
18 #include <vector>
19 
20 #include <gtest/gtest.h>
21 
22 #include <openssl/cipher.h>
23 #include <openssl/cmac.h>
24 #include <openssl/mem.h>
25 
26 #include "../test/file_test.h"
27 #include "../test/test_util.h"
28 #include "../test/wycheproof_util.h"
29 
30 
test(const char * name,const uint8_t * key,size_t key_len,const uint8_t * msg,size_t msg_len,const uint8_t * expected)31 static void test(const char *name, const uint8_t *key, size_t key_len,
32                  const uint8_t *msg, size_t msg_len, const uint8_t *expected) {
33   SCOPED_TRACE(name);
34 
35   // Test the single-shot API.
36   uint8_t out[16];
37   ASSERT_TRUE(AES_CMAC(out, key, key_len, msg, msg_len));
38   EXPECT_EQ(Bytes(expected, sizeof(out)), Bytes(out));
39 
40   bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new());
41   ASSERT_TRUE(ctx);
42   ASSERT_TRUE(CMAC_Init(ctx.get(), key, key_len, EVP_aes_128_cbc(), NULL));
43 
44   for (unsigned chunk_size = 1; chunk_size <= msg_len; chunk_size++) {
45     SCOPED_TRACE(chunk_size);
46 
47     ASSERT_TRUE(CMAC_Reset(ctx.get()));
48 
49     size_t done = 0;
50     while (done < msg_len) {
51       size_t todo = std::min(msg_len - done, static_cast<size_t>(chunk_size));
52       ASSERT_TRUE(CMAC_Update(ctx.get(), msg + done, todo));
53       done += todo;
54     }
55 
56     size_t out_len;
57     ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
58     EXPECT_EQ(Bytes(expected, sizeof(out)), Bytes(out, out_len));
59   }
60 
61   // Test that |CMAC_CTX_copy| works.
62   ASSERT_TRUE(CMAC_Reset(ctx.get()));
63   size_t chunk = msg_len / 2;
64   ASSERT_TRUE(CMAC_Update(ctx.get(), msg, chunk));
65   bssl::UniquePtr<CMAC_CTX> ctx2(CMAC_CTX_new());
66   ASSERT_TRUE(ctx2);
67   ASSERT_TRUE(CMAC_CTX_copy(ctx2.get(), ctx.get()));
68   ASSERT_TRUE(CMAC_Update(ctx2.get(), msg + chunk, msg_len - chunk));
69   size_t out_len;
70   ASSERT_TRUE(CMAC_Final(ctx2.get(), out, &out_len));
71   EXPECT_EQ(Bytes(expected, sizeof(out)), Bytes(out, out_len));
72 }
73 
TEST(CMACTest,RFC4493TestVectors)74 TEST(CMACTest, RFC4493TestVectors) {
75   static const uint8_t kKey[16] = {
76       0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
77       0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
78   };
79   static const uint8_t kOut1[16] = {
80       0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
81       0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46,
82   };
83   static const uint8_t kMsg2[] = {
84       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
85       0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
86   };
87   static const uint8_t kOut2[16] = {
88       0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
89       0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c,
90   };
91   static const uint8_t kMsg3[] = {
92       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
93       0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
94       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
95       0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
96       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
97   };
98   static const uint8_t kOut3[16] = {
99       0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
100       0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27,
101   };
102   static const uint8_t kMsg4[] = {
103       0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
104       0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
105       0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
106       0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
107       0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
108       0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
109       0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
110       0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
111   };
112   static const uint8_t kOut4[16] = {
113       0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
114       0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe,
115   };
116 
117   test("RFC 4493 #1", kKey, sizeof(kKey), NULL, 0, kOut1);
118   test("RFC 4493 #2", kKey, sizeof(kKey), kMsg2, sizeof(kMsg2), kOut2);
119   test("RFC 4493 #3", kKey, sizeof(kKey), kMsg3, sizeof(kMsg3), kOut3);
120   test("RFC 4493 #4", kKey, sizeof(kKey), kMsg4, sizeof(kMsg4), kOut4);
121 }
122 
TEST(CMACTest,Wycheproof)123 TEST(CMACTest, Wycheproof) {
124   FileTestGTest("third_party/wycheproof_testvectors/aes_cmac_test.txt",
125                 [](FileTest *t) {
126     std::string key_size, tag_size;
127     ASSERT_TRUE(t->GetInstruction(&key_size, "keySize"));
128     ASSERT_TRUE(t->GetInstruction(&tag_size, "tagSize"));
129     WycheproofResult result;
130     ASSERT_TRUE(GetWycheproofResult(t, &result));
131     std::vector<uint8_t> key, msg, tag;
132     ASSERT_TRUE(t->GetBytes(&key, "key"));
133     ASSERT_TRUE(t->GetBytes(&msg, "msg"));
134     ASSERT_TRUE(t->GetBytes(&tag, "tag"));
135 
136     const EVP_CIPHER *cipher;
137     switch (atoi(key_size.c_str())) {
138       case 128:
139         cipher = EVP_aes_128_cbc();
140         break;
141       case 192:
142         cipher = EVP_aes_192_cbc();
143         break;
144       case 256:
145         cipher = EVP_aes_256_cbc();
146         break;
147       default:
148         // Some test vectors intentionally give the wrong key size. Our API
149         // requires the caller pick the sized CBC primitive, so these tests
150         // aren't useful for us.
151         EXPECT_EQ(WycheproofResult::kInvalid, result);
152         return;
153     }
154 
155     size_t tag_len = static_cast<size_t>(atoi(tag_size.c_str())) / 8;
156 
157     uint8_t out[16];
158     bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new());
159     ASSERT_TRUE(ctx);
160     ASSERT_TRUE(CMAC_Init(ctx.get(), key.data(), key.size(), cipher, NULL));
161     ASSERT_TRUE(CMAC_Update(ctx.get(), msg.data(), msg.size()));
162     size_t out_len;
163     ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
164     // Truncate the tag, if requested.
165     out_len = std::min(out_len, tag_len);
166 
167     if (result == WycheproofResult::kValid) {
168       EXPECT_EQ(Bytes(tag), Bytes(out, out_len));
169 
170       // Test the streaming API as well.
171       ASSERT_TRUE(CMAC_Reset(ctx.get()));
172       for (uint8_t b : msg) {
173         ASSERT_TRUE(CMAC_Update(ctx.get(), &b, 1));
174       }
175       ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
176       out_len = std::min(out_len, tag_len);
177       EXPECT_EQ(Bytes(tag), Bytes(out, out_len));
178     } else {
179       // Wycheproof's invalid tests assume the implementation internally does
180       // the comparison, whereas our API only computes the tag. Check that
181       // they're not equal, but these tests are mostly not useful for us.
182       EXPECT_NE(Bytes(tag), Bytes(out, out_len));
183     }
184   });
185 }
186 
RunCAVPTest(const char * path,const EVP_CIPHER * cipher,bool is_3des)187 static void RunCAVPTest(const char *path, const EVP_CIPHER *cipher,
188                         bool is_3des) {
189   FileTestGTest(path, [&](FileTest *t) {
190     t->IgnoreAttribute("Count");
191     t->IgnoreAttribute("Klen");
192     std::string t_len, m_len, result;
193     ASSERT_TRUE(t->GetAttribute(&t_len, "Tlen"));
194     ASSERT_TRUE(t->GetAttribute(&m_len, "Mlen"));
195     ASSERT_TRUE(t->GetAttribute(&result, "Result"));
196     std::vector<uint8_t> key, msg, mac;
197     if (is_3des) {
198       std::vector<uint8_t> key2, key3;
199       ASSERT_TRUE(t->GetBytes(&key, "Key1"));
200       ASSERT_TRUE(t->GetBytes(&key2, "Key2"));
201       ASSERT_TRUE(t->GetBytes(&key3, "Key3"));
202       key.insert(key.end(), key2.begin(), key2.end());
203       key.insert(key.end(), key3.begin(), key3.end());
204     } else {
205       ASSERT_TRUE(t->GetBytes(&key, "Key"));
206     }
207     ASSERT_TRUE(t->GetBytes(&msg, "Msg"));
208     ASSERT_TRUE(t->GetBytes(&mac, "Mac"));
209 
210     // CAVP's uses a non-empty Msg attribute and zero Mlen for the empty string.
211     if (atoi(m_len.c_str()) == 0) {
212       msg.clear();
213     } else {
214       EXPECT_EQ(static_cast<size_t>(atoi(m_len.c_str())), msg.size());
215     }
216 
217     size_t tag_len = static_cast<size_t>(atoi(t_len.c_str()));
218 
219     uint8_t out[16];
220     bssl::UniquePtr<CMAC_CTX> ctx(CMAC_CTX_new());
221     ASSERT_TRUE(ctx);
222     ASSERT_TRUE(CMAC_Init(ctx.get(), key.data(), key.size(), cipher, NULL));
223     ASSERT_TRUE(CMAC_Update(ctx.get(), msg.data(), msg.size()));
224     size_t out_len;
225     ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
226     // Truncate the tag, if requested.
227     out_len = std::min(out_len, tag_len);
228 
229     ASSERT_FALSE(result.empty());
230     if (result[0] == 'P') {
231       EXPECT_EQ(Bytes(mac), Bytes(out, out_len));
232 
233       // Test the streaming API as well.
234       ASSERT_TRUE(CMAC_Reset(ctx.get()));
235       for (uint8_t b : msg) {
236         ASSERT_TRUE(CMAC_Update(ctx.get(), &b, 1));
237       }
238       ASSERT_TRUE(CMAC_Final(ctx.get(), out, &out_len));
239       out_len = std::min(out_len, tag_len);
240       EXPECT_EQ(Bytes(mac), Bytes(out, out_len));
241     } else {
242       // CAVP's invalid tests assume the implementation internally does the
243       // comparison, whereas our API only computes the tag. Check that they're
244       // not equal, but these tests are mostly not useful for us.
245       EXPECT_NE(Bytes(mac), Bytes(out, out_len));
246     }
247   });
248 }
249 
TEST(CMACTest,CAVPAES128)250 TEST(CMACTest, CAVPAES128) {
251   RunCAVPTest("crypto/cmac/cavp_aes128_cmac_tests.txt", EVP_aes_128_cbc(),
252               false);
253 }
254 
TEST(CMACTest,CAVPAES192)255 TEST(CMACTest, CAVPAES192) {
256   RunCAVPTest("crypto/cmac/cavp_aes192_cmac_tests.txt", EVP_aes_192_cbc(),
257               false);
258 }
259 
TEST(CMACTest,CAVPAES256)260 TEST(CMACTest, CAVPAES256) {
261   RunCAVPTest("crypto/cmac/cavp_aes256_cmac_tests.txt", EVP_aes_256_cbc(),
262               false);
263 }
264 
TEST(CMACTest,CAVP3DES)265 TEST(CMACTest, CAVP3DES) {
266   RunCAVPTest("crypto/cmac/cavp_3des_cmac_tests.txt", EVP_des_ede3_cbc(), true);
267 }
268