// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include #include #include "utils.h" namespace crypto { namespace testing { namespace { bool TestInit(void) { BEGIN_TEST; size_t md_size; ASSERT_OK(digest::GetDigestLen(digest::kSHA256, &md_size)); Secret ikm; Bytes salt; ASSERT_OK(ikm.Generate(md_size)); ASSERT_OK(salt.Randomize(GUID_LEN)); // Bad version HKDF hkdf; EXPECT_ZX(hkdf.Init(digest::kUninitialized, ikm, salt), ZX_ERR_INVALID_ARGS); // Bad input key material ASSERT_OK(ikm.Generate(md_size - 1)); EXPECT_ZX(hkdf.Init(digest::kSHA256, ikm, salt), ZX_ERR_INVALID_ARGS); ASSERT_OK(ikm.Generate(md_size)); // Salt is optional ASSERT_OK(salt.Resize(0)); EXPECT_OK(hkdf.Init(digest::kSHA256, ikm, salt)); ASSERT_OK(salt.Randomize(GUID_LEN)); // Invalid flags EXPECT_ZX(hkdf.Init(digest::kSHA256, ikm, salt, 0x8000), ZX_ERR_INVALID_ARGS); // Valid EXPECT_OK(hkdf.Init(digest::kSHA256, ikm, salt)); END_TEST; } bool TestDerive(void) { BEGIN_TEST; size_t md_size; ASSERT_OK(digest::GetDigestLen(digest::kSHA256, &md_size)); HKDF hkdf; Secret ikm, key1, key2, key3; Bytes salt; ASSERT_OK(ikm.Generate(md_size)); ASSERT_OK(salt.Randomize(GUID_LEN)); // Uninitialized EXPECT_ZX(hkdf.Derive("init", md_size, &key1), ZX_ERR_INVALID_ARGS); ASSERT_OK(hkdf.Init(digest::kSHA256, ikm, salt)); // Label is optional EXPECT_OK(hkdf.Derive(nullptr, md_size, &key1)); EXPECT_OK(hkdf.Derive("", md_size, &key1)); // Same label, same key EXPECT_OK(hkdf.Derive("same", md_size, &key1)); EXPECT_OK(hkdf.Derive("same", md_size, &key2)); EXPECT_EQ(key1.len(), key2.len()); EXPECT_EQ(memcmp(key1.get(), key2.get(), key1.len()), 0); // Different label, different key. EXPECT_OK(hkdf.Derive("diff", md_size, &key3)); EXPECT_EQ(key1.len(), key3.len()); EXPECT_NE(memcmp(key1.get(), key3.get(), key1.len()), 0); END_TEST; } // Based on RFC 5869, Appendix A.2: Test with SHA-256 and longer inputs/outputs bool TestRfc5869_TC1(void) { BEGIN_TEST; HKDF hkdf; Secret ikm, okm; Bytes salt; uint8_t *buf; ASSERT_OK(ikm.Allocate(22, &buf)); memset(buf, 0xb, ikm.len()); ASSERT_OK(salt.Resize(13)); for (uint8_t i = 0; i < salt.len(); ++i) { salt[i] = i; } const char* info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"; uint8_t expected[42] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65, }; EXPECT_OK(hkdf.Init(digest::kSHA256, ikm, salt, HKDF::ALLOW_WEAK_KEY)); EXPECT_OK(hkdf.Derive(info, sizeof(expected), &okm)); EXPECT_EQ(memcmp(okm.get(), expected, sizeof(expected)), 0); END_TEST; } // Based on RFC 5869, Appendix A.2: Basic test case with SHA-256 bool TestRfc5869_TC2(void) { BEGIN_TEST; HKDF hkdf; Secret ikm, okm; Bytes salt; uint8_t *buf; ASSERT_OK(ikm.Allocate(80, &buf)); for (uint8_t i = 0; i < ikm.len(); ++i) { buf[i] = i; } ASSERT_OK(salt.Resize(80)); for (uint8_t i = 0; i < salt.len(); ++i) { salt[i] = static_cast(0x60 + i); } const char* info = "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; uint8_t expected[82] = { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87, }; EXPECT_OK(hkdf.Init(digest::kSHA256, ikm, salt)); EXPECT_OK(hkdf.Derive(info, sizeof(expected), &okm)); EXPECT_EQ(memcmp(okm.get(), expected, sizeof(expected)), 0); END_TEST; } // Based on RFC 5869, Appendix A.3: Test with SHA-256 and zero-length salt/info bool TestRfc5869_TC3(void) { BEGIN_TEST; HKDF hkdf; Secret ikm, okm; Bytes salt; uint8_t *buf; ASSERT_OK(ikm.Allocate(22, &buf)); memset(buf, 0xb, ikm.len()); const char* info = ""; uint8_t expected[42] = { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8, }; EXPECT_OK(hkdf.Init(digest::kSHA256, ikm, salt, HKDF::ALLOW_WEAK_KEY)); EXPECT_OK(hkdf.Derive(info, sizeof(expected), &okm)); EXPECT_EQ(memcmp(okm.get(), expected, sizeof(expected)), 0); END_TEST; } BEGIN_TEST_CASE(KdfTest) RUN_TEST(TestInit) RUN_TEST(TestDerive) RUN_TEST(TestRfc5869_TC1) RUN_TEST(TestRfc5869_TC2) RUN_TEST(TestRfc5869_TC3) END_TEST_CASE(KdfTest) } // namespace } // namespace testing } // namespace crypto