diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-09-29 16:16:15 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-11-09 10:04:06 +0000 |
commit | a95a7417ad456115a1ef2da4bb8320531c0821f1 (patch) | |
tree | edcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/third_party/nearby/src/internal/crypto | |
parent | 33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff) | |
download | qtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz |
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/nearby/src/internal/crypto')
46 files changed, 5829 insertions, 0 deletions
diff --git a/chromium/third_party/nearby/src/internal/crypto/BUILD b/chromium/third_party/nearby/src/internal/crypto/BUILD new file mode 100644 index 00000000000..00c85dd1cd5 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/BUILD @@ -0,0 +1,103 @@ +licenses(["notice"]) + +# Copyright 2020 Google LLC +# +# 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 +# +# https://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. +package(default_visibility = ["//third_party/nearby:__subpackages__"]) + +licenses(["notice"]) + +cc_library( + name = "crypto", + srcs = [ + "aead.cc", + "ec_private_key.cc", + "ec_signature_creator.cc", + "ec_signature_creator_impl.cc", + "encryptor.cc", + "hkdf.cc", + "hmac.cc", + "nearby_base.cc", + "openssl_util.cc", + "random.cc", + "rsa_private_key.cc", + "secure_hash.cc", + "secure_util.cc", + "sha2.cc", + "signature_verifier.cc", + "symmetric_key.cc", + ], + hdrs = [ + "aead.h", + "crypto_export.h", + "ec_private_key.h", + "ec_signature_creator.h", + "ec_signature_creator_impl.h", + "encryptor.h", + "hkdf.h", + "hmac.h", + "nearby_base.h", + "openssl_util.h", + "random.h", + "rsa_private_key.h", + "secure_hash.h", + "secure_util.h", + "sha2.h", + "signature_verifier.h", + "symmetric_key.h", + ], + copts = [ + "-DCRYPTO_IMPLEMENTATION", + "-Ithird_party", + ], + deps = [ + "//internal/platform:logging", + "@boringssl//:crypto", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "crypto_unittests", + size = "large", + srcs = [ + "aead_unittest.cc", + "ec_private_key_unittest.cc", + "ec_signature_creator_unittest.cc", + "encryptor_unittest.cc", + "hmac_unittest.cc", + "random_unittest.cc", + "rsa_private_key_unittest.cc", + "secure_hash_unittest.cc", + "sha2_unittest.cc", + "signature_verifier_unittest.cc", + "symmetric_key_unittest.cc", + ], + copts = [ + "-DUNIT_TEST", + "-Wno-inconsistent-missing-override", + "-Wno-non-virtual-dtor", + "-Ithird_party", + ], + deps = [ + ":crypto", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/chromium/third_party/nearby/src/internal/crypto/BUILD.gn b/chromium/third_party/nearby/src/internal/crypto/BUILD.gn new file mode 100644 index 00000000000..43925ec66bf --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/BUILD.gn @@ -0,0 +1,217 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/chromeos/ui_mode.gni") +import("//build/config/crypto.gni") +import("//testing/test.gni") + +component("crypto") { + output_name = "crcrypto" # Avoid colliding with OpenSSL's libcrypto. + sources = [ + "aead.cc", + "aead.h", + "crypto_export.h", + "ec_private_key.cc", + "ec_private_key.h", + "ec_signature_creator.cc", + "ec_signature_creator.h", + "ec_signature_creator_impl.cc", + "ec_signature_creator_impl.h", + "encryptor.cc", + "encryptor.h", + "hkdf.cc", + "hkdf.h", + "hmac.cc", + "hmac.h", + "openssl_util.cc", + "openssl_util.h", + "p224_spake.cc", + "p224_spake.h", + "random.cc", + "random.h", + "rsa_private_key.cc", + "rsa_private_key.h", + "scoped_capi_types.h", + "scoped_nss_types.h", + "secure_hash.cc", + "secure_hash.h", + "secure_util.cc", + "secure_util.h", + "sha2.cc", + "sha2.h", + "signature_creator.cc", + "signature_creator.h", + "signature_verifier.cc", + "signature_verifier.h", + "symmetric_key.cc", + "symmetric_key.h", + "unexportable_key.cc", + "unexportable_key.h", + ] + + deps = [ + ":platform", + "//base", + "//base/third_party/dynamic_annotations", + ] + + public_deps = [ "//third_party/boringssl" ] + + if (is_apple) { + sources += [ + "apple_keychain.h", + + # TODO(brettw): these mocks should be moved to a test_support_crypto + # target if possible. + "mock_apple_keychain.cc", + "mock_apple_keychain.h", + ] + + if (is_mac) { + sources += [ + "apple_keychain_mac.mm", + + # TODO(brettw): these mocks should be moved to a test_support_crypto + # target if possible. + "mock_apple_keychain_mac.cc", + ] + } + if (is_ios) { + sources += [ + "apple_keychain_ios.mm", + + # TODO(brettw): these mocks should be moved to a test_support_crypto + # target if possible. + "mock_apple_keychain_ios.cc", + ] + } + + frameworks = [ + "CoreFoundation.framework", + "Security.framework", + ] + } + + if (is_mac) { + sources += [ + "mac_security_services_lock.cc", + "mac_security_services_lock.h", + ] + } + if (is_win) { + sources += [ + "capi_util.cc", + "capi_util.h", + "unexportable_key_win.cc", + ] + libs = [ "ncrypt.lib" ] + } + + # Some files are built when NSS is used for the platform certificate library. + if (use_nss_certs) { + sources += [ + "nss_crypto_module_delegate.h", + "nss_key_util.cc", + "nss_key_util.h", + "nss_util.cc", + "nss_util.h", + "nss_util_internal.h", + ] + deps += [ "//build:chromeos_buildflags" ] + } + + if (is_chromeos_ash) { + sources += [ "nss_util_chromeos.cc" ] + } + + if (is_chromeos || is_chromeos_lacros) { + sources += [ + "chaps_support.cc", + "chaps_support.h", + ] + } + + defines = [ "CRYPTO_IMPLEMENTATION" ] +} + +test("crypto_unittests") { + sources = [ + "aead_unittest.cc", + "ec_private_key_unittest.cc", + "ec_signature_creator_unittest.cc", + "encryptor_unittest.cc", + "hmac_unittest.cc", + "p224_spake_unittest.cc", + "random_unittest.cc", + "rsa_private_key_unittest.cc", + "secure_hash_unittest.cc", + "sha2_unittest.cc", + "signature_creator_unittest.cc", + "signature_verifier_unittest.cc", + "symmetric_key_unittest.cc", + "unexportable_key_unittest.cc", + ] + + # Some files are built when NSS is used for the platform certificate library. + if (use_nss_certs) { + sources += [ + "nss_key_util_unittest.cc", + "nss_util_unittest.cc", + ] + } + + deps = [ + ":crypto", + ":platform", + ":test_support", + "//base", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//testing/gmock", + "//testing/gtest", + ] +} + +static_library("test_support") { + testonly = true + sources = [ + "scoped_mock_unexportable_key_provider.cc", + "scoped_mock_unexportable_key_provider.h", + ] + + if (use_nss_certs) { + sources += [ + "scoped_test_nss_db.cc", + "scoped_test_nss_db.h", + ] + } + + if (is_chromeos_ash) { + sources += [ + "scoped_test_nss_chromeos_user.cc", + "scoped_test_nss_chromeos_user.h", + "scoped_test_system_nss_key_slot.cc", + "scoped_test_system_nss_key_slot.h", + ] + } + + deps = [ + ":crypto", + ":platform", + "//base", + ] +} + +# This is a meta-target that forwards to NSS's SSL library or OpenSSL, +# according to the state of the crypto flags. A target just wanting to depend +# on the current SSL library should just depend on this. +group("platform") { + public_deps = [ "//third_party/boringssl" ] + + # Link in NSS if it is used for the platform certificate library + # (use_nss_certs). + if (use_nss_certs) { + public_configs = [ "//build/config/linux/nss:system_nss_no_ssl_config" ] + } +} diff --git a/chromium/third_party/nearby/src/internal/crypto/aead.cc b/chromium/third_party/nearby/src/internal/crypto/aead.cc new file mode 100644 index 00000000000..db1b080bbee --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/aead.cc @@ -0,0 +1,182 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/aead.h" + +#include <stddef.h> +#include <stdint.h> + +#include <optional> +#include <string> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/openssl_util.h" +#include <openssl/aes.h> +#include <openssl/evp.h> + +namespace crypto { + +Aead::Aead(AeadAlgorithm algorithm) { + EnsureOpenSSLInit(); + switch (algorithm) { + case AES_128_CTR_HMAC_SHA256: + aead_ = EVP_aead_aes_128_ctr_hmac_sha256(); + break; + case AES_256_GCM: + aead_ = EVP_aead_aes_256_gcm(); + break; + case AES_256_GCM_SIV: + aead_ = EVP_aead_aes_256_gcm_siv(); + break; + case CHACHA20_POLY1305: + aead_ = EVP_aead_chacha20_poly1305(); + break; + } +} + +Aead::~Aead() = default; + +void Aead::Init(absl::Span<const uint8_t> key) { + DCHECK(!key_); + DCHECK_EQ(KeyLength(), key.size()); + key_ = key; +} + +static absl::Span<const uint8_t> ToSpan(absl::string_view sp) { + return nearbybase::as_bytes(absl::MakeSpan(sp)); +} + +void Aead::Init(const std::string* key) { Init(ToSpan(*key)); } + +std::vector<uint8_t> Aead::Seal( + absl::Span<const uint8_t> plaintext, absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data) const { + const size_t max_output_length = + EVP_AEAD_max_overhead(aead_) + plaintext.size(); + CHECK(max_output_length >= plaintext.size()); + std::vector<uint8_t> ret; + ret.resize(max_output_length); + + size_t output_length; + CHECK(Seal(plaintext, nonce, additional_data, ret.data(), &output_length, + max_output_length)); + ret.resize(output_length); + return ret; +} + +bool Aead::Seal(absl::string_view plaintext, absl::string_view nonce, + absl::string_view additional_data, + std::string* ciphertext) const { + const size_t max_output_length = + EVP_AEAD_max_overhead(aead_) + plaintext.size(); + CHECK(max_output_length + 1 >= plaintext.size()); + uint8_t* out_ptr = reinterpret_cast<uint8_t*>( + nearbybase::WriteInto(ciphertext, max_output_length + 1)); + + size_t output_length; + if (!Seal(ToSpan(plaintext), ToSpan(nonce), ToSpan(additional_data), out_ptr, + &output_length, max_output_length)) { + ciphertext->clear(); + return false; + } + + ciphertext->resize(output_length); + return true; +} + +absl::optional<std::vector<uint8_t>> Aead::Open( + absl::Span<const uint8_t> ciphertext, absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data) const { + const size_t max_output_length = ciphertext.size(); + std::vector<uint8_t> ret; + ret.resize(max_output_length); + + size_t output_length; + if (!Open(ciphertext, nonce, additional_data, ret.data(), &output_length, + max_output_length)) { + return absl::nullopt; + } + + ret.resize(output_length); + return ret; +} + +bool Aead::Open(absl::string_view ciphertext, absl::string_view nonce, + absl::string_view additional_data, + std::string* plaintext) const { + const size_t max_output_length = ciphertext.size(); + CHECK(max_output_length + 1 > max_output_length); + uint8_t* out_ptr = reinterpret_cast<uint8_t*>( + nearbybase::WriteInto(plaintext, max_output_length + 1)); + + size_t output_length; + if (!Open(ToSpan(ciphertext), ToSpan(nonce), ToSpan(additional_data), out_ptr, + &output_length, max_output_length)) { + plaintext->clear(); + return false; + } + + plaintext->resize(output_length); + return true; +} + +size_t Aead::KeyLength() const { return EVP_AEAD_key_length(aead_); } + +size_t Aead::NonceLength() const { return EVP_AEAD_nonce_length(aead_); } + +bool Aead::Seal(absl::Span<const uint8_t> plaintext, + absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data, uint8_t* out, + size_t* output_length, size_t max_output_length) const { + DCHECK(key_); + DCHECK_EQ(NonceLength(), nonce.size()); + bssl::ScopedEVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(), + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) || + !EVP_AEAD_CTX_seal(ctx.get(), out, output_length, max_output_length, + nonce.data(), nonce.size(), plaintext.data(), + plaintext.size(), additional_data.data(), + additional_data.size())) { + return false; + } + + DCHECK_LE(*output_length, max_output_length); + return true; +} + +bool Aead::Open(absl::Span<const uint8_t> plaintext, + absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data, uint8_t* out, + size_t* output_length, size_t max_output_length) const { + DCHECK(key_); + DCHECK_EQ(NonceLength(), nonce.size()); + bssl::ScopedEVP_AEAD_CTX ctx; + + if (!EVP_AEAD_CTX_init(ctx.get(), aead_, key_->data(), key_->size(), + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) || + !EVP_AEAD_CTX_open(ctx.get(), out, output_length, max_output_length, + nonce.data(), nonce.size(), plaintext.data(), + plaintext.size(), additional_data.data(), + additional_data.size())) { + return false; + } + + DCHECK_LE(*output_length, max_output_length); + return true; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/aead.h b/chromium/third_party/nearby/src/internal/crypto/aead.h new file mode 100644 index 00000000000..053f3085674 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/aead.h @@ -0,0 +1,95 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_AEAD_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_AEAD_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <optional> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +struct evp_aead_st; + +namespace crypto { + +// This class exposes the AES-128-CTR-HMAC-SHA256 and AES_256_GCM AEAD. Note +// that there are two versions of most methods: an historical version based +// around |StringPiece| and a more modern version that takes |absl::Span|. +// Prefer the latter in new code. +class CRYPTO_EXPORT Aead { + public: + enum AeadAlgorithm { + AES_128_CTR_HMAC_SHA256, + AES_256_GCM, + AES_256_GCM_SIV, + CHACHA20_POLY1305 + }; + + explicit Aead(AeadAlgorithm algorithm); + Aead(const Aead&) = delete; + Aead& operator=(const Aead&) = delete; + ~Aead(); + + // Note that Init keeps a reference to the data pointed to by |key| thus that + // data must outlive this object. + void Init(absl::Span<const uint8_t> key); + + // Note that Init keeps a reference to the data pointed to by |key| thus that + // data must outlive this object. + void Init(const std::string* key); + + std::vector<uint8_t> Seal(absl::Span<const uint8_t> plaintext, + absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data) const; + + bool Seal(absl::string_view plaintext, absl::string_view nonce, + absl::string_view additional_data, std::string* ciphertext) const; + + absl::optional<std::vector<uint8_t>> Open( + absl::Span<const uint8_t> ciphertext, absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data) const; + + bool Open(absl::string_view ciphertext, absl::string_view nonce, + absl::string_view additional_data, std::string* plaintext) const; + + size_t KeyLength() const; + + size_t NonceLength() const; + + private: + bool Seal(absl::Span<const uint8_t> plaintext, + absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data, uint8_t* out, + size_t* output_length, size_t max_output_length) const; + + bool Open(absl::Span<const uint8_t> ciphertext, + absl::Span<const uint8_t> nonce, + absl::Span<const uint8_t> additional_data, uint8_t* out, + size_t* output_length, size_t max_output_length) const; + + absl::optional<absl::Span<const uint8_t>> key_; + const evp_aead_st* aead_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_AEAD_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/aead_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/aead_unittest.cc new file mode 100644 index 00000000000..8f920818aa0 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/aead_unittest.cc @@ -0,0 +1,100 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/aead.h" + +#include <optional> +#include <string> +#include <vector> + +#include "gtest/gtest.h" + +namespace { + +const crypto::Aead::AeadAlgorithm kAllAlgorithms[]{ + crypto::Aead::AES_128_CTR_HMAC_SHA256, + crypto::Aead::AES_256_GCM, + crypto::Aead::AES_256_GCM_SIV, + crypto::Aead::CHACHA20_POLY1305, +}; + +class AeadTest : public testing::TestWithParam<crypto::Aead::AeadAlgorithm> {}; + +INSTANTIATE_TEST_SUITE_P(All, AeadTest, testing::ValuesIn(kAllAlgorithms)); + +TEST_P(AeadTest, SealOpen) { + crypto::Aead::AeadAlgorithm alg = GetParam(); + crypto::Aead aead(alg); + std::string key(aead.KeyLength(), 0); + aead.Init(&key); + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_TRUE(aead.Open(ciphertext, nonce, ad, &decrypted)); + + EXPECT_EQ(plaintext, decrypted); +} + +TEST_P(AeadTest, SealOpenSpan) { + crypto::Aead::AeadAlgorithm alg = GetParam(); + crypto::Aead aead(alg); + std::vector<uint8_t> key(aead.KeyLength(), 0u); + aead.Init(key); + std::vector<uint8_t> nonce(aead.NonceLength(), 0u); + static constexpr uint8_t kPlaintext[] = "plaintext"; + static constexpr uint8_t kAdditionalData[] = "additional data input"; + std::vector<uint8_t> ciphertext = + aead.Seal(kPlaintext, nonce, kAdditionalData); + EXPECT_LT(sizeof(kPlaintext), ciphertext.size()); + + absl::optional<std::vector<uint8_t>> decrypted = + aead.Open(ciphertext, nonce, kAdditionalData); + ASSERT_TRUE(decrypted); + ASSERT_EQ(decrypted->size(), sizeof(kPlaintext)); + ASSERT_EQ(0, memcmp(decrypted->data(), kPlaintext, sizeof(kPlaintext))); + + std::vector<uint8_t> wrong_key(aead.KeyLength(), 1u); + crypto::Aead aead_wrong_key(alg); + aead_wrong_key.Init(wrong_key); + decrypted = aead_wrong_key.Open(ciphertext, nonce, kAdditionalData); + EXPECT_FALSE(decrypted); +} + +TEST_P(AeadTest, SealOpenWrongKey) { + crypto::Aead::AeadAlgorithm alg = GetParam(); + crypto::Aead aead(alg); + std::string key(aead.KeyLength(), 0); + std::string wrong_key(aead.KeyLength(), 1); + aead.Init(&key); + crypto::Aead aead_wrong_key(alg); + aead_wrong_key.Init(&wrong_key); + + std::string nonce(aead.NonceLength(), 0); + std::string plaintext("this is the plaintext"); + std::string ad("this is the additional data"); + std::string ciphertext; + EXPECT_TRUE(aead.Seal(plaintext, nonce, ad, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_FALSE(aead_wrong_key.Open(ciphertext, nonce, ad, &decrypted)); + EXPECT_EQ(0U, decrypted.size()); +} + +} // namespace diff --git a/chromium/third_party/nearby/src/internal/crypto/crypto_export.h b/chromium/third_party/nearby/src/internal/crypto/crypto_export.h new file mode 100644 index 00000000000..91caabfe868 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/crypto_export.h @@ -0,0 +1,42 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_CRYPTO_EXPORT_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_CRYPTO_EXPORT_H_ + +// Defines CRYPTO_EXPORT so that functionality implemented by the crypto module +// can be exported to consumers. + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(CRYPTO_IMPLEMENTATION) +#define CRYPTO_EXPORT __declspec(dllexport) +#else +#define CRYPTO_EXPORT __declspec(dllimport) +#endif // defined(CRYPTO_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(CRYPTO_IMPLEMENTATION) +#define CRYPTO_EXPORT __attribute__((visibility("default"))) +#else +#define CRYPTO_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define CRYPTO_EXPORT +#endif + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_CRYPTO_EXPORT_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_private_key.cc b/chromium/third_party/nearby/src/internal/crypto/ec_private_key.cc new file mode 100644 index 00000000000..fd2fd1a48c1 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_private_key.cc @@ -0,0 +1,182 @@ +#include "internal/crypto/ec_private_key.h" + +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 <stddef.h> +#include <stdint.h> + +#include <array> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "internal/crypto/openssl_util.h" +#include "internal/platform/logging.h" +#include <openssl/bn.h> +#include <openssl/bytestring.h> +#include <openssl/ec.h> +#include <openssl/ec_key.h> +#include <openssl/evp.h> +#include <openssl/mem.h> +#include <openssl/pkcs8.h> + +namespace crypto { + +ECPrivateKey::~ECPrivateKey() = default; + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::Create() { + OpenSSLErrStackTracer err_tracer; + + bssl::UniquePtr<EC_KEY> ec_key( + EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (!ec_key || !EC_KEY_generate_key(ec_key.get())) return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_.reset(EVP_PKEY_new()); + if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_.get(), ec_key.get())) + return nullptr; + + CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_id(result->key_.get())); + return result; +} + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromPrivateKeyInfo( + absl::Span<const uint8_t> input) { + OpenSSLErrStackTracer err_tracer; + + CBS cbs; + CBS_init(&cbs, input.data(), input.size()); + bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs)); + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC) + return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_ = std::move(pkey); + return result; +} + +// static +std::unique_ptr<ECPrivateKey> ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + absl::Span<const uint8_t> encrypted_private_key_info) { + OpenSSLErrStackTracer err_tracer; + + CBS cbs; + CBS_init(&cbs, encrypted_private_key_info.data(), + encrypted_private_key_info.size()); + bssl::UniquePtr<EVP_PKEY> pkey( + PKCS8_parse_encrypted_private_key(&cbs, "", 0)); + + // Hack for reading keys generated by an older version of the OpenSSL code. + // Some implementations encode the empty password as "\0\0" (passwords are + // normally encoded in big-endian UCS-2 with a NUL terminator) and some + // encode as the empty string. PKCS8_parse_encrypted_private_key + // distinguishes the two by whether the password is nullptr. + if (!pkey) { + CBS_init(&cbs, encrypted_private_key_info.data(), + encrypted_private_key_info.size()); + pkey.reset(PKCS8_parse_encrypted_private_key(&cbs, nullptr, 0)); + } + + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC) + return nullptr; + + std::unique_ptr<ECPrivateKey> result(new ECPrivateKey()); + result->key_ = std::move(pkey); + return result; +} + +std::unique_ptr<ECPrivateKey> ECPrivateKey::Copy() const { + std::unique_ptr<ECPrivateKey> copy(new ECPrivateKey()); + copy->key_ = bssl::UpRef(key_); + return copy; +} + +bool ECPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer; + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_private_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportEncryptedPrivateKey( + std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer; + + // Encrypt the object. + // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC + // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL + // equivalent. + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !PKCS8_marshal_encrypted_private_key( + cbb.get(), NID_pbe_WithSHA1And3_Key_TripleDES_CBC, + nullptr /* cipher */, nullptr /* no password */, 0 /* pass_len */, + nullptr /* salt */, 0 /* salt_len */, 1 /* iterations */, + key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer; + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_public_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool ECPrivateKey::ExportRawPublicKey(std::string* output) const { + OpenSSLErrStackTracer err_tracer; + + std::array<uint8_t, 65> buf; + EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key_.get()); + if (!EC_POINT_point2oct(EC_KEY_get0_group(ec_key), + EC_KEY_get0_public_key(ec_key), + POINT_CONVERSION_UNCOMPRESSED, buf.data(), buf.size(), + /*ctx=*/nullptr)) { + return false; + } + + output->assign(buf.begin(), buf.end()); + return true; +} + +ECPrivateKey::ECPrivateKey() = default; + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_private_key.h b/chromium/third_party/nearby/src/internal/crypto/ec_private_key.h new file mode 100644 index 00000000000..56f512b9ad8 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_private_key.h @@ -0,0 +1,96 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_PRIVATE_KEY_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_PRIVATE_KEY_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" +#include <openssl/base.h> + +namespace crypto { + +// Encapsulates an elliptic curve (EC) private key. Can be used to generate new +// keys, export keys to other formats, or to extract a public key. +// TODO(mattm): make this and RSAPrivateKey implement some PrivateKey interface. +// (The difference in types of key() and public_key() make this a little +// tricky.) +class CRYPTO_EXPORT ECPrivateKey { + public: + ECPrivateKey(const ECPrivateKey&) = delete; + ECPrivateKey& operator=(const ECPrivateKey&) = delete; + + ~ECPrivateKey(); + + // Creates a new random instance. Can return nullptr if initialization fails. + // The created key will use the NIST P-256 curve. + // TODO(mattm): Add a curve parameter. + static std::unique_ptr<ECPrivateKey> Create(); + + // Create a new instance by importing an existing private key. The format is + // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return + // nullptr if initialization fails. + static std::unique_ptr<ECPrivateKey> CreateFromPrivateKeyInfo( + absl::Span<const uint8_t> input); + + // Creates a new instance by importing an existing key pair. + // The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo + // block with empty password and an X.509 SubjectPublicKeyInfo block. + // Returns nullptr if initialization fails. + // + // This function is deprecated. Use CreateFromPrivateKeyInfo for new code. + // See https://crbug.com/603319. + static std::unique_ptr<ECPrivateKey> CreateFromEncryptedPrivateKeyInfo( + absl::Span<const uint8_t> encrypted_private_key_info); + + // Returns a copy of the object. + std::unique_ptr<ECPrivateKey> Copy() const; + + EVP_PKEY* key() { return key_.get(); } + + // Exports the private key to a PKCS #8 PrivateKeyInfo block. + bool ExportPrivateKey(std::vector<uint8_t>* output) const; + + // Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo + // block wth empty password. This was historically used as a workaround for + // NSS API deficiencies and does not provide security. + // + // This function is deprecated. Use ExportPrivateKey for new code. See + // https://crbug.com/603319. + bool ExportEncryptedPrivateKey(std::vector<uint8_t>* output) const; + + // Exports the public key to an X.509 SubjectPublicKeyInfo block. + bool ExportPublicKey(std::vector<uint8_t>* output) const; + + // Exports the public key as an EC point in X9.62 uncompressed form. Note this + // includes the leading 0x04 byte. + bool ExportRawPublicKey(std::string* output) const; + + private: + // Constructor is private. Use one of the Create*() methods above instead. + ECPrivateKey(); + + bssl::UniquePtr<EVP_PKEY> key_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_PRIVATE_KEY_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_private_key_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/ec_private_key_unittest.cc new file mode 100644 index 00000000000..6f4887257db --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_private_key_unittest.cc @@ -0,0 +1,333 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/ec_private_key.h" + +#include <stdint.h> + +#include <array> +#include <memory> +#include <string> +#include <vector> + +#include "gtest/gtest.h" + +namespace { + +void ExpectKeysEqual(const crypto::ECPrivateKey* keypair1, + const crypto::ECPrivateKey* keypair2) { + std::vector<uint8_t> privkey1; + std::vector<uint8_t> privkey2; + EXPECT_TRUE(keypair1->ExportPrivateKey(&privkey1)); + EXPECT_TRUE(keypair2->ExportPrivateKey(&privkey2)); + EXPECT_EQ(privkey1, privkey2); + + std::vector<uint8_t> pubkey1; + std::vector<uint8_t> pubkey2; + EXPECT_TRUE(keypair1->ExportPublicKey(&pubkey1)); + EXPECT_TRUE(keypair2->ExportPublicKey(&pubkey2)); + EXPECT_EQ(pubkey1, pubkey2); + + std::string raw_pubkey1; + std::string raw_pubkey2; + EXPECT_TRUE(keypair1->ExportRawPublicKey(&raw_pubkey1)); + EXPECT_TRUE(keypair2->ExportRawPublicKey(&raw_pubkey2)); + EXPECT_EQ(raw_pubkey1, raw_pubkey2); +} + +} // namespace + +// Generate random private keys. Export, then re-import in several ways. We +// should get back the same exact public key, and the private key should have +// the same value and elliptic curve params. +TEST(ECPrivateKeyUnitTest, InitRandomTest) { + std::unique_ptr<crypto::ECPrivateKey> keypair(crypto::ECPrivateKey::Create()); + ASSERT_TRUE(keypair); + + // Re-import as a PrivateKeyInfo. + std::vector<uint8_t> privkey; + EXPECT_TRUE(keypair->ExportPrivateKey(&privkey)); + std::unique_ptr<crypto::ECPrivateKey> keypair_copy = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(privkey); + ASSERT_TRUE(keypair_copy); + ExpectKeysEqual(keypair.get(), keypair_copy.get()); + + // Re-import as an EncryptedPrivateKeyInfo with kPassword1. + std::vector<uint8_t> encrypted_privkey; + EXPECT_TRUE(keypair->ExportEncryptedPrivateKey(&encrypted_privkey)); + keypair_copy = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + encrypted_privkey); + ASSERT_TRUE(keypair_copy); + ExpectKeysEqual(keypair.get(), keypair_copy.get()); +} + +TEST(ECPrivateKeyUnitTest, Copy) { + std::unique_ptr<crypto::ECPrivateKey> keypair1( + crypto::ECPrivateKey::Create()); + std::unique_ptr<crypto::ECPrivateKey> keypair2(keypair1->Copy()); + ASSERT_TRUE(keypair1); + ASSERT_TRUE(keypair2); + + ExpectKeysEqual(keypair1.get(), keypair2.get()); +} + +TEST(ECPrivateKeyUnitTest, CreateFromPrivateKeyInfo) { + static const uint8_t kPrivateKeyInfo[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x07, 0x0f, 0x08, 0x72, 0x7a, 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, + 0x4d, 0x89, 0x68, 0x77, 0x08, 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, + 0xe8, 0xd1, 0xc9, 0xce, 0x0a, 0x8b, 0xb4, 0x6a, 0xa1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, + 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, + 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, + 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, + 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, + 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + static const uint8_t kSubjectPublicKeyInfo[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, + 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, + 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, + 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, + 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, + 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + static const uint8_t kRawPublicKey[] = { + 0x04, 0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, + 0x1e, 0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, + 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a, + 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3, + 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5, + 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1, + }; + + std::unique_ptr<crypto::ECPrivateKey> key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(std::vector<uint8_t>( + std::begin(kPrivateKeyInfo), std::end(kPrivateKeyInfo))); + ASSERT_TRUE(key); + + std::vector<uint8_t> public_key; + ASSERT_TRUE(key->ExportPublicKey(&public_key)); + EXPECT_EQ(std::vector<uint8_t>(std::begin(kSubjectPublicKeyInfo), + std::end(kSubjectPublicKeyInfo)), + public_key); + + std::string raw_public_key; + ASSERT_TRUE(key->ExportRawPublicKey(&raw_public_key)); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kRawPublicKey), + sizeof(kRawPublicKey)), + raw_public_key); +} + +TEST(ECPrivateKeyUnitTest, RSAPrivateKeyInfo) { + static const uint8_t kPrivateKeyInfo[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, + 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a, + 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, + 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a, + 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, + 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57, + 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, + 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3, + 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, + 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83, + 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98, + 0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7, + 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b, + 0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6, + 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe, + 0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b, + 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c, + 0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38, + 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b, + 0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e, + 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f, + 0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c, + 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38, + 0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89, + 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea, + 0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2, + 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0, + 0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72, + 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31, + 0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c, + 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf, + 0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b, + 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca, + 0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda, + 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74, + 0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae, + 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba, + 0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41, + 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb, + 0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0, + 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09, + 0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69, + 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6, + 0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f, + 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf, + 0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6, + 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1, + 0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca, + 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3, + }; + + std::unique_ptr<crypto::ECPrivateKey> key = + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(std::vector<uint8_t>( + std::begin(kPrivateKeyInfo), std::end(kPrivateKeyInfo))); + EXPECT_FALSE(key); +} + +TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) { + static const uint8_t kNSSKey[] = { + 0x30, 0x81, 0xb8, 0x30, 0x23, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x15, 0x04, 0x10, 0x3f, 0xac, 0xe9, + 0x38, 0xdb, 0x40, 0x6b, 0x26, 0x89, 0x09, 0x73, 0x18, 0x8d, 0x7f, 0x1c, + 0x82, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0x5e, 0x5e, 0x11, 0xef, 0xbb, + 0x7c, 0x4d, 0xec, 0xc0, 0xdc, 0xc7, 0x23, 0xd2, 0xc4, 0x77, 0xbc, 0xf4, + 0x5d, 0x59, 0x4c, 0x07, 0xc2, 0x8a, 0x26, 0xfa, 0x25, 0x1c, 0xaa, 0x42, + 0xed, 0xd0, 0xed, 0xbb, 0x5c, 0xe9, 0x13, 0x07, 0xaa, 0xdd, 0x52, 0x3c, + 0x65, 0x25, 0xbf, 0x94, 0x02, 0xaf, 0xd6, 0x97, 0xe9, 0x33, 0x00, 0x76, + 0x64, 0x4a, 0x73, 0xab, 0xfb, 0x99, 0x6e, 0x83, 0x12, 0x05, 0x86, 0x72, + 0x6c, 0xd5, 0xa4, 0xcf, 0xb1, 0xd5, 0x4d, 0x54, 0x87, 0x8b, 0x4b, 0x95, + 0x1d, 0xcd, 0xf3, 0xfe, 0xa8, 0xda, 0xe0, 0xb6, 0x72, 0x13, 0x3f, 0x2e, + 0x66, 0xe0, 0xb9, 0x2e, 0xfa, 0x69, 0x40, 0xbe, 0xd7, 0x67, 0x6e, 0x53, + 0x2b, 0x3f, 0x53, 0xe5, 0x39, 0x54, 0x77, 0xe1, 0x1d, 0xe6, 0x81, 0x92, + 0x58, 0x82, 0x14, 0xfb, 0x47, 0x85, 0x3c, 0xc3, 0xdf, 0xdd, 0xcc, 0x79, + 0x9f, 0x41, 0x83, 0x72, 0xf2, 0x0a, 0xe9, 0xe1, 0x2c, 0x12, 0xb0, 0xb0, + 0x0a, 0xb2, 0x1d, 0xca, 0x15, 0xb2, 0xca, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_nss( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kNSSKey), std::end(kNSSKey)))); + + EXPECT_TRUE(keypair_nss); +} + +TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) { + static const uint8_t kOpenSSLKey[] = { + 0x30, 0x81, 0xb0, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0xb2, 0xfe, 0x68, + 0xc2, 0xea, 0x0f, 0x10, 0x9c, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0xe2, + 0xf6, 0x1c, 0xca, 0xad, 0x64, 0x30, 0xbf, 0x88, 0x04, 0x35, 0xe5, 0x0f, + 0x11, 0x49, 0x06, 0x01, 0x14, 0x33, 0x80, 0xa2, 0x78, 0x44, 0x5b, 0xaa, + 0x0d, 0xd7, 0x00, 0x36, 0x9d, 0x91, 0x97, 0x37, 0x20, 0x7b, 0x27, 0xc1, + 0xa0, 0xa2, 0x73, 0x06, 0x15, 0xdf, 0xc8, 0x13, 0x9b, 0xc9, 0x8c, 0x9c, + 0xce, 0x00, 0xd0, 0xc8, 0x42, 0xc1, 0xda, 0x2b, 0x07, 0x2b, 0x12, 0xa3, + 0xce, 0x10, 0x39, 0x7a, 0xf1, 0x55, 0x69, 0x8d, 0xa5, 0xc4, 0x2a, 0x00, + 0x0d, 0x94, 0xc6, 0xde, 0x6a, 0x3d, 0xb7, 0xe5, 0x6d, 0x59, 0x3e, 0x09, + 0xb5, 0xe3, 0x3e, 0xfc, 0x50, 0x56, 0xe9, 0x50, 0x42, 0x7c, 0xe7, 0xf0, + 0x19, 0xbd, 0x31, 0xa7, 0x85, 0x47, 0xb3, 0xe9, 0xb3, 0x50, 0x3c, 0xc9, + 0x32, 0x37, 0x1a, 0x93, 0x78, 0x48, 0x78, 0x82, 0xde, 0xad, 0x5c, 0xf2, + 0xcf, 0xf2, 0xbb, 0x2c, 0x44, 0x05, 0x7f, 0x4a, 0xf9, 0xb1, 0x2b, 0xdd, + 0x49, 0xf6, 0x7e, 0xd0, 0x42, 0xaa, 0x14, 0x3c, 0x24, 0x77, 0xb4, + }; + static const uint8_t kOpenSSLPublicKey[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, + 0x67, 0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, + 0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, 0x50, + 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, 0xfb, 0x33, + 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, 0xc5, 0xaa, 0x44, + 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, + }; + static const uint8_t kOpenSSLRawPublicKey[] = { + 0x04, 0xb9, 0xda, 0x0d, 0x71, 0x60, 0xb3, 0x63, 0x28, 0x22, 0x67, + 0xe7, 0xe0, 0xa3, 0xf8, 0x00, 0x8e, 0x4c, 0x89, 0xed, 0x31, 0x34, + 0xf6, 0xdb, 0xc4, 0xfe, 0x0b, 0x5d, 0xe1, 0x11, 0x39, 0x49, 0xa6, + 0x50, 0xa8, 0xe3, 0x4a, 0xc0, 0x40, 0x88, 0xb8, 0x38, 0x3f, 0x56, + 0xfb, 0x33, 0x8d, 0xd4, 0x64, 0x91, 0xd6, 0x15, 0x77, 0x42, 0x27, + 0xc5, 0xaa, 0x44, 0xff, 0xab, 0x4d, 0xb5, 0x7e, 0x25, 0x3d, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_openssl( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kOpenSSLKey), + std::end(kOpenSSLKey)))); + + EXPECT_TRUE(keypair_openssl); + + std::vector<uint8_t> public_key; + EXPECT_TRUE(keypair_openssl->ExportPublicKey(&public_key)); + EXPECT_EQ(std::vector<uint8_t>(std::begin(kOpenSSLPublicKey), + std::end(kOpenSSLPublicKey)), + public_key); + + std::string raw_public_key; + EXPECT_TRUE(keypair_openssl->ExportRawPublicKey(&raw_public_key)); + EXPECT_EQ(std::string(reinterpret_cast<const char*>(kOpenSSLRawPublicKey), + std::size(kOpenSSLRawPublicKey)), + raw_public_key); +} + +// The Android code writes out Channel IDs differently from the NSS +// implementation; the empty password is converted to "\0\0". The OpenSSL port +// should support either. +TEST(ECPrivateKeyUnitTest, LoadOldOpenSSLKeyTest) { + static const uint8_t kOpenSSLKey[] = { + 0x30, 0x82, 0x01, 0xa1, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0x86, 0xaa, + 0xd7, 0xdf, 0x3b, 0x91, 0x97, 0x60, 0x02, 0x01, 0x01, 0x04, 0x82, 0x01, + 0x80, 0xcb, 0x2a, 0x14, 0xaa, 0x4f, 0x38, 0x4c, 0xe1, 0x49, 0x00, 0xe2, + 0x1a, 0x3a, 0x75, 0x87, 0x7e, 0x3d, 0xea, 0x4d, 0x53, 0xd4, 0x46, 0x47, + 0x23, 0x8f, 0xa1, 0x72, 0x51, 0x92, 0x86, 0x8b, 0xeb, 0x53, 0xe6, 0x6a, + 0x0a, 0x6b, 0xb6, 0xa0, 0xdc, 0x0f, 0xdc, 0x20, 0xc3, 0x45, 0x85, 0xf1, + 0x95, 0x90, 0x5c, 0xf4, 0xfa, 0xee, 0x47, 0xaf, 0x35, 0xd0, 0xd0, 0xd3, + 0x14, 0xde, 0x0d, 0xca, 0x1b, 0xd3, 0xbb, 0x20, 0xec, 0x9d, 0x6a, 0xd4, + 0xc1, 0xce, 0x60, 0x81, 0xab, 0x0c, 0x72, 0x10, 0xfa, 0x28, 0x3c, 0xac, + 0x87, 0x7b, 0x82, 0x85, 0x00, 0xb8, 0x58, 0x9c, 0x07, 0xc4, 0x7d, 0xa9, + 0xc5, 0x94, 0x95, 0xf7, 0x23, 0x93, 0x3f, 0xed, 0xef, 0x92, 0x55, 0x25, + 0x74, 0xbb, 0xd3, 0xd1, 0x67, 0x3b, 0x3d, 0x5a, 0xfe, 0x84, 0xf8, 0x97, + 0x7d, 0x7c, 0x01, 0xc7, 0xd7, 0x0d, 0xf8, 0xc3, 0x6d, 0xd6, 0xf1, 0xaa, + 0x9d, 0x1f, 0x69, 0x97, 0x45, 0x06, 0xc4, 0x1c, 0x95, 0x3c, 0xe0, 0xef, + 0x11, 0xb2, 0xb3, 0x72, 0x91, 0x9e, 0x7d, 0x0f, 0x7f, 0xc8, 0xf6, 0x64, + 0x49, 0x5e, 0x3c, 0x53, 0x37, 0x79, 0x03, 0x1c, 0x3f, 0x29, 0x6c, 0x6b, + 0xea, 0x4c, 0x35, 0x9b, 0x6d, 0x1b, 0x59, 0x43, 0x4c, 0x14, 0x47, 0x2a, + 0x36, 0x39, 0x2a, 0xd8, 0x96, 0x90, 0xdc, 0xfc, 0xd2, 0xdd, 0x23, 0x0e, + 0x2c, 0xb3, 0x83, 0xf9, 0xf2, 0xe3, 0xe6, 0x99, 0x53, 0x57, 0x33, 0xc5, + 0x5f, 0xf9, 0xfd, 0x56, 0x0b, 0x32, 0xd4, 0xf3, 0x9d, 0x5b, 0x34, 0xe5, + 0x94, 0xbf, 0xb6, 0xc0, 0xce, 0xe1, 0x73, 0x5c, 0x02, 0x7a, 0x4c, 0xed, + 0xde, 0x23, 0x38, 0x89, 0x9f, 0xcd, 0x51, 0xf3, 0x90, 0x80, 0xd3, 0x4b, + 0x83, 0xd3, 0xee, 0xf2, 0x9e, 0x35, 0x91, 0xa5, 0xa3, 0xc0, 0x5c, 0xce, + 0xdb, 0xaa, 0x70, 0x1e, 0x1d, 0xc1, 0x44, 0xea, 0x3b, 0xa7, 0x5a, 0x11, + 0xd1, 0xf3, 0xf3, 0xd0, 0xf4, 0x5a, 0xc4, 0x99, 0xaf, 0x8d, 0xe2, 0xbc, + 0xa2, 0xb9, 0x3d, 0x86, 0x5e, 0xba, 0xa0, 0xdf, 0x78, 0x81, 0x7c, 0x54, + 0x31, 0xe3, 0x98, 0xb5, 0x46, 0xcb, 0x4d, 0x26, 0x4b, 0xf8, 0xac, 0x3a, + 0x54, 0x1b, 0x77, 0x5a, 0x18, 0xa5, 0x43, 0x0e, 0x14, 0xde, 0x7b, 0xb7, + 0x4e, 0x45, 0x99, 0x03, 0xd1, 0x3d, 0x18, 0xb2, 0x36, 0x00, 0x48, 0x07, + 0x72, 0xbb, 0x4f, 0x21, 0x25, 0x3e, 0xda, 0x25, 0x24, 0x5b, 0xc8, 0xa0, + 0x28, 0xd5, 0x9b, 0x96, 0x87, 0x07, 0x77, 0x84, 0xff, 0xd7, 0xac, 0x71, + 0xf6, 0x61, 0x63, 0x0b, 0xfb, 0x42, 0xfd, 0x52, 0xf4, 0xc4, 0x35, 0x0c, + 0xc2, 0xc1, 0x55, 0x22, 0x42, 0x2f, 0x13, 0x7d, 0x93, 0x27, 0xc8, 0x11, + 0x35, 0xc5, 0xe3, 0xc5, 0xaa, 0x15, 0x3c, 0xac, 0x30, 0xbc, 0x45, 0x16, + 0xed, + }; + + std::unique_ptr<crypto::ECPrivateKey> keypair_openssl( + crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( + std::vector<uint8_t>(std::begin(kOpenSSLKey), + std::end(kOpenSSLKey)))); + + EXPECT_TRUE(keypair_openssl); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.cc b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.cc new file mode 100644 index 00000000000..499a1641a43 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.cc @@ -0,0 +1,30 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/ec_signature_creator.h" + +#include <memory> + +#include "internal/crypto/ec_signature_creator_impl.h" +#include "internal/platform/logging.h" + +namespace crypto { + +// static +std::unique_ptr<ECSignatureCreator> ECSignatureCreator::Create( + ECPrivateKey* key) { + return std::make_unique<ECSignatureCreatorImpl>(key); +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.h b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.h new file mode 100644 index 00000000000..a87fa9b9e46 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.h @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_H_ + +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +class ECPrivateKey; +class ECSignatureCreator; + +// Signs data using a bare private key (as opposed to a full certificate). +// We need this class because SignatureCreator is hardcoded to use +// RSAPrivateKey. +class CRYPTO_EXPORT ECSignatureCreator { + public: + virtual ~ECSignatureCreator() {} + + // Create an instance. The caller must ensure that the provided PrivateKey + // instance outlives the created ECSignatureCreator. + // TODO(rch): This is currently hard coded to use SHA256. Ideally, we should + // pass in the hash algorithm identifier. + static std::unique_ptr<ECSignatureCreator> Create(ECPrivateKey* key); + + // Signs |data| and writes the results into |signature| as a DER encoded + // ECDSA-Sig-Value from RFC 3279. + // + // ECDSA-Sig-Value ::= SEQUENCE { + // r INTEGER, + // s INTEGER } + virtual bool Sign(absl::Span<const uint8_t> data, + std::vector<uint8_t>* signature) = 0; + + // DecodeSignature converts from a DER encoded ECDSA-Sig-Value (as produced + // by Sign) to a `raw' ECDSA signature which consists of a pair of + // big-endian, zero-padded, 256-bit integers, r and s. On success it returns + // true and puts the raw signature into |out_raw_sig|. + // (Only P-256 signatures are supported.) + virtual bool DecodeSignature(const std::vector<uint8_t>& signature, + std::vector<uint8_t>* out_raw_sig) = 0; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.cc b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.cc new file mode 100644 index 00000000000..e302c1bcba2 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.cc @@ -0,0 +1,83 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/ec_signature_creator_impl.h" + +#include <stddef.h> +#include <stdint.h> + +#include <vector> + +#include "internal/crypto/ec_private_key.h" +#include "internal/crypto/openssl_util.h" +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/ecdsa.h> +#include <openssl/evp.h> +#include <openssl/sha.h> + +namespace crypto { + +ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key) : key_(key) { + EnsureOpenSSLInit(); +} + +ECSignatureCreatorImpl::~ECSignatureCreatorImpl() = default; + +bool ECSignatureCreatorImpl::Sign(absl::Span<const uint8_t> data, + std::vector<uint8_t>* signature) { + OpenSSLErrStackTracer err_tracer; + bssl::ScopedEVP_MD_CTX ctx; + size_t sig_len = 0; + if (!ctx.get() || + !EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, + key_->key()) || + !EVP_DigestSignUpdate(ctx.get(), data.data(), data.size()) || + !EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len)) { + return false; + } + + signature->resize(sig_len); + if (!EVP_DigestSignFinal(ctx.get(), &signature->front(), &sig_len)) + return false; + + // NOTE: A call to EVP_DigestSignFinal() with a nullptr second parameter + // returns a maximum allocation size, while the call without a nullptr + // returns the real one, which may be smaller. + signature->resize(sig_len); + return true; +} + +bool ECSignatureCreatorImpl::DecodeSignature( + const std::vector<uint8_t>& der_sig, std::vector<uint8_t>* out_raw_sig) { + OpenSSLErrStackTracer err_tracer; + // Create ECDSA_SIG object from DER-encoded data. + bssl::UniquePtr<ECDSA_SIG> ecdsa_sig( + ECDSA_SIG_from_bytes(der_sig.data(), der_sig.size())); + if (!ecdsa_sig.get()) return false; + + // The result is made of two 32-byte vectors. + const size_t kMaxBytesPerBN = 32; + std::vector<uint8_t> result(2 * kMaxBytesPerBN); + + if (!BN_bn2bin_padded(&result[0], kMaxBytesPerBN, ecdsa_sig->r) || + !BN_bn2bin_padded(&result[kMaxBytesPerBN], kMaxBytesPerBN, + ecdsa_sig->s)) { + return false; + } + out_raw_sig->swap(result); + return true; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.h b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.h new file mode 100644 index 00000000000..74599886dd5 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.h @@ -0,0 +1,48 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_ + +#include <stdint.h> + +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/ec_signature_creator.h" + +namespace crypto { + +class ECSignatureCreatorImpl : public ECSignatureCreator { + public: + explicit ECSignatureCreatorImpl(ECPrivateKey* key); + + ECSignatureCreatorImpl(const ECSignatureCreatorImpl&) = delete; + ECSignatureCreatorImpl& operator=(const ECSignatureCreatorImpl&) = delete; + + ~ECSignatureCreatorImpl() override; + + bool Sign(absl::Span<const uint8_t> data, + std::vector<uint8_t>* signature) override; + + bool DecodeSignature(const std::vector<uint8_t>& der_sig, + std::vector<uint8_t>* out_raw_sig) override; + + private: + ECPrivateKey* key_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_unittest.cc new file mode 100644 index 00000000000..e4eab224311 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_unittest.cc @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/ec_signature_creator.h" + +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/types/span.h" +#include "internal/crypto/ec_private_key.h" +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/signature_verifier.h" + +TEST(ECSignatureCreatorTest, BasicTest) { + // Do a verify round trip. + std::unique_ptr<crypto::ECPrivateKey> key_original( + crypto::ECPrivateKey::Create()); + ASSERT_TRUE(key_original); + + std::vector<uint8_t> key_info; + ASSERT_TRUE(key_original->ExportPrivateKey(&key_info)); + + std::unique_ptr<crypto::ECPrivateKey> key( + crypto::ECPrivateKey::CreateFromPrivateKeyInfo(key_info)); + ASSERT_TRUE(key); + ASSERT_TRUE(key->key()); + + std::unique_ptr<crypto::ECSignatureCreator> signer( + crypto::ECSignatureCreator::Create(key.get())); + ASSERT_TRUE(signer); + + std::string data("Hello, World!"); + std::vector<uint8_t> signature; + ASSERT_TRUE( + signer->Sign(nearbybase::as_bytes(absl::MakeSpan(data)), &signature)); + + std::vector<uint8_t> public_key_info; + ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info)); + + crypto::SignatureVerifier verifier; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256, + signature, public_key_info)); + + verifier.VerifyUpdate(nearbybase::as_bytes(absl::MakeSpan(data))); + ASSERT_TRUE(verifier.VerifyFinal()); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/encryptor.cc b/chromium/third_party/nearby/src/internal/crypto/encryptor.cc new file mode 100644 index 00000000000..b40a91bdd2f --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/encryptor.cc @@ -0,0 +1,218 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/encryptor.h" + +#include <stddef.h> +#include <stdint.h> + +#include <optional> +#include <string> +#include <utility> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/openssl_util.h" +#include "internal/crypto/symmetric_key.h" +#include "internal/platform/logging.h" +#include <openssl/aes.h> +#include <openssl/evp.h> + +namespace crypto { + +namespace { + +const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) { + switch (key->key().length()) { + case 16: + return EVP_aes_128_cbc(); + case 32: + return EVP_aes_256_cbc(); + default: + return nullptr; + } +} + +} // namespace + +///////////////////////////////////////////////////////////////////////////// +// Encryptor Implementation. + +Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {} + +Encryptor::~Encryptor() = default; + +bool Encryptor::Init(const SymmetricKey* key, Mode mode, absl::string_view iv) { + return Init(key, mode, nearbybase::as_bytes(absl::MakeSpan(iv))); +} + +bool Encryptor::Init(const SymmetricKey* key, Mode mode, + absl::Span<const uint8_t> iv) { + DCHECK(key); + DCHECK(mode == CBC || mode == CTR); + + EnsureOpenSSLInit(); + if (mode == CBC && iv.size() != AES_BLOCK_SIZE) return false; + // CTR mode passes the starting counter separately, via SetCounter(). + if (mode == CTR && !iv.empty()) return false; + + if (GetCipherForKey(key) == nullptr) return false; + + key_ = key; + mode_ = mode; + iv_.assign(iv.begin(), iv.end()); + return true; +} + +bool Encryptor::Encrypt(absl::string_view plaintext, std::string* ciphertext) { + DCHECK(!plaintext.empty() || mode_ == CBC); + return CryptString(/*do_encrypt=*/true, plaintext, ciphertext); +} + +bool Encryptor::Encrypt(absl::Span<const uint8_t> plaintext, + std::vector<uint8_t>* ciphertext) { + DCHECK(!plaintext.empty() || mode_ == CBC); + return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext); +} + +bool Encryptor::Decrypt(absl::string_view ciphertext, std::string* plaintext) { + DCHECK(!ciphertext.empty()); + return CryptString(/*do_encrypt=*/false, ciphertext, plaintext); +} + +bool Encryptor::Decrypt(absl::Span<const uint8_t> ciphertext, + std::vector<uint8_t>* plaintext) { + DCHECK(!ciphertext.empty()); + return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext); +} + +bool Encryptor::SetCounter(absl::string_view counter) { + return SetCounter(nearbybase::as_bytes(absl::MakeSpan(counter))); +} + +bool Encryptor::SetCounter(absl::Span<const uint8_t> counter) { + if (mode_ != CTR) return false; + if (counter.size() != 16u) return false; + + iv_.assign(counter.begin(), counter.end()); + return true; +} + +bool Encryptor::CryptString(bool do_encrypt, absl::string_view input, + std::string* output) { + size_t out_size = MaxOutput(do_encrypt, input.size()); + CHECK_GT(out_size + 1, out_size); // Overflow + std::string result; + uint8_t* out_ptr = + reinterpret_cast<uint8_t*>(nearbybase::WriteInto(&result, out_size + 1)); + + absl::optional<size_t> len = + (mode_ == CTR) + ? CryptCTR(do_encrypt, nearbybase::as_bytes(absl::MakeSpan(input)), + absl::MakeSpan(out_ptr, out_size)) + : Crypt(do_encrypt, nearbybase::as_bytes(absl::MakeSpan(input)), + absl::MakeSpan(out_ptr, out_size)); + if (!len) return false; + + result.resize(*len); + *output = std::move(result); + return true; +} + +bool Encryptor::CryptBytes(bool do_encrypt, absl::Span<const uint8_t> input, + std::vector<uint8_t>* output) { + std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size())); + absl::optional<size_t> len = + (mode_ == CTR) ? CryptCTR(do_encrypt, input, absl::MakeSpan(result)) + : Crypt(do_encrypt, input, absl::MakeSpan(result)); + if (!len) return false; + + result.resize(*len); + *output = std::move(result); + return true; +} + +size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) { + size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0); + CHECK_GE(result, length); // Overflow + return result; +} + +absl::optional<size_t> Encryptor::Crypt(bool do_encrypt, + absl::Span<const uint8_t> input, + absl::Span<uint8_t> output) { + DCHECK(key_); // Must call Init() before En/De-crypt. + + const EVP_CIPHER* cipher = GetCipherForKey(key_); + DCHECK(cipher); // Already handled in Init(); + + const std::string& key = key_->key(); + DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size()); + DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size()); + + OpenSSLErrStackTracer err_tracer; + bssl::ScopedEVP_CIPHER_CTX ctx; + if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, + reinterpret_cast<const uint8_t*>(key.data()), + iv_.data(), do_encrypt)) { + return absl::nullopt; + } + + // Encrypting needs a block size of space to allow for any padding. + CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0)); + int out_len; + if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(), + input.size())) + return absl::nullopt; + + // Write out the final block plus padding (if any) to the end of the data + // just written. + int tail_len; + if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len)) + return absl::nullopt; + + out_len += tail_len; + DCHECK_LE(out_len, static_cast<int>(output.size())); + return out_len; +} + +absl::optional<size_t> Encryptor::CryptCTR(bool do_encrypt, + absl::Span<const uint8_t> input, + absl::Span<uint8_t> output) { + if (iv_.size() != AES_BLOCK_SIZE) { + NEARBY_LOGS(ERROR) << "Counter value not set in CTR mode."; + return absl::nullopt; + } + + AES_KEY aes_key; + if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()), + key_->key().size() * 8, &aes_key) != 0) { + return absl::nullopt; + } + + uint8_t ecount_buf[AES_BLOCK_SIZE] = {0}; + unsigned int block_offset = 0; + + // |output| must have room for |input|. + CHECK_GE(output.size(), input.size()); + // Note AES_ctr128_encrypt() will update |iv_|. However, this method discards + // |ecount_buf| and |block_offset|, so this is not quite a streaming API. + AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key, + iv_.data(), ecount_buf, &block_offset); + return input.size(); +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/encryptor.h b/chromium/third_party/nearby/src/internal/crypto/encryptor.h new file mode 100644 index 00000000000..19df38cee15 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/encryptor.h @@ -0,0 +1,110 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_ENCRYPTOR_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_ENCRYPTOR_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <optional> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +class SymmetricKey; + +// This class implements encryption without authentication, which is usually +// unsafe. Prefer crypto::Aead for new code. If using this class, prefer the +// absl::Span and std::vector overloads over the absl::string_view and +// std::string overloads. +class CRYPTO_EXPORT Encryptor { + public: + enum Mode { + CBC, + CTR, + }; + + Encryptor(); + ~Encryptor(); + + // Initializes the encryptor using |key| and |iv|. Returns false if either the + // key or the initialization vector cannot be used. + // + // If |mode| is CBC, |iv| must not be empty; if it is CTR, then |iv| must be + // empty. + bool Init(const SymmetricKey* key, Mode mode, absl::string_view iv); + bool Init(const SymmetricKey* key, Mode mode, absl::Span<const uint8_t> iv); + + // Encrypts |plaintext| into |ciphertext|. |plaintext| may only be empty if + // the mode is CBC. + bool Encrypt(absl::string_view plaintext, std::string* ciphertext); + bool Encrypt(absl::Span<const uint8_t> plaintext, + std::vector<uint8_t>* ciphertext); + + // Decrypts |ciphertext| into |plaintext|. |ciphertext| must not be empty. + // + // WARNING: In CBC mode, Decrypt() returns false if it detects the padding + // in the decrypted plaintext is wrong. Padding errors can result from + // tampered ciphertext or a wrong decryption key. But successful decryption + // does not imply the authenticity of the data. The caller of Decrypt() + // must either authenticate the ciphertext before decrypting it, or take + // care to not report decryption failure. Otherwise it could inadvertently + // be used as a padding oracle to attack the crypto system. + bool Decrypt(absl::string_view ciphertext, std::string* plaintext); + bool Decrypt(absl::Span<const uint8_t> ciphertext, + std::vector<uint8_t>* plaintext); + + // Sets the counter value when in CTR mode. Currently only 128-bits + // counter value is supported. + // + // Returns true only if update was successful. + bool SetCounter(absl::string_view counter); + bool SetCounter(absl::Span<const uint8_t> counter); + + // TODO(albertb): Support streaming encryption. + + private: + const SymmetricKey* key_; + Mode mode_; + + bool CryptString(bool do_encrypt, absl::string_view input, + std::string* output); + bool CryptBytes(bool do_encrypt, absl::Span<const uint8_t> input, + std::vector<uint8_t>* output); + + // On success, these helper functions return the number of bytes written to + // |output|. + size_t MaxOutput(bool do_encrypt, size_t length); + absl::optional<size_t> Crypt(bool do_encrypt, absl::Span<const uint8_t> input, + absl::Span<uint8_t> output); + absl::optional<size_t> CryptCTR(bool do_encrypt, + absl::Span<const uint8_t> input, + absl::Span<uint8_t> output); + + // In CBC mode, the IV passed to Init(). In CTR mode, the counter value passed + // to SetCounter(). + std::vector<uint8_t> iv_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_ENCRYPTOR_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/encryptor_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/encryptor_unittest.cc new file mode 100644 index 00000000000..351ae995f97 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/encryptor_unittest.cc @@ -0,0 +1,572 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/encryptor.h" + +#include <stddef.h> + +#include <array> +#include <iterator> +#include <memory> +#include <string> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/types/span.h" +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/symmetric_key.h" + +TEST(EncryptorTest, EncryptDecrypt) { + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)); + EXPECT_TRUE(key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long as the cipher block size. + std::string iv("the iv: 16 bytes"); + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)); + + std::string plaintext("this is the plaintext"); + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); + + // Repeat the test with the bytes API. + std::vector<uint8_t> plaintext_vec(plaintext.begin(), plaintext.end()); + std::vector<uint8_t> ciphertext_vec; + EXPECT_TRUE(encryptor.Encrypt(plaintext_vec, &ciphertext_vec)); + EXPECT_LT(0U, ciphertext_vec.size()); + + std::vector<uint8_t> decrypted_vec; + EXPECT_TRUE(encryptor.Decrypt(ciphertext_vec, &decrypted_vec)); + EXPECT_EQ(plaintext_vec, decrypted_vec); +} + +TEST(EncryptorTest, DecryptWrongKey) { + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)); + EXPECT_TRUE(key.get()); + + // A wrong key that can be detected by implementations that validate every + // byte in the padding. + std::unique_ptr<crypto::SymmetricKey> wrong_key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongword", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key.get()); + + // A wrong key that can't be detected by any implementation. The password + // "wrongword;" would also work. + std::unique_ptr<crypto::SymmetricKey> wrong_key2( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongword+", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key2.get()); + + // A wrong key that can be detected by all implementations. + std::unique_ptr<crypto::SymmetricKey> wrong_key3( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::AES, "wrongwordx", "sweetest", 1000, 256)); + EXPECT_TRUE(wrong_key3.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long as the cipher block size. + std::string iv("the iv: 16 bytes"); + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)); + + std::string plaintext("this is the plaintext"); + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + + static const unsigned char expected_ciphertext[] = { + 0x7D, 0x67, 0x5B, 0x53, 0xE6, 0xD8, 0x0F, 0x27, 0x74, 0xB1, 0x90, + 0xFE, 0x6E, 0x58, 0x4A, 0xA0, 0x0E, 0x35, 0xE3, 0x01, 0xC0, 0xFE, + 0x9A, 0xD8, 0x48, 0x1D, 0x42, 0xB0, 0xBA, 0x21, 0xB2, 0x0C}; + + ASSERT_EQ(std::size(expected_ciphertext), ciphertext.size()); + for (size_t i = 0; i < ciphertext.size(); ++i) { + ASSERT_EQ(expected_ciphertext[i], + static_cast<unsigned char>(ciphertext[i])); + } + + std::string decrypted; + + // This wrong key causes the last padding byte to be 5, which is a valid + // padding length, and the second to last padding byte to be 137, which is + // invalid. If an implementation simply uses the last padding byte to + // determine the padding length without checking every padding byte, + // Encryptor::Decrypt() will still return true. This is the case for NSS + // (crbug.com/124434). + crypto::Encryptor decryptor; + EXPECT_TRUE(decryptor.Init(wrong_key.get(), crypto::Encryptor::CBC, iv)); + EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decrypted)); + + // This demonstrates that not all wrong keys can be detected by padding + // error. This wrong key causes the last padding byte to be 1, which is + // a valid padding block of length 1. + crypto::Encryptor decryptor2; + EXPECT_TRUE(decryptor2.Init(wrong_key2.get(), crypto::Encryptor::CBC, iv)); + EXPECT_TRUE(decryptor2.Decrypt(ciphertext, &decrypted)); + + // This wrong key causes the last padding byte to be 253, which should be + // rejected by all implementations. + crypto::Encryptor decryptor3; + EXPECT_TRUE(decryptor3.Init(wrong_key3.get(), crypto::Encryptor::CBC, iv)); + EXPECT_FALSE(decryptor3.Decrypt(ciphertext, &decrypted)); +} + +namespace { + +// From NIST SP 800-38a test cast: +// - F.5.1 CTR-AES128.Encrypt +// - F.5.6 CTR-AES256.Encrypt +// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +const unsigned char kAES128CTRKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, + 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, + 0x09, 0xcf, 0x4f, 0x3c}; + +const unsigned char kAES256CTRKey[] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, + 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, + 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; + +const unsigned char kAESCTRInitCounter[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff}; + +const unsigned char kAESCTRPlaintext[] = { + // Block #1 + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, + 0x73, 0x93, 0x17, 0x2a, + // Block #2 + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, + 0x45, 0xaf, 0x8e, 0x51, + // Block #3 + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, + 0x1a, 0x0a, 0x52, 0xef, + // Block #4 + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, + 0xe6, 0x6c, 0x37, 0x10}; + +const unsigned char kAES128CTRCiphertext[] = { + // Block #1 + 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, + 0x99, 0x0d, 0xb6, 0xce, + // Block #2 + 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, + 0xb9, 0xff, 0xfd, 0xff, + // Block #3 + 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, + 0x0d, 0xb0, 0x3e, 0xab, + // Block #4 + 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, + 0xf3, 0x00, 0x9c, 0xee}; + +const unsigned char kAES256CTRCiphertext[] = { + // Block #1 + 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, + 0xbb, 0xf3, 0xd2, 0x28, + // Block #2 + 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, + 0xca, 0xca, 0xf5, 0xc5, + // Block #3 + 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, + 0x2d, 0x84, 0x98, 0x8d, + // Block #4 + 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, + 0x45, 0x79, 0x41, 0xa6}; + +void TestAESCTREncrypt(const unsigned char* key, size_t key_size, + const unsigned char* init_counter, + size_t init_counter_size, const unsigned char* plaintext, + size_t plaintext_size, const unsigned char* ciphertext, + size_t ciphertext_size) { + std::string key_str(reinterpret_cast<const char*>(key), key_size); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, "")); + + absl::string_view init_counter_str( + reinterpret_cast<const char*>(init_counter), init_counter_size); + absl::string_view plaintext_str(reinterpret_cast<const char*>(plaintext), + plaintext_size); + + EXPECT_TRUE(encryptor.SetCounter(init_counter_str)); + std::string encrypted; + EXPECT_TRUE(encryptor.Encrypt(plaintext_str, &encrypted)); + + EXPECT_EQ(ciphertext_size, encrypted.size()); + EXPECT_EQ(0, memcmp(encrypted.data(), ciphertext, encrypted.size())); + + std::string decrypted; + EXPECT_TRUE(encryptor.SetCounter(init_counter_str)); + EXPECT_TRUE(encryptor.Decrypt(encrypted, &decrypted)); + + EXPECT_EQ(plaintext_str, decrypted); + + // Repeat the test with the bytes API. + EXPECT_TRUE( + encryptor.SetCounter(absl::MakeSpan(init_counter, init_counter_size))); + std::vector<uint8_t> encrypted_vec; + EXPECT_TRUE(encryptor.Encrypt(absl::MakeSpan(plaintext, plaintext_size), + &encrypted_vec)); + + EXPECT_EQ(ciphertext_size, encrypted_vec.size()); + EXPECT_EQ(0, memcmp(encrypted_vec.data(), ciphertext, encrypted_vec.size())); + + std::vector<uint8_t> decrypted_vec; + EXPECT_TRUE( + encryptor.SetCounter(absl::MakeSpan(init_counter, init_counter_size))); + EXPECT_TRUE(encryptor.Decrypt(encrypted_vec, &decrypted_vec)); + + EXPECT_EQ(std::vector<uint8_t>(plaintext, plaintext + plaintext_size), + decrypted_vec); +} + +void TestAESCTRMultipleDecrypt(const unsigned char* key, size_t key_size, + const unsigned char* init_counter, + size_t init_counter_size, + const unsigned char* plaintext, + size_t plaintext_size, + const unsigned char* ciphertext, + size_t ciphertext_size) { + std::string key_str(reinterpret_cast<const char*>(key), key_size); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, "")); + + // Counter is set only once. + EXPECT_TRUE(encryptor.SetCounter(absl::string_view( + reinterpret_cast<const char*>(init_counter), init_counter_size))); + + std::string ciphertext_str(reinterpret_cast<const char*>(ciphertext), + ciphertext_size); + + int kTestDecryptSizes[] = {32, 16, 8}; + + int offset = 0; + for (size_t i = 0; i < std::size(kTestDecryptSizes); ++i) { + std::string decrypted; + size_t len = kTestDecryptSizes[i]; + EXPECT_TRUE( + encryptor.Decrypt(ciphertext_str.substr(offset, len), &decrypted)); + EXPECT_EQ(len, decrypted.size()); + EXPECT_EQ(0, memcmp(decrypted.data(), plaintext + offset, len)); + offset += len; + } +} + +} // namespace + +TEST(EncryptorTest, EncryptAES128CTR) { + TestAESCTREncrypt(kAES128CTRKey, std::size(kAES128CTRKey), kAESCTRInitCounter, + std::size(kAESCTRInitCounter), kAESCTRPlaintext, + std::size(kAESCTRPlaintext), kAES128CTRCiphertext, + std::size(kAES128CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES256CTR) { + TestAESCTREncrypt(kAES256CTRKey, std::size(kAES256CTRKey), kAESCTRInitCounter, + std::size(kAESCTRInitCounter), kAESCTRPlaintext, + std::size(kAESCTRPlaintext), kAES256CTRCiphertext, + std::size(kAES256CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES128CTR_MultipleDecrypt) { + TestAESCTRMultipleDecrypt(kAES128CTRKey, std::size(kAES128CTRKey), + kAESCTRInitCounter, std::size(kAESCTRInitCounter), + kAESCTRPlaintext, std::size(kAESCTRPlaintext), + kAES128CTRCiphertext, + std::size(kAES128CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptAES256CTR_MultipleDecrypt) { + TestAESCTRMultipleDecrypt(kAES256CTRKey, std::size(kAES256CTRKey), + kAESCTRInitCounter, std::size(kAESCTRInitCounter), + kAESCTRPlaintext, std::size(kAESCTRPlaintext), + kAES256CTRCiphertext, + std::size(kAES256CTRCiphertext)); +} + +TEST(EncryptorTest, EncryptDecryptCTR) { + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 128)); + + EXPECT_TRUE(key.get()); + const std::string kInitialCounter = "0000000000000000"; + + crypto::Encryptor encryptor; + EXPECT_TRUE(encryptor.Init(key.get(), crypto::Encryptor::CTR, "")); + EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); + + std::string plaintext("normal plaintext of random length"); + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + std::string decrypted; + EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); + + plaintext = "0123456789012345"; + EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + EXPECT_LT(0U, ciphertext.size()); + + EXPECT_TRUE(encryptor.SetCounter(kInitialCounter)); + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); +} + +// TODO(wtc): add more known-answer tests. Test vectors are available from +// http://www.ietf.org/rfc/rfc3602 +// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf +// http://gladman.plushost.co.uk/oldsite/AES/index.php +// http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip + +// NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt. +TEST(EncryptorTest, EncryptAES256CBC) { + // From NIST SP 800-38a test cast F.2.5 CBC-AES256.Encrypt. + static const unsigned char kRawKey[] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, + 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, + 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; + static const unsigned char kRawIv[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; + static const unsigned char kRawPlaintext[] = { + // Block #1 + 0x6b, + 0xc1, + 0xbe, + 0xe2, + 0x2e, + 0x40, + 0x9f, + 0x96, + 0xe9, + 0x3d, + 0x7e, + 0x11, + 0x73, + 0x93, + 0x17, + 0x2a, + // Block #2 + 0xae, + 0x2d, + 0x8a, + 0x57, + 0x1e, + 0x03, + 0xac, + 0x9c, + 0x9e, + 0xb7, + 0x6f, + 0xac, + 0x45, + 0xaf, + 0x8e, + 0x51, + // Block #3 + 0x30, + 0xc8, + 0x1c, + 0x46, + 0xa3, + 0x5c, + 0xe4, + 0x11, + 0xe5, + 0xfb, + 0xc1, + 0x19, + 0x1a, + 0x0a, + 0x52, + 0xef, + // Block #4 + 0xf6, + 0x9f, + 0x24, + 0x45, + 0xdf, + 0x4f, + 0x9b, + 0x17, + 0xad, + 0x2b, + 0x41, + 0x7b, + 0xe6, + 0x6c, + 0x37, + 0x10, + }; + static const unsigned char kRawCiphertext[] = { + // Block #1 + 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, + 0x5f, 0x7b, 0xfb, 0xd6, + // Block #2 + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, + 0xc6, 0x70, 0x2c, 0x7d, + // Block #3 + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, + 0x04, 0x23, 0x14, 0x61, + // Block #4 + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, + 0x8c, 0x6a, 0x9d, 0x1b, + // PKCS #5 padding, encrypted. + 0x3f, 0x46, 0x17, 0x96, 0xd6, 0xb0, 0xd6, 0xb2, 0xe0, 0xc2, 0xa7, 0x2b, + 0x4d, 0x80, 0xe6, 0x44}; + + std::string key(reinterpret_cast<const char*>(kRawKey), sizeof(kRawKey)); + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long a the cipher block size. + std::string iv(reinterpret_cast<const char*>(kRawIv), sizeof(kRawIv)); + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); + + std::string plaintext(reinterpret_cast<const char*>(kRawPlaintext), + sizeof(kRawPlaintext)); + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + + EXPECT_EQ(sizeof(kRawCiphertext), ciphertext.size()); + EXPECT_EQ(0, memcmp(ciphertext.data(), kRawCiphertext, ciphertext.size())); + + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + + EXPECT_EQ(plaintext, decrypted); +} + +// Expected output derived from the NSS implementation. +TEST(EncryptorTest, EncryptAES128CBCRegression) { + std::string key = "128=SixteenBytes"; + std::string iv = "Sweet Sixteen IV"; + std::string plaintext = "Plain text with a g-clef U+1D11E \360\235\204\236"; + std::string expected_ciphertext_hex = + "D4A67A0BA33C30F207344D81D1E944BBE65587C3D7D9939A" + "C070C62B9C15A3EA312EA4AD1BC7929F4D3C16B03AD5ADA8"; + + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long a the cipher block size. + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); + + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + EXPECT_EQ(expected_ciphertext_hex, + nearbybase::HexEncode(ciphertext.data(), ciphertext.size())); + + std::string decrypted; + EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted)); + EXPECT_EQ(plaintext, decrypted); +} + +// Symmetric keys with an unsupported size should be rejected. Whether they are +// rejected by SymmetricKey::Import or Encryptor::Init depends on the platform. +TEST(EncryptorTest, UnsupportedKeySize) { + std::string key = "7 = bad"; + std::string iv = "Sweet Sixteen IV"; + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + if (!sym_key.get()) return; + + crypto::Encryptor encryptor; + // The IV must be exactly as long as the cipher block size. + EXPECT_EQ(16U, iv.size()); + EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); +} + +TEST(EncryptorTest, UnsupportedIV) { + std::string key = "128=SixteenBytes"; + std::string iv = "OnlyForteen :("; + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); +} + +TEST(EncryptorTest, EmptyEncrypt) { + std::string key = "128=SixteenBytes"; + std::string iv = "Sweet Sixteen IV"; + std::string plaintext; + std::string expected_ciphertext_hex = "8518B8878D34E7185E300D0FCC426396"; + + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long a the cipher block size. + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); + + std::string ciphertext; + EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext)); + EXPECT_EQ(expected_ciphertext_hex, + nearbybase::HexEncode(ciphertext.data(), ciphertext.size())); +} + +TEST(EncryptorTest, CipherTextNotMultipleOfBlockSize) { + std::string key = "128=SixteenBytes"; + std::string iv = "Sweet Sixteen IV"; + + std::unique_ptr<crypto::SymmetricKey> sym_key( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key)); + ASSERT_TRUE(sym_key.get()); + + crypto::Encryptor encryptor; + // The IV must be exactly as long a the cipher block size. + EXPECT_EQ(16U, iv.size()); + EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv)); + + // Use a separately allocated array to improve the odds of the memory tools + // catching invalid accesses. + // + // Otherwise when using std::string as the other tests do, accesses several + // bytes off the end of the buffer may fall inside the reservation of + // the string and not be detected. + std::unique_ptr<char[]> ciphertext(new char[1]); + + std::string plaintext; + EXPECT_FALSE( + encryptor.Decrypt(absl::string_view(ciphertext.get(), 1), &plaintext)); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/hkdf.cc b/chromium/third_party/nearby/src/internal/crypto/hkdf.cc new file mode 100644 index 00000000000..dbbf61a3b1a --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/hkdf.cc @@ -0,0 +1,58 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 <openssl/hkdf.h> + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "internal/crypto/hkdf.h" +#include "internal/crypto/hmac.h" +#include "internal/platform/logging.h" +#include <openssl/digest.h> + +namespace crypto { + +std::string HkdfSha256(absl::string_view secret, absl::string_view salt, + absl::string_view info, size_t derived_key_size) { + std::string key; + key.resize(derived_key_size); + int result = ::HKDF( + reinterpret_cast<uint8_t*>(&key[0]), derived_key_size, EVP_sha256(), + reinterpret_cast<const uint8_t*>(secret.data()), secret.size(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), + reinterpret_cast<const uint8_t*>(info.data()), info.size()); + DCHECK(result); + return key; +} + +std::vector<uint8_t> HkdfSha256(absl::Span<const uint8_t> secret, + absl::Span<const uint8_t> salt, + absl::Span<const uint8_t> info, + size_t derived_key_size) { + std::vector<uint8_t> ret; + ret.resize(derived_key_size); + int result = + ::HKDF(ret.data(), derived_key_size, EVP_sha256(), secret.data(), + secret.size(), salt.data(), salt.size(), info.data(), info.size()); + DCHECK(result); + return ret; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/hkdf.h b/chromium/third_party/nearby/src/internal/crypto/hkdf.h new file mode 100644 index 00000000000..818032709f2 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/hkdf.h @@ -0,0 +1,41 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HKDF_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HKDF_H_ + +#include <stddef.h> + +#include <string> +#include <vector> + +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +CRYPTO_EXPORT +std::string HkdfSha256(absl::string_view secret, absl::string_view salt, + absl::string_view info, size_t derived_key_size); + +CRYPTO_EXPORT +std::vector<uint8_t> HkdfSha256(absl::Span<const uint8_t> secret, + absl::Span<const uint8_t> salt, + absl::Span<const uint8_t> info, + size_t derived_key_size); + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HKDF_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/hmac.cc b/chromium/third_party/nearby/src/internal/crypto/hmac.cc new file mode 100644 index 00000000000..b5ac2688b5c --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/hmac.cc @@ -0,0 +1,114 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 <openssl/hmac.h> + +#include <stddef.h> + +#include <algorithm> +#include <string> + +#include "internal/crypto/hmac.h" +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/openssl_util.h" +#include "internal/crypto/secure_util.h" +#include "internal/crypto/symmetric_key.h" +#include "internal/platform/logging.h" + +namespace crypto { + +HMAC::HMAC(HashAlgorithm hash_alg) : hash_alg_(hash_alg), initialized_(false) { + // Only SHA-1 and SHA-256 hash algorithms are supported now. + DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); +} + +HMAC::~HMAC() { + // Zero out key copy. + key_.assign(key_.size(), 0); + nearbybase::STLClearObject(&key_); +} + +size_t HMAC::DigestLength() const { + switch (hash_alg_) { + case SHA1: + return 20; + case SHA256: + return 32; + default: + DCHECK(false); + return 0; + } +} + +bool HMAC::Init(const unsigned char* key, size_t key_length) { + // Init must not be called more than once on the same HMAC object. + DCHECK(!initialized_); + initialized_ = true; + key_.assign(key, key + key_length); + return true; +} + +bool HMAC::Init(const SymmetricKey* key) { return Init(key->key()); } + +bool HMAC::Sign(absl::string_view data, unsigned char* digest, + size_t digest_length) const { + return Sign(nearbybase::as_bytes(absl::MakeSpan(data)), + absl::MakeSpan(digest, digest_length)); +} + +bool HMAC::Sign(absl::Span<const uint8_t> data, + absl::Span<uint8_t> digest) const { + DCHECK(initialized_); + + if (digest.size() > DigestLength()) return false; + + ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> result(digest.data(), + digest.size()); + return !!::HMAC(hash_alg_ == SHA1 ? EVP_sha1() : EVP_sha256(), key_.data(), + key_.size(), data.data(), data.size(), result.safe_buffer(), + nullptr); +} + +bool HMAC::Verify(absl::string_view data, absl::string_view digest) const { + return Verify(nearbybase::as_bytes(absl::MakeSpan(data)), + nearbybase::as_bytes(absl::MakeSpan(digest))); +} + +bool HMAC::Verify(absl::Span<const uint8_t> data, + absl::Span<const uint8_t> digest) const { + if (digest.size() != DigestLength()) return false; + return VerifyTruncated(data, digest); +} + +bool HMAC::VerifyTruncated(absl::string_view data, + absl::string_view digest) const { + return VerifyTruncated(nearbybase::as_bytes(absl::MakeSpan(data)), + nearbybase::as_bytes(absl::MakeSpan(digest))); +} + +bool HMAC::VerifyTruncated(absl::Span<const uint8_t> data, + absl::Span<const uint8_t> digest) const { + if (digest.empty()) return false; + + size_t digest_length = DigestLength(); + if (digest.size() > digest_length) return false; + + uint8_t computed_digest[EVP_MAX_MD_SIZE]; + CHECK_LE(digest.size(), size_t{EVP_MAX_MD_SIZE}); + if (!Sign(data, absl::MakeSpan(computed_digest, digest.size()))) return false; + + return SecureMemEqual(digest.data(), computed_digest, digest.size()); +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/hmac.h b/chromium/third_party/nearby/src/internal/crypto/hmac.h new file mode 100644 index 00000000000..c56d7c7b23a --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/hmac.h @@ -0,0 +1,125 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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. + +// Utility class for calculating the HMAC for a given message. We currently only +// support SHA-1 and SHA-256 for the hash algorithm, but this can be extended +// easily. Prefer the absl::Span and std::vector overloads over the +// absl::string_view and std::string overloads. + +#ifndef THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HMAC_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HMAC_H_ + +#include <stddef.h> + +#include <memory> +#include <vector> + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" +#include "internal/crypto/nearby_base.h" + +namespace crypto { + +// Simplify the interface and reduce includes by abstracting out the internals. +class SymmetricKey; + +class CRYPTO_EXPORT HMAC { + public: + // The set of supported hash functions. Extend as required. + enum HashAlgorithm { + SHA1, + SHA256, + }; + + explicit HMAC(HashAlgorithm hash_alg); + + HMAC(const HMAC&) = delete; + HMAC& operator=(const HMAC&) = delete; + + ~HMAC(); + + // Returns the length of digest that this HMAC will create. + size_t DigestLength() const; + + // TODO(abarth): Add a PreferredKeyLength() member function. + + // Initializes this instance using |key| of the length |key_length|. Call Init + // only once. It returns false on the second or later calls. + // + // NOTE: the US Federal crypto standard FIPS 198, Section 3 says: + // The size of the key, K, shall be equal to or greater than L/2, where L + // is the size of the hash function output. + // In FIPS 198-1 (and SP-800-107, which describes key size recommendations), + // this requirement is gone. But a system crypto library may still enforce + // this old requirement. If the key is shorter than this recommended value, + // Init() may fail. + ABSL_MUST_USE_RESULT bool Init(const unsigned char* key, size_t key_length); + + // Initializes this instance using |key|. Call Init + // only once. It returns false on the second or later calls. + ABSL_MUST_USE_RESULT bool Init(const SymmetricKey* key); + + // Initializes this instance using |key|. Call Init only once. It returns + // false on the second or later calls. + ABSL_MUST_USE_RESULT bool Init(absl::string_view key) { + return Init(nearbybase::as_bytes(absl::MakeSpan(key))); + } + + // Initializes this instance using |key|. Call Init only once. It returns + // false on the second or later calls. + ABSL_MUST_USE_RESULT bool Init(absl::Span<const uint8_t> key) { + return Init(key.data(), key.size()); + } + + // Calculates the HMAC for the message in |data| using the algorithm supplied + // to the constructor and the key supplied to the Init method. The HMAC is + // returned in |digest|, which has |digest_length| bytes of storage available. + // If |digest_length| is smaller than DigestLength(), the output will be + // truncated. If it is larger, this method will fail. + ABSL_MUST_USE_RESULT bool Sign(absl::string_view data, unsigned char* digest, + size_t digest_length) const; + ABSL_MUST_USE_RESULT bool Sign(absl::Span<const uint8_t> data, + absl::Span<uint8_t> digest) const; + + // Verifies that the HMAC for the message in |data| equals the HMAC provided + // in |digest|, using the algorithm supplied to the constructor and the key + // supplied to the Init method. 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. |digest| must be exactly + // |DigestLength()| bytes long. + ABSL_MUST_USE_RESULT bool Verify(absl::string_view data, + absl::string_view digest) const; + ABSL_MUST_USE_RESULT bool Verify(absl::Span<const uint8_t> data, + absl::Span<const uint8_t> digest) const; + + // Verifies a truncated HMAC, behaving identical to Verify(), except + // that |digest| is allowed to be smaller than |DigestLength()|. + ABSL_MUST_USE_RESULT bool VerifyTruncated(absl::string_view data, + absl::string_view digest) const; + ABSL_MUST_USE_RESULT bool VerifyTruncated( + absl::Span<const uint8_t> data, + absl::Span<const uint8_t> digest) const ABSL_MUST_USE_RESULT; + + private: + HashAlgorithm hash_alg_; + bool initialized_; + std::vector<unsigned char> key_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_HMAC_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/hmac_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/hmac_unittest.cc new file mode 100644 index 00000000000..99677752bc2 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/hmac_unittest.cc @@ -0,0 +1,378 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/hmac.h" + +#include <stddef.h> +#include <string.h> + +#include <array> +#include <iterator> +#include <string> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" + +static const size_t kSHA1DigestSize = 20; +static const size_t kSHA256DigestSize = 32; + +static const char *kSimpleKey = + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"; +static const size_t kSimpleKeyLength = 80; + +static const struct { + const char *data; + const int data_len; + const char *digest; +} kSimpleHmacCases[] = { + {"Test Using Larger Than Block-Size Key - Hash Key First", 54, + "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55" + "\xED\x40\x21\x12"}, + {"Test Using Larger Than Block-Size Key and Larger " + "Than One Block-Size Data", + 73, + "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08" + "\xBB\xFF\x1A\x91"}}; + +TEST(HMACTest, HmacSafeBrowsingResponseTest) { + const int kKeySize = 16; + + // Client key. + const unsigned char kClientKey[kKeySize] = { + 0xbf, 0xf6, 0x83, 0x4b, 0x3e, 0xa3, 0x23, 0xdd, + 0x96, 0x78, 0x70, 0x8e, 0xa1, 0x9d, 0x3b, 0x40}; + + // Expected HMAC result using kMessage and kClientKey. + const unsigned char kReceivedHmac[kSHA1DigestSize] = { + 0xb9, 0x3c, 0xd6, 0xf0, 0x49, 0x47, 0xe2, 0x52, 0x59, 0x7a, + 0xbd, 0x1f, 0x2b, 0x4c, 0x83, 0xad, 0x86, 0xd2, 0x48, 0x85}; + + const char kMessage[] = + "n:1896\ni:goog-malware-shavar\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shav" + "ar_s_445-450\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_439-444\nu:s" + ".ytimg.com/safebrowsing/rd/goog-malware-shavar_s_437\nu:s.ytimg.com/" + "safebrowsi" + "ng/rd/goog-malware-shavar_s_436\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-sh" + "avar_s_433-435\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_431\nu:s.y" + "timg.com/safebrowsing/rd/goog-malware-shavar_s_430\nu:s.ytimg.com/" + "safebrowsing" + "/rd/goog-malware-shavar_s_429\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shav" + "ar_s_428\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_426\nu:s.ytimg.c" + "om/safebrowsing/rd/goog-malware-shavar_s_424\nu:s.ytimg.com/" + "safebrowsing/rd/go" + "og-malware-shavar_s_423\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_4" + "22\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_420\nu:s.ytimg.com/saf" + "ebrowsing/rd/goog-malware-shavar_s_419\nu:s.ytimg.com/safebrowsing/rd/" + "goog-mal" + "ware-shavar_s_414\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_409-411" + "\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_405\nu:s.ytimg.com/safeb" + "rowsing/rd/goog-malware-shavar_s_404\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malwa" + "re-shavar_s_402\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_s_401\nu:s." + "ytimg.com/safebrowsing/rd/goog-malware-shavar_a_973-978\nu:s.ytimg.com/" + "safebro" + "wsing/rd/goog-malware-shavar_a_937-972\nu:s.ytimg.com/safebrowsing/rd/" + "goog-mal" + "ware-shavar_a_931-936\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_a_925" + "-930\nu:s.ytimg.com/safebrowsing/rd/" + "goog-malware-shavar_a_919-924\ni:goog-phis" + "h-shavar\nu:s.ytimg.com/safebrowsing/rd/" + "goog-phish-shavar_a_2633\nu:s.ytimg.co" + "m/safebrowsing/rd/goog-phish-shavar_a_2632\nu:s.ytimg.com/safebrowsing/" + "rd/goog" + "-phish-shavar_a_2629-2631\nu:s.ytimg.com/safebrowsing/rd/" + "goog-phish-shavar_a_2" + "626-2628\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2625\n"; + + std::string message_data(kMessage); + + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(kClientKey, kKeySize)); + unsigned char calculated_hmac[kSHA1DigestSize]; + + EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize)); + EXPECT_EQ(0, memcmp(kReceivedHmac, calculated_hmac, kSHA1DigestSize)); +} + +// Test cases from RFC 2202 section 3 +TEST(HMACTest, RFC2202TestCases) { + const struct { + const char *key; + const int key_len; + const char *data; + const int data_len; + const char *digest; + } cases[] = { + {"\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" + "\x0B\x0B\x0B\x0B", + 20, "Hi There", 8, + "\xB6\x17\x31\x86\x55\x05\x72\x64\xE2\x8B\xC0\xB6\xFB\x37\x8C\x8E" + "\xF1\x46\xBE\x00"}, + {"Jefe", 4, "what do ya want for nothing?", 28, + "\xEF\xFC\xDF\x6A\xE5\xEB\x2F\xA2\xD2\x74\x16\xD5\xF1\x84\xDF\x9C" + "\x25\x9A\x7C\x79"}, + {"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA", + 20, + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD", + 50, + "\x12\x5D\x73\x42\xB9\xAC\x11\xCD\x91\xA3\x9A\xF4\x8A\xA1\x7B\x4F" + "\x63\xF1\x75\xD3"}, + {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18\x19", + 25, + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD", + 50, + "\x4C\x90\x07\xF4\x02\x62\x50\xC6\xBC\x84\x14\xF9\xBF\x50\xC8\x6C" + "\x2D\x72\x35\xDA"}, + {"\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" + "\x0C\x0C\x0C\x0C", + 20, "Test With Truncation", 20, + "\x4C\x1A\x03\x42\x4B\x55\xE0\x7F\xE7\xF2\x7B\xE1\xD5\x8B\xB9\x32" + "\x4A\x9A\x5A\x04"}, + {"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", + 80, "Test Using Larger Than Block-Size Key - Hash Key First", 54, + "\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55" + "\xED\x40\x21\x12"}, + {"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", + 80, + "Test Using Larger Than Block-Size Key and Larger " + "Than One Block-Size Data", + 73, + "\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08" + "\xBB\xFF\x1A\x91"}}; + + for (size_t i = 0; i < std::size(cases); ++i) { + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char *>(cases[i].key), + cases[i].key_len)); + std::string data_string(cases[i].data, cases[i].data_len); + unsigned char digest[kSHA1DigestSize]; + EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize)); + EXPECT_EQ(0, memcmp(cases[i].digest, digest, kSHA1DigestSize)); + } +} + +// TODO(wtc): add other test vectors from RFC 4231. +TEST(HMACTest, RFC4231TestCase6) { + unsigned char key[131]; + for (size_t i = 0; i < sizeof(key); ++i) key[i] = 0xaa; + + std::string data = "Test Using Larger Than Block-Size Key - Hash Key First"; + ASSERT_EQ(54U, data.size()); + + static unsigned char kKnownHMACSHA256[] = { + 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}; + + crypto::HMAC hmac(crypto::HMAC::SHA256); + ASSERT_TRUE(hmac.Init(key, sizeof(key))); + unsigned char calculated_hmac[kSHA256DigestSize]; + + EXPECT_EQ(kSHA256DigestSize, hmac.DigestLength()); + EXPECT_TRUE(hmac.Sign(data, calculated_hmac, kSHA256DigestSize)); + EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize)); +} + +// Based on NSS's FIPS HMAC power-up self-test. +TEST(HMACTest, NSSFIPSPowerUpSelfTest) { + static const char kKnownMessage[] = + "The test message for the MD2, MD5, and SHA-1 hashing algorithms."; + + static const unsigned char kKnownSecretKey[] = { + 0x46, 0x69, 0x72, 0x65, 0x66, 0x6f, 0x78, 0x20, 0x61, 0x6e, + 0x64, 0x20, 0x54, 0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x42, + 0x69, 0x72, 0x64, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x77, + 0x65, 0x73, 0x6f, 0x6d, 0x65, 0x21, 0x00}; + + static const size_t kKnownSecretKeySize = sizeof(kKnownSecretKey); + + // HMAC-SHA-1 known answer (20 bytes). + static const unsigned char kKnownHMACSHA1[] = { + 0xd5, 0x85, 0xf6, 0x5b, 0x39, 0xfa, 0xb9, 0x05, 0x3b, 0x57, + 0x1d, 0x61, 0xe7, 0xb8, 0x84, 0x1e, 0x5d, 0x0e, 0x1e, 0x11}; + + // HMAC-SHA-256 known answer (32 bytes). + static const unsigned char kKnownHMACSHA256[] = { + 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}; + + std::string message_data(kKnownMessage); + + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(kKnownSecretKey, kKnownSecretKeySize)); + unsigned char calculated_hmac[kSHA1DigestSize]; + + EXPECT_EQ(kSHA1DigestSize, hmac.DigestLength()); + EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kSHA1DigestSize)); + EXPECT_EQ(0, memcmp(kKnownHMACSHA1, calculated_hmac, kSHA1DigestSize)); + EXPECT_TRUE(hmac.Verify( + message_data, + absl::string_view(reinterpret_cast<const char *>(kKnownHMACSHA1), + kSHA1DigestSize))); + EXPECT_TRUE(hmac.VerifyTruncated( + message_data, + absl::string_view(reinterpret_cast<const char *>(kKnownHMACSHA1), + kSHA1DigestSize / 2))); + + crypto::HMAC hmac2(crypto::HMAC::SHA256); + ASSERT_TRUE(hmac2.Init(kKnownSecretKey, kKnownSecretKeySize)); + unsigned char calculated_hmac2[kSHA256DigestSize]; + + EXPECT_TRUE(hmac2.Sign(message_data, calculated_hmac2, kSHA256DigestSize)); + EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac2, kSHA256DigestSize)); +} + +TEST(HMACTest, HMACObjectReuse) { + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char *>(kSimpleKey), + kSimpleKeyLength)); + for (size_t i = 0; i < std::size(kSimpleHmacCases); ++i) { + std::string data_string(kSimpleHmacCases[i].data, + kSimpleHmacCases[i].data_len); + unsigned char digest[kSHA1DigestSize]; + EXPECT_TRUE(hmac.Sign(data_string, digest, kSHA1DigestSize)); + EXPECT_EQ(0, memcmp(kSimpleHmacCases[i].digest, digest, kSHA1DigestSize)); + } +} + +TEST(HMACTest, Verify) { + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(reinterpret_cast<const unsigned char *>(kSimpleKey), + kSimpleKeyLength)); + const char empty_digest[kSHA1DigestSize] = {0}; + for (size_t i = 0; i < std::size(kSimpleHmacCases); ++i) { + // Expected results + EXPECT_TRUE(hmac.Verify( + absl::string_view(kSimpleHmacCases[i].data, + kSimpleHmacCases[i].data_len), + absl::string_view(kSimpleHmacCases[i].digest, kSHA1DigestSize))); + // Mismatched size + EXPECT_FALSE(hmac.Verify(absl::string_view(kSimpleHmacCases[i].data, + kSimpleHmacCases[i].data_len), + absl::string_view(kSimpleHmacCases[i].data, + kSimpleHmacCases[i].data_len))); + + // Expected size, mismatched data + EXPECT_FALSE(hmac.Verify(absl::string_view(kSimpleHmacCases[i].data, + kSimpleHmacCases[i].data_len), + absl::string_view(empty_digest, kSHA1DigestSize))); + } +} + +TEST(HMACTest, EmptyKey) { + // Test vector from https://en.wikipedia.org/wiki/HMAC + const char *kExpectedDigest = + "\xFB\xDB\x1D\x1B\x18\xAA\x6C\x08\x32\x4B\x7D\x64\xB7\x1F\xB7\x63" + "\x70\x69\x0E\x1D"; + absl::string_view data(""); + + crypto::HMAC hmac(crypto::HMAC::SHA1); + ASSERT_TRUE(hmac.Init(nullptr, 0)); + + unsigned char digest[kSHA1DigestSize]; + EXPECT_TRUE(hmac.Sign(data, digest, kSHA1DigestSize)); + EXPECT_EQ(0, memcmp(kExpectedDigest, digest, kSHA1DigestSize)); + + EXPECT_TRUE( + hmac.Verify(data, absl::string_view(kExpectedDigest, kSHA1DigestSize))); +} + +TEST(HMACTest, TooLong) { + // See RFC4231, section 4.7. + unsigned char key[131]; + for (size_t i = 0; i < sizeof(key); ++i) key[i] = 0xaa; + + std::string data = "Test Using Larger Than Block-Size Key - Hash Key First"; + static uint8_t kKnownHMACSHA256[] = { + 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}; + + crypto::HMAC hmac(crypto::HMAC::SHA256); + ASSERT_TRUE(hmac.Init(key, sizeof(key))); + + // Attempting to write too large of an HMAC is an error. + uint8_t calculated_hmac[kSHA256DigestSize + 1]; + EXPECT_FALSE(hmac.Sign(data, calculated_hmac, sizeof(calculated_hmac))); + + // Attempting to verify too large of an HMAC is an error. + memcpy(calculated_hmac, kKnownHMACSHA256, kSHA256DigestSize); + calculated_hmac[kSHA256DigestSize] = 0; + EXPECT_FALSE(hmac.VerifyTruncated( + data, + std::string(calculated_hmac, calculated_hmac + sizeof(calculated_hmac)))); +} + +TEST(HMACTest, Bytes) { + // See RFC4231, section 4.7. + std::vector<uint8_t> key(131, 0xaa); + std::string data_str = + "Test Using Larger Than Block-Size Key - Hash Key First"; + std::vector<uint8_t> data(data_str.begin(), data_str.end()); + static uint8_t kKnownHMACSHA256[] = { + 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}; + + crypto::HMAC hmac(crypto::HMAC::SHA256); + ASSERT_TRUE(hmac.Init(key)); + + uint8_t calculated_hmac[kSHA256DigestSize]; + ASSERT_TRUE(hmac.Sign(data, calculated_hmac)); + EXPECT_EQ(0, memcmp(kKnownHMACSHA256, calculated_hmac, kSHA256DigestSize)); + + EXPECT_TRUE(hmac.Verify(data, calculated_hmac)); + EXPECT_TRUE(hmac.VerifyTruncated( + data, absl::MakeSpan(calculated_hmac, kSHA256DigestSize / 2))); + + data[0]++; + EXPECT_FALSE(hmac.Verify(data, calculated_hmac)); + EXPECT_FALSE(hmac.VerifyTruncated( + data, absl::MakeSpan(calculated_hmac, kSHA256DigestSize / 2))); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/nearby_base.cc b/chromium/third_party/nearby/src/internal/crypto/nearby_base.cc new file mode 100644 index 00000000000..17683c9e693 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/nearby_base.cc @@ -0,0 +1,46 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/nearby_base.h" + +#include <cstddef> +#include <limits> +#include <string> + +#include "absl/types/span.h" +#include "internal/platform/logging.h" + +namespace nearbybase { + +char* WriteInto(std::string* str, size_t length_with_null) { + DCHECK_GE(length_with_null, 1u); + str->reserve(length_with_null); + str->resize(length_with_null - 1); + return &((*str)[0]); +} + +std::string HexEncode(const void* bytes, size_t size) { + static const char kHexChars[] = "0123456789ABCDEF"; + + // Each input byte creates two output hex characters. + std::string ret(size * 2, '\0'); + + for (size_t i = 0; i < size; ++i) { + char b = reinterpret_cast<const char*>(bytes)[i]; + ret[(i * 2)] = kHexChars[(b >> 4) & 0xf]; + ret[(i * 2) + 1] = kHexChars[b & 0xf]; + } + return ret; +} +} // namespace nearbybase diff --git a/chromium/third_party/nearby/src/internal/crypto/nearby_base.h b/chromium/third_party/nearby/src/internal/crypto/nearby_base.h new file mode 100644 index 00000000000..f47bf75df0c --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/nearby_base.h @@ -0,0 +1,56 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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. + +// This header file defines base utility functions needed by Nearby Sharing. +// They are from Chromium //base with no equivalence in Abseil or pre C++20 +// Standard C++ Library. + +#ifndef THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_NEARBY_BASE_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_NEARBY_BASE_H_ + +#include <cstddef> +#include <limits> +#include <string> + +#include "absl/types/span.h" + +namespace nearbybase { + +// Copying C++20 std::span implementation, but returns absl::Span and has no +// static extent template parameter. +template <typename T> +absl::Span<const uint8_t> as_bytes(absl::Span<T> s) noexcept { + return {reinterpret_cast<const uint8_t*>(s.data()), sizeof(T) * s.size()}; +} + +// Copy of Chromium base::WriteInto. +char* WriteInto(std::string* str, size_t length_with_null); + +// Copy of Chromium base::STLClearObject. +// Clears internal memory of an STL object. +// STL clear()/reserve(0) does not always free internal memory allocated +// This function uses swap/destructor to ensure the internal memory is freed. +template <class T> +void STLClearObject(T* obj) { + T tmp; + tmp.swap(*obj); + // Sometimes "T tmp" allocates objects with memory (arena implementation?). + // Hence using additional reserve(0) even if it doesn't always work. + obj->reserve(0); +} + +// Copy of Chrome base::HexEncode. +std::string HexEncode(const void* bytes, size_t size); +} // namespace nearbybase +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_NEARBY_BASE_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/openssl_util.cc b/chromium/third_party/nearby/src/internal/crypto/openssl_util.cc new file mode 100644 index 00000000000..1568612d91c --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/openssl_util.cc @@ -0,0 +1,62 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/openssl_util.h" + +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "absl/strings/string_view.h" +#include "internal/platform/logging.h" +#include <openssl/crypto.h> +#include <openssl/err.h> + +namespace crypto { + +namespace { + +// Callback routine for OpenSSL to print error messages. |str| is a +// NULL-terminated string of length |len| containing diagnostic information +// such as the library, function and reason for the error, the file and line +// where the error originated, plus potentially any context-specific +// information about the error. |context| contains a pointer to user-supplied +// data, which is currently unused. +// If this callback returns a value <= 0, OpenSSL will stop processing the +// error queue and return, otherwise it will continue calling this function +// until all errors have been removed from the queue. +int OpenSSLErrorCallback(const char* str, size_t len, void* context) { + NEARBY_LOGS(VERBOSE) << "\t" << absl::string_view(str, len); + return 1; +} + +} // namespace + +void EnsureOpenSSLInit() { + // CRYPTO_library_init may be safely called concurrently. + CRYPTO_library_init(); +} + +void ClearOpenSSLERRStack() { + if (NEARBY_LOG_IS_ON(VERBOSE)) { + uint32_t error_num = ERR_peek_error(); + if (error_num == 0) return; + ERR_print_errors_cb(&OpenSSLErrorCallback, nullptr); + } else { + ERR_clear_error(); + } +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/openssl_util.h b/chromium/third_party/nearby/src/internal/crypto/openssl_util.h new file mode 100644 index 00000000000..2ddb517ace8 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/openssl_util.h @@ -0,0 +1,104 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_OPENSSL_UTIL_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_OPENSSL_UTIL_H_ + +#include <stddef.h> +#include <string.h> + +#include "internal/crypto/crypto_export.h" +#include "internal/platform/logging.h" + +namespace crypto { + +// Provides a buffer of at least MIN_SIZE bytes, for use when calling OpenSSL's +// SHA256, HMAC, etc functions, adapting the buffer sizing rules to meet those +// of our base wrapper APIs. +// This allows the library to write directly to the caller's buffer if it is of +// sufficient size, but if not it will write to temporary |min_sized_buffer_| +// of required size and then its content is automatically copied out on +// destruction, with truncation as appropriate. +template <int MIN_SIZE> +class ScopedOpenSSLSafeSizeBuffer { + public: + ScopedOpenSSLSafeSizeBuffer(unsigned char* output, size_t output_len) + : output_(output), output_len_(output_len) {} + + ScopedOpenSSLSafeSizeBuffer(const ScopedOpenSSLSafeSizeBuffer&) = delete; + ScopedOpenSSLSafeSizeBuffer& operator=(const ScopedOpenSSLSafeSizeBuffer&) = + delete; + + ~ScopedOpenSSLSafeSizeBuffer() { + if (output_len_ < MIN_SIZE) { + // Copy the temporary buffer out, truncating as needed. + memcpy(output_, min_sized_buffer_, output_len_); + } + // else... any writing already happened directly into |output_|. + } + + unsigned char* safe_buffer() { + return output_len_ < MIN_SIZE ? min_sized_buffer_ : output_; + } + + private: + // Pointer to the caller's data area and its associated size, where data + // written via safe_buffer() will [eventually] end up. + unsigned char* output_; + size_t output_len_; + + // Temporary buffer written into in the case where the caller's + // buffer is not of sufficient size. + unsigned char min_sized_buffer_[MIN_SIZE]; +}; + +// Initialize OpenSSL if it isn't already initialized. This must be called +// before any other OpenSSL functions though it is safe and cheap to call this +// multiple times. +// This function is thread-safe, and OpenSSL will only ever be initialized once. +// OpenSSL will be properly shut down on program exit. +CRYPTO_EXPORT void EnsureOpenSSLInit(); + +// Drains the OpenSSL ERR_get_error stack. On a debug build the error codes +// are send to VLOG(1), on a release build they are disregarded. In most +// cases you should pass absl::SourceLocation::current() as the |location|. +// TODO(b/239260254): Currently source_location.h is not available in OSS. +// We can not use std::SourceLocation as it is C++20. Once we move to C++20 or +// absl::SourceLocation is in OSS, add back "location". +// See google3/third_party/castlite/agent/crypto/openssl_util.h for reference. +CRYPTO_EXPORT void ClearOpenSSLERRStack(); + +// Place an instance of this class on the call stack to automatically clear +// the OpenSSL error stack on function exit. +class OpenSSLErrStackTracer { + public: + // Pass absl::SourceLocation::current() as |location|, to help track the + // source of OpenSSL error messages. Note any diagnostic emitted will be + // tagged with the location of the constructor call as it's not possible to + // trace a destructor's callsite. + // TODO(b/239260254): Currently source_location.h is not available in OSS. + // We can not use std::SourceLocation as it is C++20. Once we move to C++20 or + // absl::SourceLocation is in OSS, add back "location". + // See google3/third_party/castlite/agent/crypto/openssl_util.h for reference. + OpenSSLErrStackTracer() { EnsureOpenSSLInit(); } + + OpenSSLErrStackTracer(const OpenSSLErrStackTracer&) = delete; + OpenSSLErrStackTracer& operator=(const OpenSSLErrStackTracer&) = delete; + + ~OpenSSLErrStackTracer() { ClearOpenSSLERRStack(); } +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_OPENSSL_UTIL_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/random.cc b/chromium/third_party/nearby/src/internal/crypto/random.cc new file mode 100644 index 00000000000..6f68e7b50bb --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/random.cc @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/random.h" + +#include <stddef.h> + +#include <openssl/rand.h> + +namespace crypto { + +void RandBytes(void *bytes, size_t length) { + RAND_bytes(reinterpret_cast<uint8_t *>(bytes), length); +} + +void RandBytes(absl::Span<uint8_t> bytes) { + RandBytes(bytes.data(), bytes.size()); +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/random.h b/chromium/third_party/nearby/src/internal/crypto/random.h new file mode 100644 index 00000000000..72adde00fc6 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/random.h @@ -0,0 +1,34 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ + +#include <stddef.h> + +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// Fills the given buffer with |length| random bytes of cryptographically +// secure random numbers. +// |length| must be positive. +CRYPTO_EXPORT void RandBytes(void *bytes, size_t length); + +// Fills |bytes| with cryptographically-secure random bits. +CRYPTO_EXPORT void RandBytes(absl::Span<uint8_t> bytes); +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/random_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/random_unittest.cc new file mode 100644 index 00000000000..3854da62afb --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/random_unittest.cc @@ -0,0 +1,41 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/random.h" + +#include <stddef.h> + +#include <string> + +#include "gtest/gtest.h" +#include "internal/crypto/nearby_base.h" + +// Basic functionality tests. Does NOT test the security of the random data. + +// Ensures we don't have all trivial data, i.e. that the data is indeed random. +// Currently, that means the bytes cannot be all the same (e.g. all zeros). +bool IsTrivial(const std::string& bytes) { + for (size_t i = 0; i < bytes.size(); i++) { + if (bytes[i] != bytes[0]) { + return false; + } + } + return true; +} + +TEST(RandBytes, RandBytes) { + std::string bytes(16, '\0'); + crypto::RandBytes(nearbybase::WriteInto(&bytes, bytes.size()), bytes.size()); + EXPECT_TRUE(!IsTrivial(bytes)); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.cc b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.cc new file mode 100644 index 00000000000..57e7b1c1acf --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.cc @@ -0,0 +1,122 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/rsa_private_key.h" + +#include <stdint.h> + +#include <memory> +#include <utility> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/openssl_util.h" +#include "internal/platform/logging.h" +#include <openssl/bn.h> +#include <openssl/bytestring.h> +#include <openssl/evp.h> +#include <openssl/mem.h> +#include <openssl/rsa.h> + +namespace crypto { + +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::Create(uint16_t num_bits) { + OpenSSLErrStackTracer err_tracer; + + bssl::UniquePtr<RSA> rsa_key(RSA_new()); + bssl::UniquePtr<BIGNUM> bn(BN_new()); + if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L)) + return nullptr; + + if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), nullptr)) + return nullptr; + + std::unique_ptr<RSAPrivateKey> result(new RSAPrivateKey); + result->key_.reset(EVP_PKEY_new()); + if (!result->key_ || !EVP_PKEY_set1_RSA(result->key_.get(), rsa_key.get())) + return nullptr; + + return result; +} + +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromPrivateKeyInfo( + absl::Span<const uint8_t> input) { + OpenSSLErrStackTracer err_tracer; + + CBS cbs; + CBS_init(&cbs, input.data(), input.size()); + bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_private_key(&cbs)); + if (!pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) + return nullptr; + + std::unique_ptr<RSAPrivateKey> result(new RSAPrivateKey); + result->key_ = std::move(pkey); + return result; +} + +// static +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::CreateFromKey(EVP_PKEY* key) { + DCHECK(key); + if (EVP_PKEY_id(key) != EVP_PKEY_RSA) return nullptr; + std::unique_ptr<RSAPrivateKey> copy(new RSAPrivateKey); + copy->key_ = bssl::UpRef(key); + return copy; +} + +RSAPrivateKey::RSAPrivateKey() = default; + +RSAPrivateKey::~RSAPrivateKey() = default; + +std::unique_ptr<RSAPrivateKey> RSAPrivateKey::Copy() const { + std::unique_ptr<RSAPrivateKey> copy(new RSAPrivateKey); + bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(key_.get())); + if (!rsa) return nullptr; + copy->key_.reset(EVP_PKEY_new()); + if (!EVP_PKEY_set1_RSA(copy->key_.get(), rsa.get())) return nullptr; + return copy; +} + +bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer; + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_private_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const { + OpenSSLErrStackTracer err_tracer; + uint8_t* der; + size_t der_len; + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_public_key(cbb.get(), key_.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { + return false; + } + output->assign(der, der + der_len); + OPENSSL_free(der); + return true; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.h b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.h new file mode 100644 index 00000000000..58a8e986f11 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key.h @@ -0,0 +1,74 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RSA_PRIVATE_KEY_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RSA_PRIVATE_KEY_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" +#include <openssl/base.h> + +namespace crypto { + +// Encapsulates an RSA private key. Can be used to generate new keys, export +// keys to other formats, or to extract a public key. +// TODO(hclam): This class should be ref-counted so it can be reused easily. +class CRYPTO_EXPORT RSAPrivateKey { + public: + RSAPrivateKey(const RSAPrivateKey&) = delete; + RSAPrivateKey& operator=(const RSAPrivateKey&) = delete; + + ~RSAPrivateKey(); + + // Create a new random instance. Can return NULL if initialization fails. + static std::unique_ptr<RSAPrivateKey> Create(uint16_t num_bits); + + // Create a new instance by importing an existing private key. The format is + // an ASN.1-encoded PrivateKeyInfo block from PKCS #8. This can return NULL if + // initialization fails. + static std::unique_ptr<RSAPrivateKey> CreateFromPrivateKeyInfo( + absl::Span<const uint8_t> input); + + // Create a new instance from an existing EVP_PKEY, taking a + // reference to it. |key| must be an RSA key. Returns NULL on + // failure. + static std::unique_ptr<RSAPrivateKey> CreateFromKey(EVP_PKEY* key); + + EVP_PKEY* key() const { return key_.get(); } + + // Creates a copy of the object. + std::unique_ptr<RSAPrivateKey> Copy() const; + + // Exports the private key to a PKCS #8 PrivateKeyInfo block. + bool ExportPrivateKey(std::vector<uint8_t>* output) const; + + // Exports the public key to an X509 SubjectPublicKeyInfo block. + bool ExportPublicKey(std::vector<uint8_t>* output) const; + + private: + // Constructor is private. Use one of the Create*() methods above instead. + RSAPrivateKey(); + + bssl::UniquePtr<EVP_PKEY> key_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RSA_PRIVATE_KEY_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/rsa_private_key_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key_unittest.cc new file mode 100644 index 00000000000..bfe25b49688 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/rsa_private_key_unittest.cc @@ -0,0 +1,386 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/rsa_private_key.h" + +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "gtest/gtest.h" + +namespace { + +const uint8_t kTestPrivateKeyInfo[] = { + 0x30, 0x82, 0x02, 0x78, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x62, 0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, 0x0c, 0xdc, 0x51, 0x61, + 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, 0x55, 0x84, 0xd5, 0x3a, + 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, 0x13, 0x3f, 0x8d, 0xf4, + 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, 0xb0, 0x40, 0x53, 0x3a, + 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, 0xda, 0x8a, 0x31, 0x4f, + 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, 0xde, 0x4e, 0xb9, 0x57, + 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, 0x4e, 0xb6, 0x47, 0xff, + 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, 0x84, 0x32, 0x33, 0xf3, + 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, 0x6f, 0x13, 0x8d, 0xc5, + 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, 0x53, 0x56, 0xa6, 0x83, + 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, 0x0f, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x03, 0x61, 0x89, 0x37, 0xcb, 0xf2, 0x98, + 0xa0, 0xce, 0xb4, 0xcb, 0x16, 0x13, 0xf0, 0xe6, 0xaf, 0x5c, 0xc5, 0xa7, + 0x69, 0x71, 0xca, 0xba, 0x8d, 0xe0, 0x4d, 0xdd, 0xed, 0xb8, 0x48, 0x8b, + 0x16, 0x93, 0x36, 0x95, 0xc2, 0x91, 0x40, 0x65, 0x17, 0xbd, 0x7f, 0xd6, + 0xad, 0x9e, 0x30, 0x28, 0x46, 0xe4, 0x3e, 0xcc, 0x43, 0x78, 0xf9, 0xfe, + 0x1f, 0x33, 0x23, 0x1e, 0x31, 0x12, 0x9d, 0x3c, 0xa7, 0x08, 0x82, 0x7b, + 0x7d, 0x25, 0x4e, 0x5e, 0x19, 0xa8, 0x9b, 0xed, 0x86, 0xb2, 0xcb, 0x3c, + 0xfe, 0x4e, 0xa1, 0xfa, 0x62, 0x87, 0x3a, 0x17, 0xf7, 0x60, 0xec, 0x38, + 0x29, 0xe8, 0x4f, 0x34, 0x9f, 0x76, 0x9d, 0xee, 0xa3, 0xf6, 0x85, 0x6b, + 0x84, 0x43, 0xc9, 0x1e, 0x01, 0xff, 0xfd, 0xd0, 0x29, 0x4c, 0xfa, 0x8e, + 0x57, 0x0c, 0xc0, 0x71, 0xa5, 0xbb, 0x88, 0x46, 0x29, 0x5c, 0xc0, 0x4f, + 0x01, 0x02, 0x41, 0x00, 0xf5, 0x83, 0xa4, 0x64, 0x4a, 0xf2, 0xdd, 0x8c, + 0x2c, 0xed, 0xa8, 0xd5, 0x60, 0x5a, 0xe4, 0xc7, 0xcc, 0x61, 0xcd, 0x38, + 0x42, 0x20, 0xd3, 0x82, 0x18, 0xf2, 0x35, 0x00, 0x72, 0x2d, 0xf7, 0x89, + 0x80, 0x67, 0xb5, 0x93, 0x05, 0x5f, 0xdd, 0x42, 0xba, 0x16, 0x1a, 0xea, + 0x15, 0xc6, 0xf0, 0xb8, 0x8c, 0xbc, 0xbf, 0x54, 0x9e, 0xf1, 0xc1, 0xb2, + 0xb3, 0x8b, 0xb6, 0x26, 0x02, 0x30, 0xc4, 0x81, 0x02, 0x41, 0x00, 0xc0, + 0x60, 0x62, 0x80, 0xe1, 0x22, 0x78, 0xf6, 0x9d, 0x83, 0x18, 0xeb, 0x72, + 0x45, 0xd7, 0xc8, 0x01, 0x7f, 0xa9, 0xca, 0x8f, 0x7d, 0xd6, 0xb8, 0x31, + 0x2b, 0x84, 0x7f, 0x62, 0xd9, 0xa9, 0x22, 0x17, 0x7d, 0x06, 0x35, 0x6c, + 0xf3, 0xc1, 0x94, 0x17, 0x85, 0x5a, 0xaf, 0x9c, 0x5c, 0x09, 0x3c, 0xcf, + 0x2f, 0x44, 0x9d, 0xb6, 0x52, 0x68, 0x5f, 0xf9, 0x59, 0xc8, 0x84, 0x2b, + 0x39, 0x22, 0x8f, 0x02, 0x41, 0x00, 0xb2, 0x04, 0xe2, 0x0e, 0x56, 0xca, + 0x03, 0x1a, 0xc0, 0xf9, 0x12, 0x92, 0xa5, 0x6b, 0x42, 0xb8, 0x1c, 0xda, + 0x4d, 0x93, 0x9d, 0x5f, 0x6f, 0xfd, 0xc5, 0x58, 0xda, 0x55, 0x98, 0x74, + 0xfc, 0x28, 0x17, 0x93, 0x1b, 0x75, 0x9f, 0x50, 0x03, 0x7f, 0x7e, 0xae, + 0xc8, 0x95, 0x33, 0x75, 0x2c, 0xd6, 0xa4, 0x35, 0xb8, 0x06, 0x03, 0xba, + 0x08, 0x59, 0x2b, 0x17, 0x02, 0xdc, 0x4c, 0x7a, 0x50, 0x01, 0x02, 0x41, + 0x00, 0x9d, 0xdb, 0x39, 0x59, 0x09, 0xe4, 0x30, 0xa0, 0x24, 0xf5, 0xdb, + 0x2f, 0xf0, 0x2f, 0xf1, 0x75, 0x74, 0x0d, 0x5e, 0xb5, 0x11, 0x73, 0xb0, + 0x0a, 0xaa, 0x86, 0x4c, 0x0d, 0xff, 0x7e, 0x1d, 0xb4, 0x14, 0xd4, 0x09, + 0x91, 0x33, 0x5a, 0xfd, 0xa0, 0x58, 0x80, 0x9b, 0xbe, 0x78, 0x2e, 0x69, + 0x82, 0x15, 0x7c, 0x72, 0xf0, 0x7b, 0x18, 0x39, 0xff, 0x6e, 0xeb, 0xc6, + 0x86, 0xf5, 0xb4, 0xc7, 0x6f, 0x02, 0x41, 0x00, 0x8d, 0x1a, 0x37, 0x0f, + 0x76, 0xc4, 0x82, 0xfa, 0x5c, 0xc3, 0x79, 0x35, 0x3e, 0x70, 0x8a, 0xbf, + 0x27, 0x49, 0xb0, 0x99, 0x63, 0xcb, 0x77, 0x5f, 0xa8, 0x82, 0x65, 0xf6, + 0x03, 0x52, 0x51, 0xf1, 0xae, 0x2e, 0x05, 0xb3, 0xc6, 0xa4, 0x92, 0xd1, + 0xce, 0x6c, 0x72, 0xfb, 0x21, 0xb3, 0x02, 0x87, 0xe4, 0xfd, 0x61, 0xca, + 0x00, 0x42, 0x19, 0xf0, 0xda, 0x5a, 0x53, 0xe3, 0xb1, 0xc5, 0x15, 0xf3}; + +} // namespace + +// Generate random private keys with two different sizes. Reimport, then +// export them again. We should get back the same exact bytes. +TEST(RSAPrivateKeyUnitTest, InitRandomTest) { + std::unique_ptr<crypto::RSAPrivateKey> keypair1( + crypto::RSAPrivateKey::Create(1024)); + std::unique_ptr<crypto::RSAPrivateKey> keypair2( + crypto::RSAPrivateKey::Create(2048)); + ASSERT_TRUE(keypair1.get()); + ASSERT_TRUE(keypair2.get()); + + std::vector<uint8_t> privkey1; + std::vector<uint8_t> privkey2; + std::vector<uint8_t> pubkey1; + std::vector<uint8_t> pubkey2; + + ASSERT_TRUE(keypair1->ExportPrivateKey(&privkey1)); + ASSERT_TRUE(keypair2->ExportPrivateKey(&privkey2)); + ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1)); + ASSERT_TRUE(keypair2->ExportPublicKey(&pubkey2)); + + std::unique_ptr<crypto::RSAPrivateKey> keypair3( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey1)); + std::unique_ptr<crypto::RSAPrivateKey> keypair4( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(privkey2)); + ASSERT_TRUE(keypair3.get()); + ASSERT_TRUE(keypair4.get()); + + std::vector<uint8_t> privkey3; + std::vector<uint8_t> privkey4; + ASSERT_TRUE(keypair3->ExportPrivateKey(&privkey3)); + ASSERT_TRUE(keypair4->ExportPrivateKey(&privkey4)); + + ASSERT_EQ(privkey1.size(), privkey3.size()); + ASSERT_EQ(privkey2.size(), privkey4.size()); + ASSERT_EQ(0, memcmp(&privkey1.front(), &privkey3.front(), privkey1.size())); + ASSERT_EQ(0, memcmp(&privkey2.front(), &privkey4.front(), privkey2.size())); +} + +// Test Copy() method. +TEST(RSAPrivateKeyUnitTest, CopyTest) { + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + std::unique_ptr<crypto::RSAPrivateKey> key_copy(key->Copy()); + ASSERT_TRUE(key_copy.get()); + + std::vector<uint8_t> privkey_copy; + ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy)); + ASSERT_EQ(input, privkey_copy); +} + +// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA +// key. +TEST(RSAPrivateKeyUnitTest, ExtraData) { + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + input.push_back(0); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail. + EXPECT_FALSE(key); +} + +TEST(RSAPrivateKeyUnitTest, NotRsaKey) { + // Defines a valid P-256 private key. + const uint8_t kTestEcPrivateKeyInfo[] = { + 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x03, 0x01, 0x07, 0x04, 0x6D, 0x30, 0x6B, 0x02, 0x01, 0x01, 0x04, 0x20, + 0x1F, 0xE3, 0x39, 0x50, 0xC5, 0xF4, 0x61, 0x12, 0x4A, 0xE9, 0x92, 0xC2, + 0xBD, 0xFD, 0xF1, 0xC7, 0x3B, 0x16, 0x15, 0xF5, 0x71, 0xBD, 0x56, 0x7E, + 0x60, 0xD1, 0x9A, 0xA1, 0xF4, 0x8C, 0xDF, 0x42, 0xA1, 0x44, 0x03, 0x42, + 0x00, 0x04, 0x7C, 0x11, 0x0C, 0x66, 0xDC, 0xFD, 0xA8, 0x07, 0xF6, 0xE6, + 0x9E, 0x45, 0xDD, 0xB3, 0xC7, 0x4F, 0x69, 0xA1, 0x48, 0x4D, 0x20, 0x3E, + 0x8D, 0xC5, 0xAD, 0xA8, 0xE9, 0xA9, 0xDD, 0x7C, 0xB3, 0xC7, 0x0D, 0xF4, + 0x48, 0x98, 0x6E, 0x51, 0xBD, 0xE5, 0xD1, 0x57, 0x6F, 0x99, 0x90, 0x1F, + 0x9C, 0x2C, 0x6A, 0x80, 0x6A, 0x47, 0xFD, 0x90, 0x76, 0x43, 0xA7, 0x2B, + 0x83, 0x55, 0x97, 0xEF, 0xC8, 0xC6}; + + std::vector<uint8_t> input( + kTestEcPrivateKeyInfo, + kTestEcPrivateKeyInfo + sizeof(kTestEcPrivateKeyInfo)); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + + // Import should fail as the given PKCS8 bytes were for an EC key not RSA key. + EXPECT_FALSE(key); +} + +// Verify that generated public keys look good. This test data was generated +// with the openssl command line tool. +TEST(RSAPrivateKeyUnitTest, PublicKeyTest) { + const uint8_t expected_public_key_info[] = { + 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xb8, 0x7f, 0x2b, 0x20, 0xdc, 0x7c, 0x9b, + 0x0c, 0xdc, 0x51, 0x61, 0x99, 0x0d, 0x36, 0x0f, 0xd4, 0x66, 0x88, 0x08, + 0x55, 0x84, 0xd5, 0x3a, 0xbf, 0x2b, 0xa4, 0x64, 0x85, 0x7b, 0x0c, 0x04, + 0x13, 0x3f, 0x8d, 0xf4, 0xbc, 0x38, 0x0d, 0x49, 0xfe, 0x6b, 0xc4, 0x5a, + 0xb0, 0x40, 0x53, 0x3a, 0xd7, 0x66, 0x09, 0x0f, 0x9e, 0x36, 0x74, 0x30, + 0xda, 0x8a, 0x31, 0x4f, 0x1f, 0x14, 0x50, 0xd7, 0xc7, 0x20, 0x94, 0x17, + 0xde, 0x4e, 0xb9, 0x57, 0x5e, 0x7e, 0x0a, 0xe5, 0xb2, 0x65, 0x7a, 0x89, + 0x4e, 0xb6, 0x47, 0xff, 0x1c, 0xbd, 0xb7, 0x38, 0x13, 0xaf, 0x47, 0x85, + 0x84, 0x32, 0x33, 0xf3, 0x17, 0x49, 0xbf, 0xe9, 0x96, 0xd0, 0xd6, 0x14, + 0x6f, 0x13, 0x8d, 0xc5, 0xfc, 0x2c, 0x72, 0xba, 0xac, 0xea, 0x7e, 0x18, + 0x53, 0x56, 0xa6, 0x83, 0xa2, 0xce, 0x93, 0x93, 0xe7, 0x1f, 0x0f, 0xe6, + 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01}; + + std::vector<uint8_t> input(kTestPrivateKeyInfo, + kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo)); + + std::unique_ptr<crypto::RSAPrivateKey> key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input)); + ASSERT_TRUE(key.get()); + + std::vector<uint8_t> output; + ASSERT_TRUE(key->ExportPublicKey(&output)); + + ASSERT_EQ(0, + memcmp(expected_public_key_info, &output.front(), output.size())); +} + +// These two test keys each contain an integer that has 0x00 for its most +// significant byte. When encoded as ASN.1, this byte is dropped and there are +// two interesting sub-cases. When the sign bit of the integer is set, an extra +// null byte is added back to force the encoded value to be positive. When the +// sign bit is not set, the encoded integer is just left shorter than usual. +// See also: http://code.google.com/p/chromium/issues/detail?id=14877. +// +// Before we were handling this correctly, we would see one of two failures: +// * RSAPrivateKey::CreateFromPrivateKeyInfo would return null because the +// underlying windows API failed to import the key. +// * The import would succeed, but incorrectly interpret the data. On export, +// the key would contain different values. +// +// This test case verifies these two failures modes don't occur. +TEST(RSAPrivateKeyUnitTest, ShortIntegers) { + const uint8_t short_integer_with_high_bit[] = { + 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0x92, 0x59, 0x32, 0x7d, 0x8e, 0xaf, 0x2e, 0xd5, 0xb2, 0x5c, 0x67, + 0xc8, 0x7d, 0x48, 0xb7, 0x84, 0x12, 0xd0, 0x76, 0xda, 0xe1, 0xa3, 0x1e, + 0x40, 0x01, 0x14, 0x5c, 0xef, 0x26, 0x6e, 0x28, 0xa2, 0xf7, 0xa5, 0xb4, + 0x02, 0x37, 0xd0, 0x53, 0x10, 0xcb, 0x7c, 0x6a, 0xf4, 0x53, 0x9f, 0xb8, + 0xe0, 0x83, 0x93, 0xd1, 0x19, 0xd8, 0x28, 0xd1, 0xd1, 0xd8, 0x87, 0x8f, + 0x92, 0xfd, 0x73, 0xc0, 0x4d, 0x3e, 0x07, 0x22, 0x1f, 0xc1, 0x20, 0xb0, + 0x70, 0xb2, 0x3b, 0xea, 0xb1, 0xe5, 0x0a, 0xfd, 0x56, 0x49, 0x5e, 0x39, + 0x90, 0x91, 0xce, 0x04, 0x83, 0x29, 0xaa, 0xfd, 0x12, 0xa4, 0x42, 0x26, + 0x6c, 0x6e, 0x79, 0x70, 0x77, 0x03, 0xb2, 0x07, 0x01, 0x3d, 0x85, 0x81, + 0x95, 0x9e, 0xda, 0x5a, 0xa3, 0xf4, 0x2d, 0x38, 0x04, 0x58, 0xf5, 0x6b, + 0xc9, 0xf1, 0xb5, 0x65, 0xfe, 0x66, 0x0d, 0xa2, 0xd5, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x5e, 0x01, 0x5f, 0xb6, 0x59, 0x1d, 0xdc, + 0x36, 0xb6, 0x60, 0x36, 0xe6, 0x08, 0xdb, 0xd9, 0xcd, 0xc3, 0x8c, 0x16, + 0x9c, 0x98, 0x8d, 0x7f, 0xd3, 0xdb, 0x1d, 0xaa, 0x68, 0x8f, 0xc5, 0xf8, + 0xe2, 0x5d, 0xb3, 0x19, 0xc2, 0xc6, 0xf9, 0x51, 0x32, 0x1b, 0x93, 0x6a, + 0xdc, 0x50, 0x8e, 0xeb, 0x61, 0x84, 0x03, 0x42, 0x30, 0x98, 0xb1, 0xf7, + 0xbd, 0x14, 0x9a, 0x57, 0x36, 0x33, 0x09, 0xd4, 0x3e, 0x90, 0xda, 0xef, + 0x09, 0x6e, 0xef, 0x49, 0xb6, 0x60, 0x68, 0x5e, 0x54, 0x17, 0x25, 0x5b, + 0x37, 0xe3, 0x35, 0x63, 0x5b, 0x60, 0x3c, 0xbd, 0x50, 0xdf, 0x46, 0x43, + 0x08, 0xa4, 0x71, 0x21, 0xf1, 0x30, 0x71, 0xdc, 0xda, 0xd7, 0x6f, 0xd2, + 0x18, 0xbd, 0x39, 0xf1, 0xe1, 0xbe, 0xa8, 0x8d, 0x62, 0xdf, 0xa2, 0x3e, + 0xb6, 0x15, 0x26, 0xb6, 0x57, 0xbd, 0x63, 0xdb, 0xc1, 0x91, 0xec, 0xb8, + 0x01, 0x02, 0x41, 0x00, 0xc6, 0x1a, 0x06, 0x48, 0xf2, 0x12, 0x1c, 0x9f, + 0x74, 0x20, 0x5c, 0x85, 0xa2, 0xda, 0xe5, 0x62, 0x96, 0x8d, 0x22, 0x7b, + 0x78, 0x73, 0xea, 0xbb, 0x9f, 0x59, 0x42, 0x13, 0x15, 0xc8, 0x11, 0x50, + 0x6c, 0x55, 0xf6, 0xdf, 0x8b, 0xfe, 0xc7, 0xdd, 0xa8, 0xca, 0x54, 0x41, + 0xe8, 0xce, 0xbe, 0x7d, 0xbd, 0xe2, 0x13, 0x4b, 0x5b, 0x61, 0xeb, 0x69, + 0x6c, 0xb1, 0x9b, 0x28, 0x68, 0x5b, 0xd6, 0x01, 0x02, 0x41, 0x00, 0xbd, + 0x1e, 0xfe, 0x51, 0x99, 0xb6, 0xe3, 0x84, 0xfe, 0xf1, 0x9e, 0xfd, 0x9c, + 0xe7, 0x86, 0x43, 0x68, 0x7f, 0x2f, 0x6a, 0x2a, 0x4c, 0xae, 0xa6, 0x41, + 0x1c, 0xf0, 0x10, 0x37, 0x54, 0x23, 0xba, 0x05, 0x0d, 0x18, 0x27, 0x8d, + 0xb8, 0xe4, 0x8f, 0xf2, 0x25, 0x73, 0x8a, 0xd7, 0x05, 0x98, 0x6b, 0x3d, + 0x55, 0xb7, 0x6f, 0x7c, 0xec, 0x77, 0x61, 0x54, 0x7b, 0xb6, 0x6b, 0x31, + 0xec, 0x94, 0xd5, 0x02, 0x41, 0x00, 0x90, 0xa2, 0xa5, 0x9e, 0x12, 0xa7, + 0x68, 0xa0, 0x7e, 0xdf, 0xb5, 0xcd, 0x98, 0x26, 0xab, 0xbd, 0xbc, 0x5f, + 0xd5, 0x22, 0x42, 0xc2, 0x97, 0x4a, 0x5f, 0x40, 0x82, 0xfe, 0x7e, 0x33, + 0xb1, 0x78, 0x7f, 0x70, 0x90, 0x2b, 0x8d, 0x01, 0xfb, 0x18, 0xfa, 0x48, + 0xa7, 0x15, 0xec, 0x0d, 0x2e, 0x85, 0x8d, 0xe2, 0x86, 0xe5, 0xc9, 0x15, + 0x88, 0x14, 0x53, 0xd8, 0xa4, 0x88, 0xef, 0x10, 0xc6, 0x01, 0x02, 0x41, + 0x00, 0xba, 0xe4, 0xaf, 0x14, 0xfa, 0xdf, 0xf6, 0xd5, 0xce, 0x8f, 0xfe, + 0xbb, 0xc8, 0x5c, 0x30, 0x9d, 0xda, 0xdd, 0x9d, 0x80, 0xc0, 0x0e, 0x89, + 0xa5, 0xb8, 0xc1, 0x1d, 0x28, 0x19, 0x55, 0x67, 0xfd, 0x03, 0xd2, 0xdd, + 0xe4, 0xf0, 0xb4, 0x20, 0x03, 0x74, 0x9b, 0xb8, 0x24, 0x23, 0xbb, 0xde, + 0xd5, 0x53, 0x86, 0xaa, 0xc1, 0x5d, 0x65, 0xdd, 0xcf, 0xec, 0x8a, 0x59, + 0x4a, 0x73, 0xca, 0xc5, 0x85, 0x02, 0x40, 0x00, 0xc4, 0x5e, 0x8d, 0xa4, + 0xea, 0xbb, 0x6a, 0x9b, 0xe6, 0x3a, 0x4d, 0xc1, 0xdb, 0xe5, 0x52, 0x38, + 0xf9, 0x59, 0x91, 0x2d, 0x90, 0x82, 0xe3, 0x31, 0x1b, 0x48, 0xb7, 0x42, + 0xfa, 0x1d, 0x83, 0xd5, 0x3d, 0x02, 0xc2, 0x12, 0x71, 0x10, 0x3a, 0xbd, + 0x92, 0x8f, 0x9b, 0xa2, 0x6b, 0x2d, 0x21, 0xa4, 0x65, 0xe9, 0xfa, 0x8c, + 0x30, 0x2a, 0x89, 0xce, 0xd0, 0xa7, 0x67, 0xd8, 0x45, 0x84, 0xb0}; + + const uint8_t short_integer_without_high_bit[] = { + 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xc3, 0x9e, 0x8d, 0xc4, 0x6d, 0x38, 0xe8, 0x0e, 0x9f, 0x84, 0x03, + 0x40, 0x8e, 0x81, 0x2e, 0x56, 0x67, 0x78, 0x11, 0x85, 0x27, 0x81, 0x52, + 0xf2, 0x1b, 0x3e, 0x5b, 0xf8, 0xab, 0xfc, 0xaf, 0xca, 0x5c, 0x26, 0xd5, + 0xfa, 0xd4, 0x55, 0x50, 0x38, 0xb9, 0x9d, 0x89, 0x92, 0x7e, 0x34, 0xcf, + 0x37, 0x82, 0x48, 0x2d, 0xaa, 0xc4, 0x6a, 0x0e, 0x93, 0xea, 0xad, 0x8a, + 0x33, 0xf0, 0x42, 0x23, 0xe0, 0x4c, 0x98, 0xbf, 0x01, 0x00, 0x1b, 0xfe, + 0x06, 0x15, 0xc6, 0xe3, 0x80, 0x79, 0x6d, 0xfe, 0x48, 0xcd, 0x40, 0xbb, + 0xf9, 0x58, 0xe6, 0xbf, 0xd5, 0x4c, 0x29, 0x48, 0x53, 0x78, 0x06, 0x03, + 0x0d, 0x59, 0xf5, 0x20, 0xe0, 0xe6, 0x8c, 0xb2, 0xf5, 0xd8, 0x61, 0x52, + 0x7e, 0x40, 0x83, 0xd7, 0x69, 0xae, 0xd7, 0x75, 0x02, 0x2d, 0x49, 0xd5, + 0x15, 0x5b, 0xf1, 0xd9, 0x4d, 0x60, 0x7d, 0x62, 0xa5, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x7f, 0x6d, 0x45, 0x23, 0xeb, 0x95, 0x17, 0x34, 0x88, + 0xf6, 0x91, 0xc7, 0x3f, 0x48, 0x5a, 0xe0, 0x87, 0x63, 0x44, 0xae, 0x84, + 0xb2, 0x8c, 0x8a, 0xc8, 0xb2, 0x6f, 0x22, 0xf0, 0xc5, 0x21, 0x61, 0x10, + 0xa8, 0x69, 0x09, 0x1e, 0x13, 0x7d, 0x94, 0x52, 0x1b, 0x5c, 0xe4, 0x7b, + 0xf0, 0x03, 0x8f, 0xbc, 0x72, 0x09, 0xdf, 0x78, 0x84, 0x3e, 0xb9, 0xe5, + 0xe6, 0x31, 0x0a, 0x01, 0xf9, 0x32, 0xf8, 0xd6, 0x57, 0xa3, 0x87, 0xe6, + 0xf5, 0x98, 0xbc, 0x8e, 0x41, 0xb9, 0x50, 0x17, 0x7b, 0xd3, 0x97, 0x5a, + 0x44, 0x3a, 0xee, 0xff, 0x6b, 0xb3, 0x3a, 0x52, 0xe7, 0xa4, 0x96, 0x9a, + 0xf6, 0x83, 0xc8, 0x97, 0x1c, 0x63, 0xa1, 0xd6, 0xb3, 0xa8, 0xb2, 0xc7, + 0x73, 0x25, 0x0f, 0x58, 0x36, 0xb9, 0x7a, 0x47, 0xa7, 0x4d, 0x30, 0xfe, + 0x4d, 0x74, 0x56, 0xe8, 0xfb, 0xd6, 0x50, 0xe5, 0xe0, 0x28, 0x15, 0x02, + 0x41, 0x00, 0xeb, 0x15, 0x62, 0xb6, 0x37, 0x41, 0x7c, 0xc5, 0x00, 0x22, + 0x2c, 0x5a, 0x5e, 0xe4, 0xb2, 0x11, 0x87, 0x89, 0xad, 0xf4, 0x57, 0x68, + 0x90, 0xb7, 0x9f, 0xe2, 0x79, 0x20, 0x6b, 0x98, 0x00, 0x0d, 0x3a, 0x3b, + 0xc1, 0xcd, 0x36, 0xf9, 0x27, 0xda, 0x40, 0x36, 0x1d, 0xb8, 0x5c, 0x96, + 0xeb, 0x04, 0x08, 0xe1, 0x3f, 0xfa, 0x94, 0x8b, 0x0f, 0xa0, 0xff, 0xc1, + 0x51, 0xea, 0x90, 0xad, 0x15, 0xc7, 0x02, 0x41, 0x00, 0xd5, 0x06, 0x45, + 0xd7, 0x55, 0x63, 0x1a, 0xf0, 0x89, 0x81, 0xae, 0x87, 0x23, 0xa2, 0x39, + 0xfe, 0x3d, 0x82, 0xc7, 0xcb, 0x15, 0xb9, 0xe3, 0xe2, 0x5b, 0xc6, 0xd2, + 0x55, 0xdd, 0xab, 0x55, 0x29, 0x7c, 0xda, 0x0e, 0x1c, 0x09, 0xfc, 0x73, + 0x0d, 0x01, 0xed, 0x6d, 0x2f, 0x05, 0xd0, 0xd5, 0x1d, 0xce, 0x18, 0x7f, + 0xb0, 0xc8, 0x47, 0x77, 0xd2, 0xa9, 0x9e, 0xfc, 0x39, 0x4b, 0x3d, 0x94, + 0x33, 0x02, 0x41, 0x00, 0x8f, 0x94, 0x09, 0x2d, 0x17, 0x44, 0x75, 0x0a, + 0xf1, 0x10, 0xee, 0x1b, 0xe7, 0xd7, 0x2f, 0xf6, 0xca, 0xdc, 0x49, 0x15, + 0x72, 0x09, 0x58, 0x51, 0xfe, 0x61, 0xd8, 0xee, 0xf7, 0x27, 0xe7, 0xe8, + 0x2c, 0x47, 0xf1, 0x0f, 0x00, 0x63, 0x5e, 0x76, 0xcb, 0x3f, 0x02, 0x19, + 0xe6, 0xda, 0xfa, 0x01, 0x05, 0xd7, 0x65, 0x37, 0x0b, 0x60, 0x7f, 0x94, + 0x2a, 0x80, 0x8d, 0x22, 0x81, 0x68, 0x65, 0x63, 0x02, 0x41, 0x00, 0xc2, + 0xd4, 0x18, 0xde, 0x47, 0x9e, 0xfb, 0x8d, 0x91, 0x05, 0xc5, 0x3c, 0x9d, + 0xcf, 0x8a, 0x60, 0xc7, 0x9b, 0x2b, 0xe5, 0xc6, 0xba, 0x1b, 0xfc, 0xf3, + 0xd9, 0x54, 0x97, 0xe9, 0xc4, 0x00, 0x80, 0x90, 0x4a, 0xd2, 0x6a, 0xbc, + 0x8b, 0x62, 0x22, 0x3c, 0x68, 0x0c, 0xda, 0xdb, 0xe3, 0xd2, 0x76, 0x8e, + 0xff, 0x03, 0x12, 0x09, 0x2a, 0xac, 0x21, 0x44, 0xb7, 0x3e, 0x91, 0x9c, + 0x09, 0xf6, 0xd7, 0x02, 0x41, 0x00, 0xc0, 0xa1, 0xbb, 0x70, 0xdc, 0xf8, + 0xeb, 0x17, 0x61, 0xd4, 0x8c, 0x7c, 0x3b, 0x82, 0x91, 0x58, 0xff, 0xf9, + 0x19, 0xac, 0x3a, 0x73, 0xa7, 0x20, 0xe5, 0x22, 0x02, 0xc4, 0xf6, 0xb9, + 0xb9, 0x43, 0x53, 0x35, 0x88, 0xe1, 0x05, 0xb6, 0x43, 0x9b, 0x39, 0xc8, + 0x04, 0x4d, 0x2b, 0x01, 0xf7, 0xe6, 0x1b, 0x8d, 0x7e, 0x89, 0xe3, 0x43, + 0xd4, 0xf3, 0xab, 0x28, 0xd4, 0x5a, 0x1f, 0x20, 0xea, 0xbe}; + + std::vector<uint8_t> input1; + std::vector<uint8_t> input2; + + input1.resize(sizeof(short_integer_with_high_bit)); + input2.resize(sizeof(short_integer_without_high_bit)); + + memcpy(&input1.front(), short_integer_with_high_bit, + sizeof(short_integer_with_high_bit)); + memcpy(&input2.front(), short_integer_without_high_bit, + sizeof(short_integer_without_high_bit)); + + std::unique_ptr<crypto::RSAPrivateKey> keypair1( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input1)); + std::unique_ptr<crypto::RSAPrivateKey> keypair2( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input2)); + ASSERT_TRUE(keypair1.get()); + ASSERT_TRUE(keypair2.get()); + + std::vector<uint8_t> output1; + std::vector<uint8_t> output2; + ASSERT_TRUE(keypair1->ExportPrivateKey(&output1)); + ASSERT_TRUE(keypair2->ExportPrivateKey(&output2)); + + ASSERT_EQ(input1.size(), output1.size()); + ASSERT_EQ(input2.size(), output2.size()); + ASSERT_EQ(0, memcmp(&output1.front(), &input1.front(), input1.size())); + ASSERT_EQ(0, memcmp(&output2.front(), &input2.front(), input2.size())); +} + +TEST(RSAPrivateKeyUnitTest, CreateFromKeyTest) { + std::unique_ptr<crypto::RSAPrivateKey> key_pair( + crypto::RSAPrivateKey::Create(512)); + ASSERT_TRUE(key_pair.get()); + + std::unique_ptr<crypto::RSAPrivateKey> key_copy( + crypto::RSAPrivateKey::CreateFromKey(key_pair->key())); + ASSERT_TRUE(key_copy.get()); + + std::vector<uint8_t> privkey; + std::vector<uint8_t> pubkey; + ASSERT_TRUE(key_pair->ExportPrivateKey(&privkey)); + ASSERT_TRUE(key_pair->ExportPublicKey(&pubkey)); + + std::vector<uint8_t> privkey_copy; + std::vector<uint8_t> pubkey_copy; + ASSERT_TRUE(key_copy->ExportPrivateKey(&privkey_copy)); + ASSERT_TRUE(key_copy->ExportPublicKey(&pubkey_copy)); + + ASSERT_EQ(privkey, privkey_copy); + ASSERT_EQ(pubkey, pubkey_copy); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/secure_hash.cc b/chromium/third_party/nearby/src/internal/crypto/secure_hash.cc new file mode 100644 index 00000000000..e950de1d67b --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/secure_hash.cc @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/secure_hash.h" + +#include <stddef.h> + +#include <memory> + +#include "internal/crypto/openssl_util.h" +#include <openssl/mem.h> +#include <openssl/sha.h> + +namespace crypto { + +namespace { + +class SecureHashSHA256 : public SecureHash { + public: + SecureHashSHA256() { + // Ensure that CPU features detection is performed before using + // BoringSSL. This will enable hw accelerated implementations. + EnsureOpenSSLInit(); + SHA256_Init(&ctx_); + } + + SecureHashSHA256(const SecureHashSHA256& other) { + memcpy(&ctx_, &other.ctx_, sizeof(ctx_)); + } + + ~SecureHashSHA256() override { OPENSSL_cleanse(&ctx_, sizeof(ctx_)); } + + void Update(const void* input, size_t len) override { + SHA256_Update(&ctx_, static_cast<const unsigned char*>(input), len); + } + + void Finish(void* output, size_t len) override { + ScopedOpenSSLSafeSizeBuffer<SHA256_DIGEST_LENGTH> result( + static_cast<unsigned char*>(output), len); + SHA256_Final(result.safe_buffer(), &ctx_); + } + + std::unique_ptr<SecureHash> Clone() const override { + return std::make_unique<SecureHashSHA256>(*this); + } + + size_t GetHashLength() const override { return SHA256_DIGEST_LENGTH; } + + private: + SHA256_CTX ctx_; +}; + +} // namespace + +std::unique_ptr<SecureHash> SecureHash::Create(Algorithm algorithm) { + switch (algorithm) { + case SHA256: + return std::make_unique<SecureHashSHA256>(); + default: + // NOTIMPLEMENTED(); + return nullptr; + } +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/secure_hash.h b/chromium/third_party/nearby/src/internal/crypto/secure_hash.h new file mode 100644 index 00000000000..32a30809691 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/secure_hash.h @@ -0,0 +1,57 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_HASH_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_HASH_H_ + +#include <stddef.h> + +#include <memory> + +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// A wrapper to calculate secure hashes incrementally, allowing to +// be used when the full input is not known in advance. The end result will the +// same as if we have the full input in advance. +class CRYPTO_EXPORT SecureHash { + public: + enum Algorithm { + SHA256, + }; + + SecureHash(const SecureHash&) = delete; + SecureHash& operator=(const SecureHash&) = delete; + + virtual ~SecureHash() {} + + static std::unique_ptr<SecureHash> Create(Algorithm type); + + virtual void Update(const void* input, size_t len) = 0; + virtual void Finish(void* output, size_t len) = 0; + virtual size_t GetHashLength() const = 0; + + // Create a clone of this SecureHash. The returned clone and this both + // represent the same hash state. But from this point on, calling + // Update()/Finish() on either doesn't affect the state of the other. + virtual std::unique_ptr<SecureHash> Clone() const = 0; + + protected: + SecureHash() {} +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_HASH_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/secure_hash_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/secure_hash_unittest.cc new file mode 100644 index 00000000000..94950328c7a --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/secure_hash_unittest.cc @@ -0,0 +1,117 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/secure_hash.h" + +#include <stddef.h> +#include <stdint.h> + +#include <memory> +#include <string> + +#include "gtest/gtest.h" +#include "internal/crypto/sha2.h" + +TEST(SecureHashTest, TestUpdate) { + // Example B.3 from FIPS 180-2: long message. + std::string input3(500000, 'a'); // 'a' repeated half a million times + const int kExpectedHashOfInput3[] = { + 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, + 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, + 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}; + + uint8_t output3[crypto::kSHA256Length]; + + std::unique_ptr<crypto::SecureHash> ctx( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + ctx->Update(input3.data(), input3.size()); + ctx->Update(input3.data(), input3.size()); + + ctx->Finish(output3, sizeof(output3)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(kExpectedHashOfInput3[i], static_cast<int>(output3[i])); +} + +TEST(SecureHashTest, TestClone) { + std::string input1(10001, 'a'); // 'a' repeated 10001 times + std::string input2(10001, 'd'); // 'd' repeated 10001 times + + const uint8_t kExpectedHashOfInput1[crypto::kSHA256Length] = { + 0x0c, 0xab, 0x99, 0xa0, 0x58, 0x60, 0x0f, 0xfa, 0xad, 0x12, 0x92, + 0xd0, 0xc5, 0x3c, 0x05, 0x48, 0xeb, 0xaf, 0x88, 0xdd, 0x1d, 0x01, + 0x03, 0x03, 0x45, 0x70, 0x5f, 0x01, 0x8a, 0x81, 0x39, 0x09}; + const uint8_t kExpectedHashOfInput1And2[crypto::kSHA256Length] = { + 0x4c, 0x8e, 0x26, 0x5a, 0xc3, 0x85, 0x1f, 0x1f, 0xa5, 0x04, 0x1c, + 0xc7, 0x88, 0x53, 0x1c, 0xc7, 0x80, 0x47, 0x15, 0xfb, 0x47, 0xff, + 0x72, 0xb1, 0x28, 0x37, 0xb0, 0x4d, 0x6e, 0x22, 0x2e, 0x4d}; + + uint8_t output1[crypto::kSHA256Length]; + uint8_t output2[crypto::kSHA256Length]; + uint8_t output3[crypto::kSHA256Length]; + + std::unique_ptr<crypto::SecureHash> ctx1( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + ctx1->Update(input1.data(), input1.size()); + + std::unique_ptr<crypto::SecureHash> ctx2(ctx1->Clone()); + std::unique_ptr<crypto::SecureHash> ctx3(ctx2->Clone()); + // At this point, ctx1, ctx2, and ctx3 are all equivalent and represent the + // state after hashing input1. + + // Updating ctx1 and ctx2 with input2 should produce equivalent results. + ctx1->Update(input2.data(), input2.size()); + ctx1->Finish(output1, sizeof(output1)); + + ctx2->Update(input2.data(), input2.size()); + ctx2->Finish(output2, sizeof(output2)); + + EXPECT_EQ(0, memcmp(output1, output2, crypto::kSHA256Length)); + EXPECT_EQ(0, + memcmp(output1, kExpectedHashOfInput1And2, crypto::kSHA256Length)); + + // Finish() ctx3, which should produce the hash of input1. + ctx3->Finish(&output3, sizeof(output3)); + EXPECT_EQ(0, memcmp(output3, kExpectedHashOfInput1, crypto::kSHA256Length)); +} + +TEST(SecureHashTest, TestLength) { + std::unique_ptr<crypto::SecureHash> ctx( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + EXPECT_EQ(crypto::kSHA256Length, ctx->GetHashLength()); +} + +TEST(SecureHashTest, Equality) { + std::string input1(10001, 'a'); // 'a' repeated 10001 times + std::string input2(10001, 'd'); // 'd' repeated 10001 times + + uint8_t output1[crypto::kSHA256Length]; + uint8_t output2[crypto::kSHA256Length]; + + // Call Update() twice on input1 and input2. + std::unique_ptr<crypto::SecureHash> ctx1( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + ctx1->Update(input1.data(), input1.size()); + ctx1->Update(input2.data(), input2.size()); + ctx1->Finish(output1, sizeof(output1)); + + // Call Update() once one input1 + input2 (concatenation). + std::unique_ptr<crypto::SecureHash> ctx2( + crypto::SecureHash::Create(crypto::SecureHash::SHA256)); + std::string input3 = input1 + input2; + ctx2->Update(input3.data(), input3.size()); + ctx2->Finish(output2, sizeof(output2)); + + // The hash should be the same. + EXPECT_EQ(0, memcmp(output1, output2, crypto::kSHA256Length)); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/secure_util.cc b/chromium/third_party/nearby/src/internal/crypto/secure_util.cc new file mode 100644 index 00000000000..9cc13b23c0c --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/secure_util.cc @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/secure_util.h" + +#include <openssl/mem.h> + +namespace crypto { + +bool SecureMemEqual(const void* s1, const void* s2, size_t n) { + return CRYPTO_memcmp(s1, s2, n) == 0; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/secure_util.h b/chromium/third_party/nearby/src/internal/crypto/secure_util.h new file mode 100644 index 00000000000..4db08bbe108 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/secure_util.h @@ -0,0 +1,38 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_UTIL_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_UTIL_H_ + +#include <stddef.h> + +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// Performs a constant-time comparison of two strings, returning true if the +// strings are equal. +// +// For cryptographic operations, comparison functions such as memcmp() may +// expose side-channel information about input, allowing an attacker to +// perform timing analysis to determine what the expected bits should be. In +// order to avoid such attacks, the comparison must execute in constant time, +// so as to not to reveal to the attacker where the difference(s) are. +// For an example attack, see +// http://groups.google.com/group/keyczar-discuss/browse_thread/thread/5571eca0948b2a13 +CRYPTO_EXPORT bool SecureMemEqual(const void* s1, const void* s2, size_t n); + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SECURE_UTIL_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/sha2.cc b/chromium/third_party/nearby/src/internal/crypto/sha2.cc new file mode 100644 index 00000000000..32f06b899ff --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/sha2.cc @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/sha2.h" + +#include <stddef.h> + +#include <array> +#include <memory> +#include <string> + +#include "absl/strings/string_view.h" +#include "internal/crypto/secure_hash.h" +#include <openssl/sha.h> + +namespace crypto { + +std::array<uint8_t, kSHA256Length> SHA256Hash(absl::Span<const uint8_t> input) { + std::array<uint8_t, kSHA256Length> digest; + ::SHA256(input.data(), input.size(), digest.data()); + return digest; +} + +void SHA256HashString(absl::string_view str, void* output, size_t len) { + std::unique_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256)); + ctx->Update(str.data(), str.length()); + ctx->Finish(output, len); +} + +std::string SHA256HashString(absl::string_view str) { + std::string output(kSHA256Length, 0); + SHA256HashString(str, &*output.begin(), output.size()); + return output; +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/sha2.h b/chromium/third_party/nearby/src/internal/crypto/sha2.h new file mode 100644 index 00000000000..301957172e7 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/sha2.h @@ -0,0 +1,51 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SHA2_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SHA2_H_ + +#include <stddef.h> + +#include <array> +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// These functions perform SHA-256 operations. +// +// Functions for SHA-384 and SHA-512 can be added when the need arises. + +static const size_t kSHA256Length = 32; // Length in bytes of a SHA-256 hash. + +// Computes the SHA-256 hash of |input|. +CRYPTO_EXPORT std::array<uint8_t, kSHA256Length> SHA256Hash( + absl::Span<const uint8_t> input); + +// Convenience version of the above that returns the result in a 32-byte +// string. +CRYPTO_EXPORT std::string SHA256HashString(absl::string_view str); + +// Computes the SHA-256 hash of the input string 'str' and stores the first +// 'len' bytes of the hash in the output buffer 'output'. If 'len' > 32, +// only 32 bytes (the full hash) are stored in the 'output' buffer. +CRYPTO_EXPORT void SHA256HashString(absl::string_view str, void* output, + size_t len); + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SHA2_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/sha2_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/sha2_unittest.cc new file mode 100644 index 00000000000..69e66025cf5 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/sha2_unittest.cc @@ -0,0 +1,98 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/sha2.h" + +#include <stddef.h> +#include <stdint.h> + +#include <string> + +#include "gtest/gtest.h" + +TEST(Sha256Test, Test1) { + // Example B.1 from FIPS 180-2: one-block message. + std::string input1 = "abc"; + int expected1[] = {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + + uint8_t output1[crypto::kSHA256Length]; + crypto::SHA256HashString(input1, output1, sizeof(output1)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected1[i], static_cast<int>(output1[i])); + + uint8_t output_truncated1[4]; // 4 bytes == 32 bits + crypto::SHA256HashString(input1, output_truncated1, + sizeof(output_truncated1)); + for (size_t i = 0; i < sizeof(output_truncated1); i++) + EXPECT_EQ(expected1[i], static_cast<int>(output_truncated1[i])); +} + +TEST(Sha256Test, Test1_String) { + // Same as the above, but using the wrapper that returns a std::string. + // Example B.1 from FIPS 180-2: one-block message. + std::string input1 = "abc"; + int expected1[] = {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + + std::string output1 = crypto::SHA256HashString(input1); + ASSERT_EQ(crypto::kSHA256Length, output1.size()); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected1[i], static_cast<uint8_t>(output1[i])); +} + +TEST(Sha256Test, Test2) { + // Example B.2 from FIPS 180-2: multi-block message. + std::string input2 = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + int expected2[] = {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}; + + uint8_t output2[crypto::kSHA256Length]; + crypto::SHA256HashString(input2, output2, sizeof(output2)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected2[i], static_cast<int>(output2[i])); + + uint8_t output_truncated2[6]; + crypto::SHA256HashString(input2, output_truncated2, + sizeof(output_truncated2)); + for (size_t i = 0; i < sizeof(output_truncated2); i++) + EXPECT_EQ(expected2[i], static_cast<int>(output_truncated2[i])); +} + +TEST(Sha256Test, Test3) { + // Example B.3 from FIPS 180-2: long message. + std::string input3(1000000, 'a'); // 'a' repeated a million times + int expected3[] = {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, + 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, + 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, + 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}; + + uint8_t output3[crypto::kSHA256Length]; + crypto::SHA256HashString(input3, output3, sizeof(output3)); + for (size_t i = 0; i < crypto::kSHA256Length; i++) + EXPECT_EQ(expected3[i], static_cast<int>(output3[i])); + + uint8_t output_truncated3[12]; + crypto::SHA256HashString(input3, output_truncated3, + sizeof(output_truncated3)); + for (size_t i = 0; i < sizeof(output_truncated3); i++) + EXPECT_EQ(expected3[i], static_cast<int>(output_truncated3[i])); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/signature_verifier.cc b/chromium/third_party/nearby/src/internal/crypto/signature_verifier.cc new file mode 100644 index 00000000000..1328a82319f --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/signature_verifier.cc @@ -0,0 +1,115 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/signature_verifier.h" + +#include <memory> + +#include "internal/crypto/openssl_util.h" +#include "internal/platform/logging.h" +#include <openssl/bytestring.h> +#include <openssl/digest.h> +#include <openssl/evp.h> +#include <openssl/rsa.h> + +namespace crypto { + +struct SignatureVerifier::VerifyContext { + bssl::ScopedEVP_MD_CTX ctx; +}; + +SignatureVerifier::SignatureVerifier() = default; + +SignatureVerifier::~SignatureVerifier() = default; + +bool SignatureVerifier::VerifyInit(SignatureAlgorithm signature_algorithm, + absl::Span<const uint8_t> signature, + absl::Span<const uint8_t> public_key_info) { + OpenSSLErrStackTracer err_tracer; + + int pkey_type = EVP_PKEY_NONE; + const EVP_MD* digest = nullptr; + switch (signature_algorithm) { + case RSA_PKCS1_SHA1: + pkey_type = EVP_PKEY_RSA; + digest = EVP_sha1(); + break; + case RSA_PKCS1_SHA256: + case RSA_PSS_SHA256: + pkey_type = EVP_PKEY_RSA; + digest = EVP_sha256(); + break; + case ECDSA_SHA256: + pkey_type = EVP_PKEY_EC; + digest = EVP_sha256(); + break; + } + DCHECK_NE(EVP_PKEY_NONE, pkey_type); + DCHECK(digest); + + if (verify_context_) return false; + + verify_context_ = std::make_unique<VerifyContext>(); + signature_.assign(signature.data(), signature.data() + signature.size()); + + CBS cbs; + CBS_init(&cbs, public_key_info.data(), public_key_info.size()); + bssl::UniquePtr<EVP_PKEY> public_key(EVP_parse_public_key(&cbs)); + if (!public_key || CBS_len(&cbs) != 0 || + EVP_PKEY_id(public_key.get()) != pkey_type) { + return false; + } + + EVP_PKEY_CTX* pkey_ctx; + if (!EVP_DigestVerifyInit(verify_context_->ctx.get(), &pkey_ctx, digest, + nullptr, public_key.get())) { + return false; + } + + if (signature_algorithm == RSA_PSS_SHA256) { + if (!EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, -1 /* match digest and salt length */)) { + return false; + } + } + + return true; +} + +void SignatureVerifier::VerifyUpdate(absl::Span<const uint8_t> data_part) { + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer; + int rv = EVP_DigestVerifyUpdate(verify_context_->ctx.get(), data_part.data(), + data_part.size()); + DCHECK_EQ(rv, 1); +} + +bool SignatureVerifier::VerifyFinal() { + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer; + int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(), signature_.data(), + signature_.size()); + DCHECK_EQ(static_cast<int>(!!rv), rv); + Reset(); + return rv == 1; +} + +void SignatureVerifier::Reset() { + verify_context_.reset(); + signature_.clear(); +} + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/signature_verifier.h b/chromium/third_party/nearby/src/internal/crypto/signature_verifier.h new file mode 100644 index 00000000000..18a00202abd --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/signature_verifier.h @@ -0,0 +1,81 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SIGNATURE_VERIFIER_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SIGNATURE_VERIFIER_H_ + +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "absl/types/span.h" +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// The SignatureVerifier class verifies a signature using a bare public key +// (as opposed to a certificate). +class CRYPTO_EXPORT SignatureVerifier { + public: + // The set of supported signature algorithms. Extend as required. + enum SignatureAlgorithm { + RSA_PKCS1_SHA1, + RSA_PKCS1_SHA256, + ECDSA_SHA256, + // This is RSA-PSS with SHA-256 as both signing hash and MGF-1 hash, and the + // salt length matching the hash length. + RSA_PSS_SHA256, + }; + + SignatureVerifier(); + ~SignatureVerifier(); + + // Streaming interface: + + // Initiates a signature verification operation. This should be followed + // by one or more VerifyUpdate calls and a VerifyFinal call. + // + // The signature is encoded according to the signature algorithm. + // + // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo + // structure, which contains not only the public key but also its type + // (algorithm): + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + bool VerifyInit(SignatureAlgorithm signature_algorithm, + absl::Span<const uint8_t> signature, + absl::Span<const uint8_t> public_key_info); + + // Feeds a piece of the data to the signature verifier. + void VerifyUpdate(absl::Span<const uint8_t> data_part); + + // Concludes a signature verification operation. Returns true if the + // signature is valid. Returns false if the signature is invalid or an + // error occurred. + bool VerifyFinal(); + + private: + void Reset(); + + std::vector<uint8_t> signature_; + + struct VerifyContext; + std::unique_ptr<VerifyContext> verify_context_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SIGNATURE_VERIFIER_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/signature_verifier_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/signature_verifier_unittest.cc new file mode 100644 index 00000000000..70e9ea44911 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/signature_verifier_unittest.cc @@ -0,0 +1,424 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/signature_verifier.h" + +#include <stddef.h> +#include <stdint.h> + +#include <iterator> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/types/span.h" + +TEST(SignatureVerifierTest, BasicTest) { + // The input data in this test comes from real certificates. + // + // tbs_certificate ("to-be-signed certificate", the part of a certificate that + // is signed), signature, and algorithm come from the certificate of + // bugs.webkit.org. + // + // public_key_info comes from the certificate of the issuer, Go Daddy Secure + // Certification Authority. + // + // The bytes in the array initializers are formatted to expose the DER + // encoding of the ASN.1 structures. + + // The data that is signed is the following ASN.1 structure: + // TBSCertificate ::= SEQUENCE { + // ... -- omitted, not important + // } + const uint8_t tbs_certificate[1017] = { + 0x30, 0x82, 0x03, 0xf5, // a SEQUENCE of length 1013 (0x3f5) + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, + 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, + 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, + 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, + 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, + 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, + 0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38, + 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, + 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, + 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, + 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72, + 0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72, + 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, + 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28, + 0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5, + 0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0, + 0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c, + 0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1, + 0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff, + 0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39, + 0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca, + 0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1, + 0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb, + 0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e, + 0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30, + 0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, + 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, + 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, + 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57, + 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0, + 0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, + 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e, + 0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b, + 0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, + 0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, + 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64, + 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48, + 0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5, + 0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, + 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, + 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, + 0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, + 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69, + 0x74, 0x2e, 0x6f, 0x72, 0x67}; + + // RSA signature, a big integer in the big-endian byte order. + const uint8_t signature[256] = { + 0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f, + 0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37, + 0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82, + 0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01, + 0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01, + 0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98, + 0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56, + 0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8, + 0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff, + 0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d, + 0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84, + 0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8, + 0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9, + 0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2, + 0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94, + 0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3, + 0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a, + 0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e, + 0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08, + 0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd, + 0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8, + 0x3c, 0xd8, 0x48, 0x8a}; + + // The public key is specified as the following ASN.1 structure: + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + const uint8_t public_key_info[294] = { + 0x30, 0x82, 0x01, 0x22, // a SEQUENCE of length 290 (0x122) + // algorithm + 0x30, 0x0d, // a SEQUENCE of length 13 + 0x06, 0x09, // an OBJECT IDENTIFIER of length 9 + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, // a NULL of length 0 + // subjectPublicKey + 0x03, 0x82, 0x01, 0x0f, // a BIT STRING of length 271 (0x10f) + 0x00, // number of unused bits + 0x30, 0x82, 0x01, 0x0a, // a SEQUENCE of length 266 (0x10a) + // modulus + 0x02, 0x82, 0x01, 0x01, // an INTEGER of length 257 (0x101) + 0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec, 0x32, 0x35, + 0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61, 0x81, 0x59, 0x3b, 0x70, + 0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7, 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79, + 0xe4, 0x3a, 0xed, 0x3c, 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6, + 0xb2, 0x87, 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b, + 0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9, 0x54, 0xeb, + 0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95, 0xad, 0xef, 0xfb, 0xfe, + 0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00, 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42, + 0x04, 0xce, 0xa7, 0x3f, 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52, + 0xa1, 0x69, 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea, + 0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48, 0xc7, 0x98, + 0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66, 0x6d, 0x0a, 0x9c, 0xb3, + 0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8, 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9, + 0x7a, 0x91, 0xc1, 0xa7, 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65, + 0x6e, 0x6a, 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b, + 0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0, 0xbf, 0x87, + 0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5, 0x9d, 0xaf, 0x17, 0x31, + 0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81, 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf, + 0x3a, 0xaf, 0x25, 0x87, 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45, + 0x8e, 0x97, 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37, + 0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe, 0x13, 0x94, + 0xa3, 0x3f, 0x84, 0x0d, 0x4f, + // public exponent + 0x02, 0x03, // an INTEGER of length 3 + 0x01, 0x00, 0x01}; + + // We use the signature verifier to perform four signature verification + // tests. + crypto::SignatureVerifier verifier; + + // Test 1: feed all of the data to the verifier at once (a single + // VerifyUpdate call). + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(tbs_certificate); + EXPECT_TRUE(verifier.VerifyFinal()); + + // Test 2: feed the data to the verifier in three parts (three VerifyUpdate + // calls). + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(absl::MakeSpan(tbs_certificate, 256)); + verifier.VerifyUpdate(absl::MakeSpan(tbs_certificate + 256, 256)); + verifier.VerifyUpdate( + absl::MakeSpan(tbs_certificate + 512, sizeof(tbs_certificate) - 512)); + EXPECT_TRUE(verifier.VerifyFinal()); + + // Test 3: verify the signature with incorrect data. + uint8_t bad_tbs_certificate[sizeof(tbs_certificate)]; + memcpy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate)); + bad_tbs_certificate[10] += 1; // Corrupt one byte of the data. + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, public_key_info)); + verifier.VerifyUpdate(bad_tbs_certificate); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Test 4: verify a bad signature. + uint8_t bad_signature[sizeof(signature)]; + memcpy(bad_signature, signature, sizeof(signature)); + bad_signature[10] += 1; // Corrupt one byte of the signature. + EXPECT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + bad_signature, public_key_info)); + verifier.VerifyUpdate(tbs_certificate); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Test 5: import an invalid key. + uint8_t bad_public_key_info[sizeof(public_key_info)]; + memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info)); + bad_public_key_info[0] += 1; // Corrupt part of the SPKI syntax. + EXPECT_FALSE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, bad_public_key_info)); + + // Test 6: import a key with extra data. + uint8_t long_public_key_info[sizeof(public_key_info) + 5]; + memset(long_public_key_info, 0, sizeof(long_public_key_info)); + memcpy(long_public_key_info, public_key_info, sizeof(public_key_info)); + EXPECT_FALSE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, + signature, long_public_key_info)); +} + +// The following RSA-PSS tests were generated via the following OpenSSL +// commands: +// +// clang-format off +// openssl genrsa -f4 -out key.pem 2048 +// openssl rsa -in key.pem -pubout -outform der | xxd -i > spki.txt +// openssl rand -out message 50 +// xxd -i message > message.txt +// openssl dgst -sign key.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt \ +// rsa_pss_saltlen:32 < message | xxd -i > sig-good.txt +// openssl dgst -sign key.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt \ +// rsa_pss_saltlen:33 < message | xxd -i > sig-bad-saltlen.txt +// clang-format on + +namespace { + +// This is the public key corresponding to the following private key. +// +// -----BEGIN RSA PRIVATE KEY----- +// MIIEowIBAAKCAQEArg5NXFRQQ5QU7dcqqIjZwL4qy4AaJNSPfSPvXmFbK0hDXdp6 +// PdOZ2Wd+lQLZwb7ZQ2ZdqHVK3kZ2sVUlFmngIoEXNhVg+gW2zGPZ1YemwBMdZ/NW +// V2xTX7Y3RrdR/kSccd9ByRTHKb+BCJ2XN5pHu91+LFchahW0lVPHz9DkBPUCThM2 +// I4ZosM3+AcO93RrrcbiQdpuY60Lfg9ZX7+1clM7zhiuOjWNY+FLN4+j4Ec8isiis +// /V1LQyxRZ2t29kto47UJKu0Li7gUvEE1PS/nXBVgEqcSEBBKXa4ahsTqKWJAwvEH +// xaH1t2qhVO1IHcf9FSv5k1T47H7XMLpO2OCPrwIDAQABAoIBAQCXA4exTOHa0Dcc +// aGv1j87GAPimWX3VaKsaGzyKuZNdSTRR0MXwsI+yZa4Y4UFHbSuZ483s499SXPaM +// Q2CLQs8ZgME/xmq+YojIavXL4wcVbUA9OY43CaCI0VLCQzmbj7HgxqCQMzvdh+8P +// J5PUxUHpyHG5TNuL7EsiqG8bapT7ip2+IpKrKjr18gn3k0k9mLNJxK9Qr+CJphwo +// eJgq0Kcjx3bfgDEpPzyvdd+J3e+jclOTYbk2HwJ0FVCrfgJedHFIWUytZoM5783g +// knXzgDyKs65aUDjc/opidXp3WOqfNJUPSiofPYPdYQ26UI0vztL5MBkWCpl+d/55 +// BqxCdDlhAoGBANm90DFUca+7LdnDgj8mWtUIzr+XVzSD9tzOIpcjiPwEnxk8RHrM +// aMHCAKZpbsnX/ikdc2I1OsirPgNFh1q30xgL7oCadzxlwfXnEM0Nff8RJKtN+yI6 +// +nRoOCDGCHBsaa2wyMYRbnanyRDLPIOP4eGQ6Hz/LQJBvhjRyTXlrUU/AoGBAMyj +// ec1ySnlJ2S0JqPBCk14dRsEs/zStgFz1Wdmk7TMRBPUMyhWf8JwNrU5Ppm9biJMo +// MKwkiFjzv/us4ne3wFRsTiKj4uiIwfji7/N2VpbEXSDGtonrX7hES4wQ/s+qr8XJ +// 8ykHrZ9rPOY2lBhxOo+VYE3U6aspAY/qwK8WyumRAoGAMdl+/Iw0quLTkHNuMj75 +// tKQbkUl4sZE0x0B6Mtfz2J7GPeTKWMLLiPB9bZvdvWAx0//mFqnRF3f87orQfjhv +// n6W7qL20ZqN1UHLiKc/Y9LhcCMwFnsSZ6mSh1P8Bl5t6ZkV+8bmz7H5lTe75n7Ul +// JZsjXtqc11NtzgjZY/l9PckCgYAH6ZI+FVs30VkqWqNDlu9nxi4ELh84BDVgYsQ0 +// nCHnxZKxfusZZvPAtO6shnvi9mETf4xSO59iARq9OnQPOPWgzgc/Y6LUZuVJIE0y +// 1rKGZdVL/SL1tjofP9TD96xCj1D4jtRuE7Ps5BKYvCeBwm8HOjldCQx357/9to/4 +// tSLnYQKBgG7STr94Slb3/BzzMxdMLCum1PH73/+IFxu1J0cXxYLP2zEhcSgqGIwm +// aMgdu1L9eE6lJM99AWTEkpcUz8UFwNt+hZW+lZZpex77RMgRl9VCiwid1BNBSU/o +// +lT1mlpDrPCNOge9n6Qvy5waBugB8uNS86w0UImYiKZr+8IQ4EdE +// -----END RSA PRIVATE KEY----- +const uint8_t kPSSPublicKey[] = { + 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, + 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0x0e, 0x4d, + 0x5c, 0x54, 0x50, 0x43, 0x94, 0x14, 0xed, 0xd7, 0x2a, 0xa8, 0x88, 0xd9, + 0xc0, 0xbe, 0x2a, 0xcb, 0x80, 0x1a, 0x24, 0xd4, 0x8f, 0x7d, 0x23, 0xef, + 0x5e, 0x61, 0x5b, 0x2b, 0x48, 0x43, 0x5d, 0xda, 0x7a, 0x3d, 0xd3, 0x99, + 0xd9, 0x67, 0x7e, 0x95, 0x02, 0xd9, 0xc1, 0xbe, 0xd9, 0x43, 0x66, 0x5d, + 0xa8, 0x75, 0x4a, 0xde, 0x46, 0x76, 0xb1, 0x55, 0x25, 0x16, 0x69, 0xe0, + 0x22, 0x81, 0x17, 0x36, 0x15, 0x60, 0xfa, 0x05, 0xb6, 0xcc, 0x63, 0xd9, + 0xd5, 0x87, 0xa6, 0xc0, 0x13, 0x1d, 0x67, 0xf3, 0x56, 0x57, 0x6c, 0x53, + 0x5f, 0xb6, 0x37, 0x46, 0xb7, 0x51, 0xfe, 0x44, 0x9c, 0x71, 0xdf, 0x41, + 0xc9, 0x14, 0xc7, 0x29, 0xbf, 0x81, 0x08, 0x9d, 0x97, 0x37, 0x9a, 0x47, + 0xbb, 0xdd, 0x7e, 0x2c, 0x57, 0x21, 0x6a, 0x15, 0xb4, 0x95, 0x53, 0xc7, + 0xcf, 0xd0, 0xe4, 0x04, 0xf5, 0x02, 0x4e, 0x13, 0x36, 0x23, 0x86, 0x68, + 0xb0, 0xcd, 0xfe, 0x01, 0xc3, 0xbd, 0xdd, 0x1a, 0xeb, 0x71, 0xb8, 0x90, + 0x76, 0x9b, 0x98, 0xeb, 0x42, 0xdf, 0x83, 0xd6, 0x57, 0xef, 0xed, 0x5c, + 0x94, 0xce, 0xf3, 0x86, 0x2b, 0x8e, 0x8d, 0x63, 0x58, 0xf8, 0x52, 0xcd, + 0xe3, 0xe8, 0xf8, 0x11, 0xcf, 0x22, 0xb2, 0x28, 0xac, 0xfd, 0x5d, 0x4b, + 0x43, 0x2c, 0x51, 0x67, 0x6b, 0x76, 0xf6, 0x4b, 0x68, 0xe3, 0xb5, 0x09, + 0x2a, 0xed, 0x0b, 0x8b, 0xb8, 0x14, 0xbc, 0x41, 0x35, 0x3d, 0x2f, 0xe7, + 0x5c, 0x15, 0x60, 0x12, 0xa7, 0x12, 0x10, 0x10, 0x4a, 0x5d, 0xae, 0x1a, + 0x86, 0xc4, 0xea, 0x29, 0x62, 0x40, 0xc2, 0xf1, 0x07, 0xc5, 0xa1, 0xf5, + 0xb7, 0x6a, 0xa1, 0x54, 0xed, 0x48, 0x1d, 0xc7, 0xfd, 0x15, 0x2b, 0xf9, + 0x93, 0x54, 0xf8, 0xec, 0x7e, 0xd7, 0x30, 0xba, 0x4e, 0xd8, 0xe0, 0x8f, + 0xaf, 0x02, 0x03, 0x01, 0x00, 0x01, +}; + +const uint8_t kPSSMessage[] = { + 0x1e, 0x70, 0xbd, 0xeb, 0x24, 0xf2, 0x9d, 0x05, 0xc5, 0xb5, + 0xf4, 0xca, 0xe6, 0x1d, 0x01, 0x97, 0x29, 0xf4, 0xe0, 0x7c, + 0xfd, 0xcc, 0x97, 0x8d, 0xc2, 0xbb, 0x2d, 0x9b, 0x6b, 0x45, + 0x06, 0xbd, 0x2c, 0x66, 0x10, 0x42, 0x73, 0x8d, 0x88, 0x9b, + 0x18, 0xcc, 0xcb, 0x7e, 0x43, 0x23, 0x06, 0xe9, 0x8f, 0x8f, +}; + +const uint8_t kPSSSignatureGood[] = { + 0x12, 0xa7, 0x6d, 0x9e, 0x8a, 0xea, 0x28, 0xe0, 0x3f, 0x6f, 0x5a, 0xa4, + 0x1b, 0x6a, 0x0a, 0x14, 0xba, 0xfa, 0x84, 0xf6, 0xb7, 0x3c, 0xc9, 0xd6, + 0x84, 0xab, 0x1e, 0x77, 0x88, 0x53, 0x95, 0x43, 0x8e, 0x73, 0xe4, 0x21, + 0xab, 0x69, 0xb2, 0x0c, 0x73, 0x4d, 0x98, 0x42, 0xbd, 0x65, 0xa2, 0x95, + 0x0d, 0x76, 0xb2, 0xbd, 0xe5, 0x9a, 0x6e, 0x9f, 0x72, 0x7f, 0xdd, 0x1e, + 0x9f, 0xda, 0xc8, 0x2e, 0xa3, 0xe6, 0x28, 0x03, 0x98, 0x5c, 0x13, 0xa7, + 0x7d, 0x4e, 0xde, 0xea, 0x35, 0x1b, 0x35, 0x7e, 0xaa, 0x14, 0xf9, 0xfb, + 0xac, 0x61, 0xd0, 0x44, 0x20, 0xd5, 0x52, 0x5b, 0x92, 0x8f, 0xe7, 0x37, + 0xa2, 0x72, 0x7d, 0xe6, 0x0d, 0x81, 0x63, 0xcc, 0x0f, 0xbd, 0xde, 0x25, + 0xe3, 0x3f, 0x89, 0x1b, 0x39, 0x64, 0xfa, 0x21, 0x1d, 0x0f, 0x9b, 0x8a, + 0xc1, 0xad, 0x03, 0x49, 0x96, 0xff, 0x9f, 0x2d, 0x83, 0xee, 0x2d, 0x2a, + 0x1e, 0xc5, 0x73, 0x9f, 0x5b, 0xde, 0xcb, 0xaf, 0x02, 0xbd, 0xc5, 0x9b, + 0x78, 0xb9, 0x8e, 0x01, 0x75, 0x3c, 0xc9, 0x6e, 0x7d, 0x3e, 0x61, 0x62, + 0xc4, 0x8c, 0x9e, 0x76, 0xed, 0x52, 0x5e, 0x80, 0x89, 0xa7, 0x75, 0x5e, + 0xc6, 0x34, 0x97, 0x22, 0x40, 0xb5, 0x0c, 0x77, 0x09, 0x8c, 0xa8, 0xe9, + 0xf6, 0x8d, 0xc0, 0x10, 0x78, 0x92, 0xa9, 0xc6, 0x68, 0xa3, 0x57, 0x6e, + 0x73, 0xb5, 0x73, 0x8d, 0x8e, 0x21, 0xb1, 0xf3, 0xd0, 0x0a, 0x40, 0x68, + 0xfc, 0x3c, 0xeb, 0xd3, 0x48, 0x4a, 0x44, 0xbd, 0xc0, 0x40, 0x5d, 0x9b, + 0x40, 0x6f, 0x45, 0x98, 0x2b, 0xae, 0x58, 0xe8, 0x9d, 0x34, 0x49, 0xd2, + 0xec, 0xdc, 0xd5, 0x98, 0xb4, 0x87, 0x8a, 0xcc, 0x41, 0x3e, 0xd7, 0xe6, + 0x21, 0xd6, 0x4c, 0x89, 0xf1, 0xf4, 0x77, 0x40, 0x3f, 0x9a, 0x28, 0x25, + 0x55, 0x7c, 0xf5, 0x0c, +}; + +const uint8_t kPSSSignatureBadSaltLength[] = { + 0x6e, 0x61, 0xbe, 0x8a, 0x82, 0xbd, 0xed, 0xc6, 0xe4, 0x33, 0x91, 0xa4, + 0x43, 0x57, 0x51, 0x7e, 0xa8, 0x18, 0xbf, 0x20, 0x98, 0xbc, 0x04, 0x50, + 0x06, 0x1b, 0x0b, 0xb6, 0x43, 0xde, 0x58, 0x7f, 0x6b, 0xa5, 0x5e, 0x9d, + 0xd1, 0x75, 0x03, 0xf5, 0x19, 0x8d, 0xdb, 0x2c, 0xd2, 0x9a, 0xf9, 0xbd, + 0x82, 0x8d, 0x32, 0x9d, 0x7d, 0x70, 0x6f, 0x81, 0x95, 0x60, 0x1d, 0x62, + 0x72, 0xf3, 0x95, 0x5b, 0x7a, 0x66, 0x7f, 0x45, 0x94, 0x0c, 0x07, 0xc8, + 0xa7, 0x64, 0x38, 0x57, 0x1a, 0x64, 0x64, 0xf1, 0xe0, 0x45, 0xfe, 0x00, + 0x11, 0x90, 0x57, 0x95, 0x15, 0x21, 0x10, 0x85, 0xc0, 0xbe, 0x53, 0x5b, + 0x3b, 0xa3, 0x57, 0x99, 0x2b, 0x94, 0x6b, 0xbf, 0xa5, 0x55, 0x7d, 0x5a, + 0xcb, 0xa2, 0x73, 0x6b, 0x5f, 0x7b, 0x3f, 0x10, 0x90, 0xd1, 0x26, 0x72, + 0x5e, 0xad, 0xd1, 0x34, 0xe8, 0x8a, 0x33, 0xeb, 0xd2, 0xbf, 0x54, 0x92, + 0xeb, 0x7c, 0xb9, 0x97, 0x80, 0x5a, 0x46, 0xc4, 0xbd, 0xf5, 0x7e, 0xd6, + 0x20, 0x90, 0x92, 0xcb, 0x37, 0x85, 0x9d, 0x81, 0x0a, 0xd0, 0xa5, 0x73, + 0x17, 0x7e, 0xe2, 0x91, 0xef, 0x35, 0x55, 0xc9, 0x5e, 0x87, 0x84, 0x11, + 0xa4, 0x36, 0xf0, 0x2a, 0xa7, 0x7a, 0x83, 0x1d, 0x7a, 0x90, 0x69, 0x22, + 0x5d, 0x3b, 0x30, 0x48, 0x46, 0xd2, 0xd3, 0x49, 0x23, 0x64, 0xa4, 0x6d, + 0xd1, 0xef, 0xb9, 0x1b, 0xa4, 0xd1, 0x92, 0xdd, 0x8c, 0xb2, 0xaa, 0x9f, + 0x6a, 0x2c, 0xc9, 0xdb, 0xa7, 0x35, 0x66, 0x92, 0x8b, 0x73, 0x11, 0x70, + 0x2b, 0xf4, 0x34, 0x3f, 0x9e, 0x15, 0x3e, 0xc0, 0xac, 0x78, 0x6f, 0x74, + 0x8a, 0x6b, 0xe4, 0xf2, 0x7b, 0x10, 0xca, 0x01, 0x3a, 0x3a, 0x88, 0x39, + 0x34, 0xa8, 0x52, 0x4a, 0x76, 0x50, 0xef, 0xdb, 0x91, 0x3c, 0x4a, 0x5c, + 0xe5, 0x43, 0x6f, 0x8e, +}; + +} // namespace + +TEST(SignatureVerifierTest, VerifyRSAPSS) { + // Verify the test vector. + crypto::SignatureVerifier verifier; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_TRUE(verifier.VerifyFinal()); + + // Verify the test vector byte-by-byte. + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + for (uint8_t b : kPSSMessage) { + verifier.VerifyUpdate(absl::MakeSpan(&b, 1)); + } + EXPECT_TRUE(verifier.VerifyFinal()); + + // The bad salt length does not verify. + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureBadSaltLength, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Corrupt the message. + std::vector<uint8_t> message(std::begin(kPSSMessage), std::end(kPSSMessage)); + message[0] ^= 1; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + kPSSSignatureGood, kPSSPublicKey)); + verifier.VerifyUpdate(message); + EXPECT_FALSE(verifier.VerifyFinal()); + + // Corrupt the signature. + std::vector<uint8_t> signature(std::begin(kPSSSignatureGood), + std::end(kPSSSignatureGood)); + signature[0] ^= 1; + ASSERT_TRUE(verifier.VerifyInit(crypto::SignatureVerifier::RSA_PSS_SHA256, + signature, kPSSPublicKey)); + verifier.VerifyUpdate(kPSSMessage); + EXPECT_FALSE(verifier.VerifyFinal()); +} diff --git a/chromium/third_party/nearby/src/internal/crypto/symmetric_key.cc b/chromium/third_party/nearby/src/internal/crypto/symmetric_key.cc new file mode 100644 index 00000000000..13c24bd492f --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/symmetric_key.cc @@ -0,0 +1,140 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/symmetric_key.h" + +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> +#include <memory> +#include <string> +#include <utility> + +#include "internal/crypto/nearby_base.h" +#include "internal/crypto/openssl_util.h" +#include "internal/platform/logging.h" +#include <openssl/evp.h> +#include <openssl/rand.h> + +namespace crypto { + +namespace { + +bool CheckDerivationParameters(SymmetricKey::Algorithm algorithm, + size_t key_size_in_bits) { + switch (algorithm) { + case SymmetricKey::AES: + // Whitelist supported key sizes to avoid accidentally relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + return key_size_in_bits == 128 || key_size_in_bits == 256; + case SymmetricKey::HMAC_SHA1: + return key_size_in_bits % 8 == 0 && key_size_in_bits != 0; + } + + DCHECK(false); + return false; +} + +} // namespace + +SymmetricKey::~SymmetricKey() { + std::fill(key_.begin(), key_.end(), '\0'); // Zero out the confidential key. +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::GenerateRandomKey( + Algorithm algorithm, size_t key_size_in_bits) { + DCHECK_EQ(AES, algorithm); + + // Whitelist supported key sizes to avoid accidentally relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + if (key_size_in_bits != 128 && key_size_in_bits != 256) return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + DCHECK_EQ(key_size_in_bits, key_size_in_bytes * 8); + + if (key_size_in_bytes == 0) return nullptr; + + OpenSSLErrStackTracer err_tracer; + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + nearbybase::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = RAND_bytes(key_data, static_cast<int>(key_size_in_bytes)); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + Algorithm algorithm, const std::string& password, const std::string& salt, + size_t iterations, size_t key_size_in_bits) { + if (!CheckDerivationParameters(algorithm, key_size_in_bits)) return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + + OpenSSLErrStackTracer err_tracer; + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + nearbybase::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = PKCS5_PBKDF2_HMAC_SHA1( + password.data(), password.length(), + reinterpret_cast<const uint8_t*>(salt.data()), salt.length(), + static_cast<unsigned>(iterations), key_size_in_bytes, key_data); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::DeriveKeyFromPasswordUsingScrypt( + Algorithm algorithm, const std::string& password, const std::string& salt, + size_t cost_parameter, size_t block_size, size_t parallelization_parameter, + size_t max_memory_bytes, size_t key_size_in_bits) { + if (!CheckDerivationParameters(algorithm, key_size_in_bits)) return nullptr; + + size_t key_size_in_bytes = key_size_in_bits / 8; + + OpenSSLErrStackTracer err_tracer; + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + uint8_t* key_data = reinterpret_cast<uint8_t*>( + nearbybase::WriteInto(&key->key_, key_size_in_bytes + 1)); + + int rv = EVP_PBE_scrypt(password.data(), password.length(), + reinterpret_cast<const uint8_t*>(salt.data()), + salt.length(), cost_parameter, block_size, + parallelization_parameter, max_memory_bytes, key_data, + key_size_in_bytes); + return rv == 1 ? std::move(key) : nullptr; +} + +// static +std::unique_ptr<SymmetricKey> SymmetricKey::Import(Algorithm algorithm, + const std::string& raw_key) { + if (algorithm == AES) { + // Whitelist supported key sizes to avoid accidentally relying on + // algorithms available in NSS but not BoringSSL and vice + // versa. Note that BoringSSL does not support AES-192. + if (raw_key.size() != 128 / 8 && raw_key.size() != 256 / 8) return nullptr; + } + + std::unique_ptr<SymmetricKey> key(new SymmetricKey); + key->key_ = raw_key; + return key; +} + +SymmetricKey::SymmetricKey() = default; + +} // namespace crypto diff --git a/chromium/third_party/nearby/src/internal/crypto/symmetric_key.h b/chromium/third_party/nearby/src/internal/crypto/symmetric_key.h new file mode 100644 index 00000000000..054a8ad1732 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/symmetric_key.h @@ -0,0 +1,89 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SYMMETRIC_KEY_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SYMMETRIC_KEY_H_ + +#include <stddef.h> + +#include <memory> +#include <string> + +#include "internal/crypto/crypto_export.h" + +namespace crypto { + +// Wraps a platform-specific symmetric key and allows it to be held in a +// scoped_ptr. +class CRYPTO_EXPORT SymmetricKey { + public: + // Defines the algorithm that a key will be used with. See also + // classs Encrptor. + enum Algorithm { + AES, + HMAC_SHA1, + }; + + SymmetricKey(const SymmetricKey&) = delete; + SymmetricKey& operator=(const SymmetricKey&) = delete; + + virtual ~SymmetricKey(); + + // Generates a random key suitable to be used with |algorithm| and of + // |key_size_in_bits| bits. |key_size_in_bits| must be a multiple of 8. + // The caller is responsible for deleting the returned SymmetricKey. + static std::unique_ptr<SymmetricKey> GenerateRandomKey( + Algorithm algorithm, size_t key_size_in_bits); + + // Derives a key from the supplied password and salt using PBKDF2, suitable + // for use with specified |algorithm|. Note |algorithm| is not the algorithm + // used to derive the key from the password. |key_size_in_bits| must be a + // multiple of 8. The caller is responsible for deleting the returned + // SymmetricKey. + static std::unique_ptr<SymmetricKey> DeriveKeyFromPasswordUsingPbkdf2( + Algorithm algorithm, const std::string& password, const std::string& salt, + size_t iterations, size_t key_size_in_bits); + + // Derives a key from the supplied password and salt using scrypt, suitable + // for use with specified |algorithm|. Note |algorithm| is not the algorithm + // used to derive the key from the password. |cost_parameter|, |block_size|, + // and |parallelization_parameter| correspond to the parameters |N|, |r|, and + // |p| from the scrypt specification (see RFC 7914). |key_size_in_bits| must + // be a multiple of 8. The caller is responsible for deleting the returned + // SymmetricKey. + static std::unique_ptr<SymmetricKey> DeriveKeyFromPasswordUsingScrypt( + Algorithm algorithm, const std::string& password, const std::string& salt, + size_t cost_parameter, size_t block_size, + size_t parallelization_parameter, size_t max_memory_bytes, + size_t key_size_in_bits); + + // Imports an array of key bytes in |raw_key|. This key may have been + // generated by GenerateRandomKey or DeriveKeyFromPassword{Pbkdf2,Scrypt} and + // exported with key(). The key must be of suitable size for use with + // |algorithm|. The caller owns the returned SymmetricKey. + static std::unique_ptr<SymmetricKey> Import(Algorithm algorithm, + const std::string& raw_key); + + // Returns the raw platform specific key data. + const std::string& key() const { return key_; } + + private: + SymmetricKey(); + + std::string key_; +}; + +} // namespace crypto + +#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_SYMMETRIC_KEY_H_ diff --git a/chromium/third_party/nearby/src/internal/crypto/symmetric_key_unittest.cc b/chromium/third_party/nearby/src/internal/crypto/symmetric_key_unittest.cc new file mode 100644 index 00000000000..4fe70b410e9 --- /dev/null +++ b/chromium/third_party/nearby/src/internal/crypto/symmetric_key_unittest.cc @@ -0,0 +1,262 @@ +// Copyright 2020 Google LLC +// +// 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 +// +// https://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 "internal/crypto/symmetric_key.h" + +#include <memory> +#include <string> + +#include "gtest/gtest.h" +#include "absl/strings/ascii.h" +#include "internal/crypto/nearby_base.h" + +TEST(SymmetricKeyTest, GenerateRandomKey) { + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); + ASSERT_TRUE(key); + EXPECT_EQ(32U, key->key().size()); + + // Do it again and check that the keys are different. + // (Note: this has a one-in-10^77 chance of failure!) + std::unique_ptr<crypto::SymmetricKey> key2( + crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); + ASSERT_TRUE(key2); + EXPECT_EQ(32U, key2->key().size()); + EXPECT_NE(key->key(), key2->key()); +} + +TEST(SymmetricKeyTest, ImportGeneratedKey) { + std::unique_ptr<crypto::SymmetricKey> key1( + crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 256)); + ASSERT_TRUE(key1); + + std::unique_ptr<crypto::SymmetricKey> key2( + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key1->key())); + ASSERT_TRUE(key2); + + EXPECT_EQ(key1->key(), key2->key()); +} + +TEST(SymmetricKeyTest, ImportDerivedKey) { + std::unique_ptr<crypto::SymmetricKey> key1( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + crypto::SymmetricKey::HMAC_SHA1, "password", "somesalt", 1024, 160)); + ASSERT_TRUE(key1); + + std::unique_ptr<crypto::SymmetricKey> key2(crypto::SymmetricKey::Import( + crypto::SymmetricKey::HMAC_SHA1, key1->key())); + ASSERT_TRUE(key2); + + EXPECT_EQ(key1->key(), key2->key()); +} + +struct PBKDF2TestVector { + crypto::SymmetricKey::Algorithm algorithm; + const char* password; + const char* salt; + unsigned int rounds; + unsigned int key_size_in_bits; + const char* expected; // ASCII encoded hex bytes. +}; + +struct ScryptTestVector { + crypto::SymmetricKey::Algorithm algorithm; + const char* password; + const char* salt; + unsigned int cost_parameter; + unsigned int block_size; + unsigned int parallelization_parameter; + unsigned int key_size_in_bits; + const char* expected; // ASCII encoded hex bytes. +}; + +class SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test + : public testing::TestWithParam<PBKDF2TestVector> {}; + +class SymmetricKeyDeriveKeyFromPasswordUsingScryptTest + : public testing::TestWithParam<ScryptTestVector> {}; + +TEST_P(SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test, + DeriveKeyFromPasswordUsingPbkdf2) { + PBKDF2TestVector test_data(GetParam()); + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2( + test_data.algorithm, test_data.password, test_data.salt, + test_data.rounds, test_data.key_size_in_bits)); + ASSERT_TRUE(key); + + const std::string& raw_key = key->key(); + EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size()); + EXPECT_EQ(test_data.expected, absl::AsciiStrToLower(nearbybase::HexEncode( + raw_key.data(), raw_key.size()))); +} + +TEST_P(SymmetricKeyDeriveKeyFromPasswordUsingScryptTest, + DeriveKeyFromPasswordUsingScrypt) { + const int kScryptMaxMemoryBytes = 128 * 1024 * 1024; // 128 MiB. + + ScryptTestVector test_data(GetParam()); + std::unique_ptr<crypto::SymmetricKey> key( + crypto::SymmetricKey::DeriveKeyFromPasswordUsingScrypt( + test_data.algorithm, test_data.password, test_data.salt, + test_data.cost_parameter, test_data.block_size, + test_data.parallelization_parameter, kScryptMaxMemoryBytes, + test_data.key_size_in_bits)); + ASSERT_TRUE(key); + + const std::string& raw_key = key->key(); + EXPECT_EQ(test_data.key_size_in_bits / 8, raw_key.size()); + EXPECT_EQ(test_data.expected, absl::AsciiStrToLower((nearbybase::HexEncode( + raw_key.data(), raw_key.size())))); +} + +static const PBKDF2TestVector kTestVectorsPbkdf2[] = { + // These tests come from + // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt. + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "salt", + 1, + 160, + "0c60c80f961f0e71f3a9b524af6012062fe037a6", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "salt", + 2, + 160, + "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "salt", + 4096, + 160, + "4b007901b765489abead49d926f721d065a429c1", + }, +// This test takes over 30s to run on the trybots. +#if 0 + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "salt", + 16777216, + 160, + "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984", + }, +#endif + + // These tests come from RFC 3962, via BSD source code at + // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain. + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "ATHENA.MIT.EDUraeburn", + 1, + 160, + "cdedb5281bb2f801565a1122b25635150ad1f7a0", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "ATHENA.MIT.EDUraeburn", + 2, + 160, + "01dbee7f4a9e243e988b62c73cda935da05378b9", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "ATHENA.MIT.EDUraeburn", + 1200, + 160, + "5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddb", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "password", + "\022" + "4VxxV4\022", /* 0x1234567878563412 */ + 5, + 160, + "d1daa78615f287e6a1c8b120d7062a493f98d203", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", + 1200, + 160, + "139c30c0966bc32ba55fdbf212530ac9c5ec59f1", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", + 1200, + 160, + "9ccad6d468770cd51b10e6a68721be611a8b4d28", + }, + { + crypto::SymmetricKey::HMAC_SHA1, + "\360\235\204\236", /* g-clef (0xf09d849e) */ + "EXAMPLE.COMpianist", + 50, + 160, + "6b9cf26d45455a43a5b8bb276a403b39e7fe37a0", + }, + + // Regression tests for AES keys, derived from the Linux NSS implementation. + { + crypto::SymmetricKey::AES, + "A test password", + "saltsalt", + 1, + 256, + "44899a7777f0e6e8b752f875f02044b8ac593de146de896f2e8a816e315a36de", + }, + { + crypto::SymmetricKey::AES, + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", + 20, + 256, + "e0739745dc28b8721ba402e05214d2ac1eab54cf72bee1fba388297a09eb493c", + }, +}; + +static const ScryptTestVector kTestVectorsScrypt[] = { + // From RFC 7914, "The scrypt Password-Based Key Derivation Function", + // https://tools.ietf.org/html/rfc7914.html. The fourth test vector is + // intentionally not used, as it would make the test significantly slower, + // due to the very high cost parameter. + {crypto::SymmetricKey::HMAC_SHA1, "", "", 16, 1, 1, 512, + "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069de" + "d0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"}, + {crypto::SymmetricKey::HMAC_SHA1, "password", "NaCl", 1024, 8, 16, 512, + "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92" + "e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"}, + {crypto::SymmetricKey::HMAC_SHA1, "pleaseletmein", "SodiumChloride", 16384, + 8, 1, 512, + "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d54329556" + "13f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"}}; + +INSTANTIATE_TEST_SUITE_P(All, SymmetricKeyDeriveKeyFromPasswordUsingPbkdf2Test, + testing::ValuesIn(kTestVectorsPbkdf2)); + +INSTANTIATE_TEST_SUITE_P(All, SymmetricKeyDeriveKeyFromPasswordUsingScryptTest, + testing::ValuesIn(kTestVectorsScrypt)); |