mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Port crypto from location/nearby/cpp/sharing/implementation/internal/crypto to third_party/nearby/internal/crypto.
BEGIN_PUBLIC Add crypto library to Nearby. END_PUBLIC Remove the reference to absl::SourceLocation as it is not in OSS. PiperOrigin-RevId: 465427879
This commit is contained in:
committed by
Copybara-Service
parent
ce6c5893d7
commit
21c2c7c1ea
@@ -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",
|
||||
],
|
||||
)
|
||||
@@ -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" ]
|
||||
}
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/aead.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/span.h"
|
||||
#include "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "third_party/openssl/aes.h"
|
||||
#include "third_party/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;
|
||||
}
|
||||
|
||||
std::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 std::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
|
||||
@@ -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 "third_party/nearby/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;
|
||||
|
||||
std::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;
|
||||
|
||||
std::optional<absl::Span<const uint8_t>> key_;
|
||||
const evp_aead_st* aead_;
|
||||
};
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_AEAD_H_
|
||||
@@ -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 "third_party/nearby/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());
|
||||
|
||||
std::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
|
||||
@@ -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_
|
||||
@@ -0,0 +1,182 @@
|
||||
#include "third_party/nearby/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 "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "third_party/openssl/bn.h"
|
||||
#include "third_party/openssl/bytestring.h"
|
||||
#include "third_party/openssl/ec.h"
|
||||
#include "third_party/openssl/ec_key.h"
|
||||
#include "third_party/openssl/evp.h"
|
||||
#include "third_party/openssl/mem.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/internal/crypto/crypto_export.h"
|
||||
#include "third_party/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_
|
||||
@@ -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 "third_party/nearby/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);
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/ec_signature_creator.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "third_party/nearby/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/ec_signature_creator_impl.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/nearby/internal/crypto/ec_private_key.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "third_party/openssl/bn.h"
|
||||
#include "third_party/openssl/ec.h"
|
||||
#include "third_party/openssl/ecdsa.h"
|
||||
#include "third_party/openssl/evp.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/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 "third_party/nearby/internal/crypto/ec_private_key.h"
|
||||
#include "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/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());
|
||||
}
|
||||
@@ -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 "third_party/nearby/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 "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "third_party/nearby/internal/crypto/symmetric_key.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "third_party/openssl/aes.h"
|
||||
#include "third_party/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));
|
||||
|
||||
std::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()));
|
||||
std::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;
|
||||
}
|
||||
|
||||
std::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 std::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 std::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 std::nullopt;
|
||||
|
||||
out_len += tail_len;
|
||||
DCHECK_LE(out_len, static_cast<int>(output.size()));
|
||||
return out_len;
|
||||
}
|
||||
|
||||
std::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 std::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 std::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
|
||||
@@ -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 "third_party/nearby/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);
|
||||
std::optional<size_t> Crypt(bool do_encrypt, absl::Span<const uint8_t> input,
|
||||
absl::Span<uint8_t> output);
|
||||
std::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_
|
||||
@@ -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 "third_party/nearby/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 "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/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));
|
||||
}
|
||||
@@ -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 "third_party/openssl/hkdf.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "third_party/nearby/internal/crypto/hkdf.h"
|
||||
#include "third_party/nearby/internal/crypto/hmac.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "src/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/openssl/hmac.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "third_party/nearby/internal/crypto/hmac.h"
|
||||
#include "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "third_party/nearby/internal/crypto/secure_util.h"
|
||||
#include "third_party/nearby/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
|
||||
@@ -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 "third_party/nearby/internal/crypto/crypto_export.h"
|
||||
#include "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/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)));
|
||||
}
|
||||
@@ -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 "third_party/nearby/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
|
||||
@@ -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_
|
||||
@@ -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 "third_party/nearby/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 "third_party/openssl/crypto.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/random.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/random.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "third_party/nearby/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));
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/rsa_private_key.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/span.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "third_party/openssl/bn.h"
|
||||
#include "third_party/openssl/bytestring.h"
|
||||
#include "third_party/openssl/evp.h"
|
||||
#include "third_party/openssl/mem.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/internal/crypto/crypto_export.h"
|
||||
#include "third_party/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_
|
||||
@@ -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 "third_party/nearby/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);
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/secure_hash.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "third_party/openssl/mem.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/secure_hash.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "third_party/nearby/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));
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/secure_util.h"
|
||||
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/sha2.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "third_party/nearby/internal/crypto/secure_hash.h"
|
||||
#include "third_party/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.data(), output.size());
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/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]));
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/signature_verifier.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "third_party/openssl/bytestring.h"
|
||||
#include "src/include/openssl/digest.h"
|
||||
#include "third_party/openssl/evp.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/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());
|
||||
}
|
||||
@@ -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 "third_party/nearby/internal/crypto/symmetric_key.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "third_party/nearby/internal/crypto/nearby_base.h"
|
||||
#include "third_party/nearby/internal/crypto/openssl_util.h"
|
||||
#include "internal/platform/logging.h"
|
||||
#include "third_party/openssl/evp.h"
|
||||
#include "third_party/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
|
||||
@@ -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 "third_party/nearby/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_
|
||||
@@ -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 "third_party/nearby/internal/crypto/symmetric_key.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "third_party/nearby/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));
|
||||
@@ -105,6 +105,7 @@ cc_library(
|
||||
"//connections:__subpackages__",
|
||||
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__",
|
||||
"//internal/analytics:__subpackages__",
|
||||
"//internal/crypto:__subpackages__",
|
||||
"//internal/platform:__subpackages__",
|
||||
"//internal/proto/analytics:__subpackages__",
|
||||
"//location/nearby/analytics/cpp:__subpackages__",
|
||||
|
||||
@@ -112,6 +112,7 @@ cc_library(
|
||||
visibility = [
|
||||
"//connections:__subpackages__",
|
||||
"//internal/analytics:__subpackages__",
|
||||
"//internal/crypto:__subpackages__",
|
||||
"//internal/platform:__subpackages__",
|
||||
"//internal/proto/analytics:__subpackages__",
|
||||
"//location/nearby/cpp/sharing:__subpackages__",
|
||||
|
||||
Reference in New Issue
Block a user