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:
suetfei
2022-08-04 16:11:00 -07:00
committed by Copybara-Service
parent ce6c5893d7
commit 21c2c7c1ea
48 changed files with 5831 additions and 0 deletions
+103
View File
@@ -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",
],
)
+217
View File
@@ -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" ]
}
}
+182
View File
@@ -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
+95
View File
@@ -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_
+100
View File
@@ -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
+42
View File
@@ -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_
+182
View File
@@ -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
+96
View File
@@ -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_
+333
View File
@@ -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);
}
+30
View File
@@ -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
+65
View File
@@ -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());
}
+218
View File
@@ -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
+110
View File
@@ -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_
+572
View File
@@ -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));
}
+58
View File
@@ -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
+41
View File
@@ -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_
+114
View File
@@ -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
+125
View File
@@ -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_
+378
View File
@@ -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)));
}
+46
View File
@@ -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
+56
View File
@@ -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_
+62
View File
@@ -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
+104
View File
@@ -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_
+31
View File
@@ -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
+34
View File
@@ -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_
+41
View File
@@ -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));
}
+122
View File
@@ -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
+74
View File
@@ -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_
+386
View File
@@ -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);
}
+76
View File
@@ -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
+57
View File
@@ -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_
+117
View File
@@ -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));
}
+25
View File
@@ -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
+38
View File
@@ -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_
+47
View File
@@ -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
+51
View File
@@ -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_
+98
View File
@@ -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]));
}
+115
View File
@@ -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
+81
View File
@@ -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());
}
+140
View File
@@ -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
+89
View File
@@ -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_
+262
View File
@@ -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));
+1
View File
@@ -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__",