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