1 // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <memory>
16 #include <string>
17 #include <vector>
18
19 #include <gtest/gtest.h>
20
21 #include <openssl/digest.h>
22 #include <openssl/hmac.h>
23
24 #include "../test/file_test.h"
25 #include "../test/test_util.h"
26 #include "../test/wycheproof_util.h"
27
28
GetDigest(const std::string & name)29 static const EVP_MD *GetDigest(const std::string &name) {
30 if (name == "MD5") {
31 return EVP_md5();
32 } else if (name == "SHA1") {
33 return EVP_sha1();
34 } else if (name == "SHA224") {
35 return EVP_sha224();
36 } else if (name == "SHA256") {
37 return EVP_sha256();
38 } else if (name == "SHA384") {
39 return EVP_sha384();
40 } else if (name == "SHA512") {
41 return EVP_sha512();
42 }
43 return nullptr;
44 }
45
TEST(HMACTest,TestVectors)46 TEST(HMACTest, TestVectors) {
47 FileTestGTest("crypto/hmac/hmac_tests.txt", [](FileTest *t) {
48 std::string digest_str;
49 ASSERT_TRUE(t->GetAttribute(&digest_str, "HMAC"));
50 const EVP_MD *digest = GetDigest(digest_str);
51 ASSERT_TRUE(digest) << "Unknown digest: " << digest_str;
52
53 std::vector<uint8_t> key, input, output;
54 ASSERT_TRUE(t->GetBytes(&key, "Key"));
55 ASSERT_TRUE(t->GetBytes(&input, "Input"));
56 ASSERT_TRUE(t->GetBytes(&output, "Output"));
57 ASSERT_EQ(EVP_MD_size(digest), output.size());
58
59 // Test using the one-shot API.
60 auto mac = std::make_unique<uint8_t[]>(EVP_MD_size(digest));
61 unsigned mac_len;
62 ASSERT_TRUE(HMAC(digest, key.data(), key.size(), input.data(), input.size(),
63 mac.get(), &mac_len));
64 EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
65
66 // Test using HMAC_CTX.
67 bssl::ScopedHMAC_CTX ctx;
68 ASSERT_TRUE(
69 HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr));
70 ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size()));
71 ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
72 EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
73
74 // Test that an HMAC_CTX may be reset with the same key.
75 ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr));
76 ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size()));
77 ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
78 EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
79
80 // Test feeding the input in byte by byte.
81 ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr));
82 for (size_t i = 0; i < input.size(); i++) {
83 ASSERT_TRUE(HMAC_Update(ctx.get(), &input[i], 1));
84 }
85 ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len));
86 EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len));
87 });
88 }
89
RunWycheproofTest(const char * path,const EVP_MD * md)90 static void RunWycheproofTest(const char *path, const EVP_MD *md) {
91 SCOPED_TRACE(path);
92 FileTestGTest(path, [&](FileTest *t) {
93 t->IgnoreInstruction("keySize");
94 t->IgnoreInstruction("tagSize");
95 std::vector<uint8_t> key, msg, tag;
96 ASSERT_TRUE(t->GetBytes(&key, "key"));
97 ASSERT_TRUE(t->GetBytes(&msg, "msg"));
98 ASSERT_TRUE(t->GetBytes(&tag, "tag"));
99 WycheproofResult result;
100 ASSERT_TRUE(GetWycheproofResult(t, &result));
101
102 if (!result.IsValid()) {
103 // Wycheproof tests assume the HMAC implementation checks the MAC. Ours
104 // simply computes the HMAC, so skip the tests with invalid outputs.
105 return;
106 }
107
108 uint8_t out[EVP_MAX_MD_SIZE];
109 unsigned out_len;
110 ASSERT_TRUE(HMAC(md, key.data(), key.size(), msg.data(), msg.size(), out,
111 &out_len));
112 // Wycheproof tests truncate the tags down to |tagSize|.
113 ASSERT_LE(tag.size(), out_len);
114 EXPECT_EQ(Bytes(out, tag.size()), Bytes(tag));
115 });
116 }
117
TEST(HMACTest,WycheproofSHA1)118 TEST(HMACTest, WycheproofSHA1) {
119 RunWycheproofTest("third_party/wycheproof_testvectors/hmac_sha1_test.txt",
120 EVP_sha1());
121 }
122
TEST(HMACTest,WycheproofSHA224)123 TEST(HMACTest, WycheproofSHA224) {
124 RunWycheproofTest("third_party/wycheproof_testvectors/hmac_sha224_test.txt",
125 EVP_sha224());
126 }
127
TEST(HMACTest,WycheproofSHA256)128 TEST(HMACTest, WycheproofSHA256) {
129 RunWycheproofTest("third_party/wycheproof_testvectors/hmac_sha256_test.txt",
130 EVP_sha256());
131 }
132
TEST(HMACTest,WycheproofSHA384)133 TEST(HMACTest, WycheproofSHA384) {
134 RunWycheproofTest("third_party/wycheproof_testvectors/hmac_sha384_test.txt",
135 EVP_sha384());
136 }
137
TEST(HMACTest,WycheproofSHA512)138 TEST(HMACTest, WycheproofSHA512) {
139 RunWycheproofTest("third_party/wycheproof_testvectors/hmac_sha512_test.txt",
140 EVP_sha512());
141 }
142