diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Android.mk | 4 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | ecdsa_key.h | 75 | ||||
-rw-r--r-- | google_keymaster_test_utils.cpp | 29 | ||||
-rw-r--r-- | google_keymaster_test_utils.h | 1 | ||||
-rw-r--r-- | hkdf.cpp | 91 | ||||
-rw-r--r-- | hkdf.h | 55 | ||||
-rw-r--r-- | hkdf_test.cpp | 96 | ||||
-rw-r--r-- | hmac.cpp | 82 | ||||
-rw-r--r-- | hmac.h | 60 | ||||
-rw-r--r-- | hmac_test.cpp | 90 |
12 files changed, 534 insertions, 76 deletions
@@ -14,3 +14,5 @@ /trusty_keymaster_device_test /abstract_factory_registry_test /keymaster_enforcement_test +/hmac_test +/hkdf_test @@ -51,6 +51,10 @@ LOCAL_SRC_FILES:= \ ec_key.cpp \ ecdsa_operation.cpp \ google_keymaster.cpp \ + google_keymaster_messages.cpp \ + google_keymaster_utils.cpp \ + hkdf.cpp \ + hmac.cpp \ hmac_key.cpp \ hmac_operation.cpp \ key.cpp \ @@ -44,6 +44,10 @@ CPPSRCS=\ google_keymaster_test.cpp \ google_keymaster_test_utils.cpp \ google_keymaster_utils.cpp \ + hkdf.cpp \ + hkdf_test.cpp \ + hmac.cpp \ + hmac_test.cpp \ hmac_key.cpp \ hmac_operation.cpp \ key.cpp \ @@ -72,8 +76,10 @@ BINARIES = abstract_factory_registry_test \ authorization_set_test \ google_keymaster_test \ google_keymaster_messages_test \ + hkdf_test \ + hmac_test \ key_blob_test \ - keymaster_enforcement_test + keymaster_enforcement_test \ .PHONY: coverage memcheck massif clean run @@ -118,6 +124,23 @@ memcheck: $(BINARIES:=.memcheck) massif: $(BINARIES:=.massif) +hmac_test: hmac_test.o \ + hmac.o \ + authorization_set.o \ + google_keymaster_test_utils.o \ + logger.o \ + serializable.o \ + $(GTEST)/src/gtest-all.o + +hkdf_test: hkdf_test.o \ + hkdf.o \ + hmac.o \ + authorization_set.o \ + logger.o \ + google_keymaster_test_utils.o \ + serializable.o \ + $(GTEST)/src/gtest-all.o + authorization_set_test: authorization_set_test.o \ authorization_set.o \ google_keymaster_test_utils.o \ diff --git a/ecdsa_key.h b/ecdsa_key.h deleted file mode 100644 index d688979..0000000 --- a/ecdsa_key.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SYSTEM_KEYMASTER_EDCSA_KEY_H_ -#define SYSTEM_KEYMASTER_EDCSA_KEY_H_ - -#include <openssl/ecdsa.h> - -#include "asymmetric_key.h" - -namespace keymaster { - -class EcdsaKeyFactory : public AsymmetricKeyFactory { - public: - virtual keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_ECDSA; } - - virtual Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error); - virtual Key* ImportKey(const AuthorizationSet& key_description, - keymaster_key_format_t key_format, const uint8_t* key_data, - size_t key_data_length, keymaster_error_t* error); - virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error); - virtual Key* RescopeKey(const UnencryptedKeyBlob& blob, - const AuthorizationSet& new_authorizations, keymaster_error_t* error); - - private: - static EC_GROUP* choose_group(size_t key_size_bits); - static keymaster_error_t get_group_size(const EC_GROUP& group, size_t* key_size_bits); - - struct EC_GROUP_Delete { - void operator()(EC_GROUP* p) { EC_GROUP_free(p); } - }; -}; - -class EcdsaSignOperationFactory; -class EcdsaVerifyOperationFactory; - -class EcdsaKey : public AsymmetricKey { - private: - friend EcdsaKeyFactory; - friend EcdsaSignOperationFactory; - friend EcdsaVerifyOperationFactory; - - EcdsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error); - EcdsaKey(EC_KEY* ecdsa_key, const AuthorizationSet auths) - : AsymmetricKey(auths), ecdsa_key_(ecdsa_key) {} - - virtual int evp_key_type() { return EVP_PKEY_EC; } - virtual bool InternalToEvp(EVP_PKEY* pkey) const; - virtual bool EvpToInternal(const EVP_PKEY* pkey); - - struct ECDSA_Delete { - void operator()(EC_KEY* p) { EC_KEY_free(p); } - }; - - EC_KEY* key() const { return EC_KEY_dup(ecdsa_key_.get()); } - - UniquePtr<EC_KEY, ECDSA_Delete> ecdsa_key_; -}; - -} // namespace keymaster - -#endif // SYSTEM_KEYMASTER_ECDSA_KEY_H_ diff --git a/google_keymaster_test_utils.cpp b/google_keymaster_test_utils.cpp index 0f5db5f..664e020 100644 --- a/google_keymaster_test_utils.cpp +++ b/google_keymaster_test_utils.cpp @@ -99,6 +99,35 @@ bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b) } } +static char hex_value[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +string hex2str(string a) { + string b; + size_t num = a.size()/2; + b.resize(num); + for (size_t i = 0; i < num; i++) { + b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]); + } + return b; +} + namespace keymaster { bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) { diff --git a/google_keymaster_test_utils.h b/google_keymaster_test_utils.h index c4856f3..97c90dc 100644 --- a/google_keymaster_test_utils.h +++ b/google_keymaster_test_utils.h @@ -37,6 +37,7 @@ std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param); bool operator==(const keymaster_key_param_t& a, const keymaster_key_param_t& b); +std::string hex2str(std::string); namespace keymaster { diff --git a/hkdf.cpp b/hkdf.cpp new file mode 100644 index 0000000..3f0de46 --- /dev/null +++ b/hkdf.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmac.h" +#include "hkdf.h" + +#include <assert.h> +#include <keymaster/logger.h> + +namespace keymaster { + +const size_t kSHA256HashLength = 32; + +Rfc5869HmacSha256Kdf::Rfc5869HmacSha256Kdf(Buffer& secret, Buffer& salt, Buffer& info, + size_t key_bytes_to_generate) { + Rfc5869HmacSha256Kdf(secret.peek_read(), secret.available_read(), salt.peek_read(), + salt.available_read(), info.peek_read(), info.available_read(), + key_bytes_to_generate); +} + +Rfc5869HmacSha256Kdf::Rfc5869HmacSha256Kdf(const uint8_t* secret, size_t secret_len, + const uint8_t* salt, size_t salt_len, + const uint8_t* info, size_t info_len, + size_t key_bytes_to_generate) { + // https://tools.ietf.org/html/rfc5869#section-2.2 + Buffer actual_salt; + if (salt) { + actual_salt.Reinitialize(salt, salt_len); + } else { + char zeros[kSHA256HashLength]; + // If salt is not given, HashLength zeros are used. + memset(zeros, 0, sizeof(zeros)); + actual_salt.Reinitialize(zeros, sizeof(zeros)); + } + + // Step 1. Extract: PRK = HMAC-SHA256(actual_salt, secret) + // https://tools.ietf.org/html/rfc5869#section-2.2 + HmacSha256 prk_hmac; + bool result = prk_hmac.Init(actual_salt); + assert(result); + + // |prk| is a pseudorandom key (of kSHA256HashLength octets). + uint8_t prk[kSHA256HashLength]; + assert(sizeof(prk) == prk_hmac.DigestLength()); + result = prk_hmac.Sign(secret, secret_len, prk, sizeof(prk)); + assert(result); + + // Step 2. Expand: OUTPUT = HKDF-Expand(PRK, info) + // https://tools.ietf.org/html/rfc5869#section-2.3 + const size_t n = (key_bytes_to_generate + kSHA256HashLength - 1) / kSHA256HashLength; + assert(n < 256u); + + output_.Reinitialize(n * kSHA256HashLength); + uint8_t buf[kSHA256HashLength + info_len + 1]; + uint8_t digest[kSHA256HashLength]; + Buffer previous; + + HmacSha256 hmac; + result = hmac.Init(prk, sizeof(prk)); + assert(result); + + for (size_t i = 1; i <= n; i++) { + memcpy(buf, previous.peek_read(), previous.available_read()); + size_t j = previous.available_read(); + memcpy(buf + j, info, info_len); + j += info_len; + buf[j++] = static_cast<uint8_t>(i); + result = hmac.Sign(buf, j, digest, sizeof(digest)); + assert(result); + output_.write(digest, sizeof(digest)); + previous.Reinitialize(reinterpret_cast<uint8_t*>(digest), sizeof(digest)); + } + + if (key_bytes_to_generate) + secret_key_.Reinitialize(output_.peek_read(), key_bytes_to_generate); +} + +} // namespace keymaster @@ -0,0 +1,55 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_HKDF_H_ +#define SYSTEM_KEYMASTER_HKDF_H_ + +#include <keymaster/serializable.h> + +namespace keymaster { + +// Rfc5869HmacSha256Kdf implements the key derivation function specified in RFC 5869 (using +// SHA256) and outputs key material, as needed by ECIES. +// See https://tools.ietf.org/html/rfc5869 for details. +class Rfc5869HmacSha256Kdf { + public: + // |secret|: the input shared secret (or, from RFC 5869, the IKM). + // |salt|: an (optional) public salt / non-secret random value. While + // optional, callers are strongly recommended to provide a salt. There is no + // added security value in making this larger than the SHA-256 block size of + // 64 bytes. + // |info|: an (optional) label to distinguish different uses of HKDF. It is + // optional context and application specific information (can be a zero-length + // string). + // |key_bytes_to_generate|: the number of bytes of key material to generate. + Rfc5869HmacSha256Kdf(Buffer& secret, Buffer& salt, Buffer& info, size_t key_bytes_to_generate); + + Rfc5869HmacSha256Kdf(const uint8_t* secret, size_t secret_len, const uint8_t* salt, + size_t salt_len, const uint8_t* info, size_t info_len, + size_t key_bytes_to_generate); + + void secret_key(Buffer* buf) const { + buf->Reinitialize(secret_key_.peek_read(), secret_key_.available_read()); + } + + private: + Buffer output_; + Buffer secret_key_; +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_HKDF_H_ diff --git a/hkdf_test.cpp b/hkdf_test.cpp new file mode 100644 index 0000000..789e08e --- /dev/null +++ b/hkdf_test.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hkdf.h" + +#include <gtest/gtest.h> +#include <string.h> + +#include "google_keymaster_test_utils.h" + +using std::string; + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} + +namespace keymaster { + +namespace test { + +struct HkdfTest { + const char* key_hex; + const char* salt_hex; + const char* info_hex; + const char* output_hex; +}; + +// These test cases are taken from +// https://tools.ietf.org/html/rfc5869#appendix-A. +static const HkdfTest kHkdfTests[] = { + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5" + "b887185865", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324" + "25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849" + "4a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384" + "85868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9" + "aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4" + "d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9" + "fafbfcfdfeff", + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99ca" + "c7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c" + "01d5c1f3434f1d87", + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "", "", + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395fa" + "a4b61a96c8", + }, +}; + +TEST(HkdfTest, Hkdf) { + for (size_t i = 0; i < 3; i++) { + const HkdfTest& test(kHkdfTests[i]); + const string key = hex2str(test.key_hex); + const string salt = hex2str(test.salt_hex); + const string info = hex2str(test.info_hex); + const string expected = hex2str(test.output_hex); + + // We set the key_length to the length of the expected output and then take + // the result. + Rfc5869HmacSha256Kdf hkdf(reinterpret_cast<const uint8_t*>(key.data()), key.size(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), + reinterpret_cast<const uint8_t*>(info.data()), info.size(), + expected.size()); + + Buffer secret_key; + hkdf.secret_key(&secret_key); + ASSERT_EQ(expected.size(), secret_key.available_read()); + EXPECT_EQ(0, memcmp(expected.data(), secret_key.peek_read(), expected.size())); + } +} + +} // namespace test +} // namespace keymaster diff --git a/hmac.cpp b/hmac.cpp new file mode 100644 index 0000000..0591236 --- /dev/null +++ b/hmac.cpp @@ -0,0 +1,82 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmac.h" + +#include <assert.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/sha.h> + +namespace keymaster { + +size_t HmacSha256::DigestLength() const { + return SHA256_DIGEST_LENGTH; +} + +bool HmacSha256::Init(const uint8_t* key, size_t key_len) { + if (!key) + return false; + + key_.Reinitialize(key, key_len); + return true; +} + +bool HmacSha256::Init(const Buffer& key) { + return Init(key.peek_read(), key.available_read()); +} + +bool HmacSha256::Sign(const Buffer& data, uint8_t* out_digest, size_t digest_len) const { + return Sign(data.peek_read(), data.available_read(), out_digest, digest_len); +} + +bool HmacSha256::Sign(const uint8_t* data, size_t data_len, uint8_t* out_digest, + size_t digest_len) const { + assert(digest_len); + + uint8_t tmp[SHA256_DIGEST_LENGTH]; + uint8_t* digest = tmp; + if (digest_len >= SHA256_DIGEST_LENGTH) + digest = out_digest; + + if (nullptr == ::HMAC(EVP_sha256(), key_.peek_read(), key_.available_read(), + data, data_len, digest, nullptr)) { + return false; + } + if (digest_len < SHA256_DIGEST_LENGTH) + memcpy(out_digest, tmp, digest_len); + + return true; +} + +bool HmacSha256::Verify(const Buffer& data, const Buffer& digest) const { + return Verify(data.peek_read(), data.available_read(), digest.peek_read(), + digest.available_read()); +} + +bool HmacSha256::Verify(const uint8_t* data, size_t data_len, const uint8_t* digest, + size_t digest_len) const { + if (digest_len != SHA256_DIGEST_LENGTH) + return false; + + uint8_t computed_digest[SHA256_DIGEST_LENGTH]; + if (!Sign(data, data_len, computed_digest, sizeof(computed_digest))) + return false; + + return 0 == CRYPTO_memcmp(digest, computed_digest, SHA256_DIGEST_LENGTH); +} + +} // namespace keymaster @@ -0,0 +1,60 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYSTEM_KEYMASTER_HMAC_H_ +#define SYSTEM_KEYMASTER_HMAC_H_ + +#include <keymaster/serializable.h> + +namespace keymaster { + + +// Only HMAC-SHA256 is supported. +class HmacSha256 { + public: + HmacSha256() {}; + + // DigestLength returns the length, in bytes, of the resulting digest. + size_t DigestLength() const; + + // Initializes this instance using |key|. Call Init only once. It returns + // false on the second of later calls. + bool Init(const uint8_t* key, size_t key_length); + bool Init(const Buffer& key); + + // Sign calculates the HMAC of |data| with the key supplied to the Init + // method. At most |digest_len| bytes of the resulting digest are written + // to |digest|. + bool Sign(const Buffer& data, uint8_t* digest, size_t digest_len) const; + bool Sign(const uint8_t* data, size_t data_len, uint8_t* digest, size_t digest_len) const; + + // Verify returns true if |digest| is a valid HMAC of |data| using the key + // supplied to Init. |digest| must be exactly |DigestLength()| bytes long. + // Use of this method is strongly recommended over using Sign() with a manual + // comparison (such as memcmp), as such comparisons may result in + // side-channel disclosures, such as timing, that undermine the cryptographic + // integrity. + bool Verify(const Buffer& data, const Buffer& digest) const; + bool Verify(const uint8_t* data, size_t data_len, const uint8_t* digest, + size_t digest_len) const; + + private: + Buffer key_; +}; + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_HMAC_H_ diff --git a/hmac_test.cpp b/hmac_test.cpp new file mode 100644 index 0000000..06f6377 --- /dev/null +++ b/hmac_test.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hmac.h" + +#include <gtest/gtest.h> +#include <string.h> + +#include "google_keymaster_test_utils.h" + +using std::string; + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} + +namespace keymaster { + +namespace test { + +struct HmacTest { + const char* data; + const char* key; + uint8_t digest[32]; +}; + +static const HmacTest kHmacTests[] = { + { + "Test Using Larger Than Block-Size Key - Hash Key First", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + { + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, + 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, + 0x0e, 0xe3, 0x7f, 0x54, + }, + }, + { + "The test message for the MD2, MD5, and SHA-1 hashing algorithms.", + "46697265666f7820616e64205468756e64657242697264206172652061776573" + "6f6d652100", + { + 0x05, 0x75, 0x9a, 0x9e, 0x70, 0x5e, 0xe7, 0x44, 0xe2, 0x46, 0x4b, 0x92, 0x22, 0x14, + 0x22, 0xe0, 0x1b, 0x92, 0x8a, 0x0c, 0xfe, 0xf5, 0x49, 0xe9, 0xa7, 0x1b, 0x56, 0x7d, + 0x1d, 0x29, 0x40, 0x48, + }, + }, +}; + +TEST(HmacTest, SHA256) { + for (size_t i = 0; i < 2; i++) { + const HmacTest& test(kHmacTests[i]); + + HmacSha256 hmac; + const string key = hex2str(test.key); + Buffer key_buffer(key.data(), key.size()); + ASSERT_TRUE(hmac.Init(key_buffer)); + + uint8_t digest_copy[sizeof(test.digest)]; + memcpy(digest_copy, test.digest, sizeof(test.digest)); + Buffer digest_buffer(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy)); + + Buffer data_buffer(test.data, strlen(test.data)); + EXPECT_TRUE(hmac.Verify(data_buffer, digest_buffer)); + + digest_copy[16] ^= 0x80; + digest_buffer.Reinitialize(reinterpret_cast<uint8_t*>(digest_copy), sizeof(digest_copy)); + EXPECT_FALSE(hmac.Verify(data_buffer, digest_buffer)); + } +} + +} // namespace test +} // namespace keymaster |