cmac_test.cc
Go to the documentation of this file.
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 
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) {
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());
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());
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 
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 
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"));
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_FALSE(result.IsValid());
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.IsValid()) {
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 
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 
250 TEST(CMACTest, CAVPAES128) {
251  RunCAVPTest("crypto/cmac/cavp_aes128_cmac_tests.txt", EVP_aes_128_cbc(),
252  false);
253 }
254 
255 TEST(CMACTest, CAVPAES192) {
256  RunCAVPTest("crypto/cmac/cavp_aes192_cmac_tests.txt", EVP_aes_192_cbc(),
257  false);
258 }
259 
260 TEST(CMACTest, CAVPAES256) {
261  RunCAVPTest("crypto/cmac/cavp_aes256_cmac_tests.txt", EVP_aes_256_cbc(),
262  false);
263 }
264 
265 TEST(CMACTest, CAVP3DES) {
266  RunCAVPTest("crypto/cmac/cavp_3des_cmac_tests.txt", EVP_des_ede3_cbc(), true);
267 }
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
CMAC_CTX_copy
#define CMAC_CTX_copy
Definition: boringssl_prefix_symbols.h:1098
Bytes
Definition: boringssl-with-bazel/src/crypto/test/test_util.h:38
ctx
Definition: benchmark-async.c:30
grpc::testing::key2
const char key2[]
Definition: client_context_test_peer_test.cc:33
CMAC_Reset
#define CMAC_Reset
Definition: boringssl_prefix_symbols.h:1103
WycheproofResult
Definition: wycheproof_util.h:34
TEST
TEST(CMACTest, RFC4493TestVectors)
Definition: cmac_test.cc:74
EVP_aes_256_cbc
const OPENSSL_EXPORT EVP_CIPHER * EVP_aes_256_cbc(void)
EVP_aes_192_cbc
const OPENSSL_EXPORT EVP_CIPHER * EVP_aes_192_cbc(void)
test
static void test(const char *name, const uint8_t *key, size_t key_len, const uint8_t *msg, size_t msg_len, const uint8_t *expected)
Definition: cmac_test.cc:31
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
setup.name
name
Definition: setup.py:542
check_documentation.path
path
Definition: check_documentation.py:57
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
AES_CMAC
#define AES_CMAC
Definition: boringssl_prefix_symbols.h:594
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
FileTestGTest
void FileTestGTest(const char *path, std::function< void(FileTest *)> run_test)
Definition: file_test_gtest.cc:68
RunCAVPTest
static void RunCAVPTest(const char *path, const EVP_CIPHER *cipher, bool is_3des)
Definition: cmac_test.cc:187
evp_cipher_st
Definition: cipher.h:585
SCOPED_TRACE
#define SCOPED_TRACE(message)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2264
tag
static void * tag(intptr_t t)
Definition: bad_client.cc:318
EXPECT_NE
#define EXPECT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2028
CMAC_Update
#define CMAC_Update
Definition: boringssl_prefix_symbols.h:1104
FileTest
Definition: file_test.h:90
GetWycheproofResult
bool GetWycheproofResult(FileTest *t, WycheproofResult *out)
Definition: wycheproof_util.cc:49
done
struct tab * done
Definition: bloaty/third_party/zlib/examples/enough.c:176
cipher.h
min
#define min(a, b)
Definition: qsort.h:83
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
EVP_des_ede3_cbc
const OPENSSL_EXPORT EVP_CIPHER * EVP_des_ede3_cbc(void)
ctx2
static struct echo_ctx ctx2
Definition: test-ipc-send-recv.c:66
msg
std::string msg
Definition: client_interceptors_end2end_test.cc:372
kKey
static const uint8_t kKey[32]
Definition: chacha_test.cc:32
CMAC_Final
#define CMAC_Final
Definition: boringssl_prefix_symbols.h:1101
key
const char * key
Definition: hpack_parser_table.cc:164
CMAC_CTX_new
#define CMAC_CTX_new
Definition: boringssl_prefix_symbols.h:1100
CMAC_Init
#define CMAC_Init
Definition: boringssl_prefix_symbols.h:1102
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
ASSERT_FALSE
#define ASSERT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1976
mem.h
cmac.h
EVP_aes_128_cbc
const OPENSSL_EXPORT EVP_CIPHER * EVP_aes_128_cbc(void)
mkowners.todo
todo
Definition: mkowners.py:209


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:56