summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Android.mk4
-rw-r--r--Makefile25
-rw-r--r--ecdsa_key.h75
-rw-r--r--google_keymaster_test_utils.cpp29
-rw-r--r--google_keymaster_test_utils.h1
-rw-r--r--hkdf.cpp91
-rw-r--r--hkdf.h55
-rw-r--r--hkdf_test.cpp96
-rw-r--r--hmac.cpp82
-rw-r--r--hmac.h60
-rw-r--r--hmac_test.cpp90
12 files changed, 534 insertions, 76 deletions
diff --git a/.gitignore b/.gitignore
index 6422747..cea2e31 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,5 @@
/trusty_keymaster_device_test
/abstract_factory_registry_test
/keymaster_enforcement_test
+/hmac_test
+/hkdf_test
diff --git a/Android.mk b/Android.mk
index 734fb79..216fe31 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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 \
diff --git a/Makefile b/Makefile
index ba07341..b5795b1 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/hkdf.h b/hkdf.h
new file mode 100644
index 0000000..b33b920
--- /dev/null
+++ b/hkdf.h
@@ -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
diff --git a/hmac.h b/hmac.h
new file mode 100644
index 0000000..09ae5e8
--- /dev/null
+++ b/hmac.h
@@ -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