summaryrefslogtreecommitdiff
path: root/chromium/third_party/nearby/src/internal/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/nearby/src/internal/crypto')
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/BUILD103
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/BUILD.gn217
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/aead.cc182
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/aead.h95
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/aead_unittest.cc100
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/crypto_export.h42
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_private_key.cc182
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_private_key.h96
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_private_key_unittest.cc333
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.cc30
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_signature_creator.h65
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.cc83
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_impl.h48
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/ec_signature_creator_unittest.cc61
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/encryptor.cc218
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/encryptor.h110
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/encryptor_unittest.cc572
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/hkdf.cc58
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/hkdf.h41
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/hmac.cc114
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/hmac.h125
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/hmac_unittest.cc378
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/nearby_base.cc46
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/nearby_base.h56
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/openssl_util.cc62
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/openssl_util.h104
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/random.cc31
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/random.h34
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/random_unittest.cc41
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/rsa_private_key.cc122
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/rsa_private_key.h74
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/rsa_private_key_unittest.cc386
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/secure_hash.cc76
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/secure_hash.h57
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/secure_hash_unittest.cc117
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/secure_util.cc25
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/secure_util.h38
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/sha2.cc47
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/sha2.h51
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/sha2_unittest.cc98
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/signature_verifier.cc115
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/signature_verifier.h81
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/signature_verifier_unittest.cc424
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/symmetric_key.cc140
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/symmetric_key.h89
-rw-r--r--chromium/third_party/nearby/src/internal/crypto/symmetric_key_unittest.cc262
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));