提交 dc325abd 编写于 作者: A Adam Barth

Remove //crypto and //services/android

These directories aren't referenced anymore.
上级 f0db1999
# 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.
component("crypto") {
output_name = "crcrypto" # Avoid colliding with OpenSSL's libcrypto.
sources = [
"random.cc",
"random.h",
]
deps = [
"//base",
]
}
agl@chromium.org
davidben@chromium.org
rsleevi@chromium.org
rvargas@chromium.org
// Copyright 2015 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.
#include "crypto/aead_openssl.h"
#if defined(USE_OPENSSL)
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <string>
#include "base/basictypes.h"
#include "base/strings/string_util.h"
#include "crypto/openssl_util.h"
namespace crypto {
Aead::Aead(AeadAlgorithm algorithm) : key_(nullptr) {
EnsureOpenSSLInit();
switch (algorithm) {
case AES_128_CTR_HMAC_SHA256:
aead_ = EVP_aead_aes_128_ctr_hmac_sha256();
break;
}
}
Aead::~Aead() {
}
void Aead::Init(const std::string* key) {
DCHECK(!key_);
DCHECK_EQ(KeyLength(), key->size());
key_ = key;
}
bool Aead::Seal(const base::StringPiece& plaintext,
const base::StringPiece& nonce,
const base::StringPiece& additional_data,
std::string* ciphertext) const {
DCHECK(key_);
DCHECK_EQ(NonceLength(), nonce.size());
EVP_AEAD_CTX ctx;
if (!EVP_AEAD_CTX_init(&ctx, aead_,
reinterpret_cast<const uint8*>(key_->data()),
key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
return false;
}
std::string result;
const size_t max_output_length =
EVP_AEAD_max_overhead(aead_) + plaintext.size();
size_t output_length;
uint8* out_ptr =
reinterpret_cast<uint8*>(base::WriteInto(&result, max_output_length + 1));
if (!EVP_AEAD_CTX_seal(
&ctx, out_ptr, &output_length, max_output_length,
reinterpret_cast<const uint8*>(nonce.data()), nonce.size(),
reinterpret_cast<const uint8*>(plaintext.data()), plaintext.size(),
reinterpret_cast<const uint8*>(additional_data.data()),
additional_data.size())) {
EVP_AEAD_CTX_cleanup(&ctx);
return false;
}
DCHECK_LE(output_length, max_output_length);
result.resize(output_length);
ciphertext->swap(result);
EVP_AEAD_CTX_cleanup(&ctx);
return true;
}
bool Aead::Open(const base::StringPiece& ciphertext,
const base::StringPiece& nonce,
const base::StringPiece& additional_data,
std::string* plaintext) const {
DCHECK(key_);
EVP_AEAD_CTX ctx;
if (!EVP_AEAD_CTX_init(&ctx, aead_,
reinterpret_cast<const uint8*>(key_->data()),
key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
return false;
}
std::string result;
const size_t max_output_length = ciphertext.size();
size_t output_length;
uint8* out_ptr =
reinterpret_cast<uint8*>(base::WriteInto(&result, max_output_length + 1));
if (!EVP_AEAD_CTX_open(
&ctx, out_ptr, &output_length, max_output_length,
reinterpret_cast<const uint8*>(nonce.data()), nonce.size(),
reinterpret_cast<const uint8*>(ciphertext.data()), ciphertext.size(),
reinterpret_cast<const uint8*>(additional_data.data()),
additional_data.size())) {
EVP_AEAD_CTX_cleanup(&ctx);
return false;
}
DCHECK_LE(output_length, max_output_length);
result.resize(output_length);
plaintext->swap(result);
EVP_AEAD_CTX_cleanup(&ctx);
return true;
}
size_t Aead::KeyLength() const {
return EVP_AEAD_key_length(aead_);
}
size_t Aead::NonceLength() const {
return EVP_AEAD_nonce_length(aead_);
}
} // namespace
#endif
// Copyright 2015 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.
#ifndef CRYPTO_AEAD_H_
#define CRYPTO_AEAD_H_
#include "base/strings/string_piece.h"
#include "crypto/crypto_export.h"
struct evp_aead_st;
namespace crypto {
// This class exposes the AES-128-CTR-HMAC-SHA256 AEAD, currently only
// for OpenSSL builds.
class CRYPTO_EXPORT Aead {
public:
enum AeadAlgorithm { AES_128_CTR_HMAC_SHA256 };
explicit Aead(AeadAlgorithm algorithm);
~Aead();
void Init(const std::string* key);
bool Seal(const base::StringPiece& plaintext,
const base::StringPiece& nonce,
const base::StringPiece& additional_data,
std::string* ciphertext) const;
bool Open(const base::StringPiece& ciphertext,
const base::StringPiece& nonce,
const base::StringPiece& additional_data,
std::string* plaintext) const;
size_t KeyLength() const;
size_t NonceLength() const;
private:
const std::string* key_;
const evp_aead_st* aead_;
};
} // namespace crypto
#endif // CRYPTO_ENCRYPTOR_H_
// Copyright 2015 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.
#include "crypto/aead_openssl.h"
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
namespace {
#if defined(USE_OPENSSL)
TEST(AeadTest, SealOpen) {
crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256);
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(AeadTest, SealOpenWrongKey) {
crypto::Aead aead(crypto::Aead::AES_128_CTR_HMAC_SHA256);
std::string key(aead.KeyLength(), 0);
std::string wrong_key(aead.KeyLength(), 1);
aead.Init(&key);
crypto::Aead aead_wrong_key(crypto::Aead::AES_128_CTR_HMAC_SHA256);
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());
}
#endif
} // namespace
// Copyright 2015 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.
#include "crypto/aes_128_gcm_helpers_nss.h"
#include <pkcs11t.h>
#include <seccomon.h>
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "crypto/ghash.h"
#include "crypto/scoped_nss_types.h"
#if defined(USE_NSS_CERTS)
#include <dlfcn.h>
#endif
namespace crypto {
namespace {
// Declaration of the prototype both PK11_Decrypt and PK11_Encrypt follow.
using PK11_TransformFunction = SECStatus(PK11SymKey* symKey,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* outLen,
unsigned int maxLen,
const unsigned char* data,
unsigned int dataLen);
// On Linux, dynamically link against the system version of libnss3.so. In
// order to continue working on systems without up-to-date versions of NSS,
// lookup PK11_Decrypt and PK11_Encrypt with dlsym.
//
// GcmSupportChecker is a singleton which caches the results of runtime symbol
// resolution of these symbols.
class GcmSupportChecker {
public:
PK11_TransformFunction* pk11_decrypt_func() { return pk11_decrypt_func_; }
PK11_TransformFunction* pk11_encrypt_func() { return pk11_encrypt_func_; }
private:
friend struct base::DefaultLazyInstanceTraits<GcmSupportChecker>;
GcmSupportChecker() {
#if !defined(USE_NSS_CERTS)
// Using a bundled version of NSS that is guaranteed to have these symbols.
pk11_decrypt_func_ = PK11_Decrypt;
pk11_encrypt_func_ = PK11_Encrypt;
#else
// Using system NSS libraries and PCKS #11 modules, which may not have the
// necessary functions (PK11_Decrypt and PK11_Encrypt) or mechanism support
// (CKM_AES_GCM).
// If PK11_Decrypt() and PK11_Encrypt() were successfully resolved, then NSS
// will support AES-GCM directly. This was introduced in NSS 3.15.
pk11_decrypt_func_ = reinterpret_cast<PK11_TransformFunction*>(
dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
pk11_encrypt_func_ = reinterpret_cast<PK11_TransformFunction*>(
dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
#endif
}
~GcmSupportChecker() {}
// |pk11_decrypt_func_| stores the runtime symbol resolution of PK11_Decrypt.
PK11_TransformFunction* pk11_decrypt_func_;
// |pk11_encrypt_func_| stores the runtime symbol resolution of PK11_Encrypt.
PK11_TransformFunction* pk11_encrypt_func_;
DISALLOW_COPY_AND_ASSIGN(GcmSupportChecker);
};
base::LazyInstance<GcmSupportChecker>::Leaky g_gcm_support_checker =
LAZY_INSTANCE_INITIALIZER;
} // namespace
// Calls PK11_Decrypt if it's available. Otherwise, emulates CKM_AES_GCM using
// CKM_AES_CTR and the GaloisHash class.
SECStatus PK11DecryptHelper(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* out_len,
unsigned int max_len,
const unsigned char* data,
unsigned int data_len) {
// If PK11_Decrypt() was successfully resolved or if bundled version of NSS is
// being used, then NSS will support AES-GCM directly.
PK11_TransformFunction* pk11_decrypt_func =
g_gcm_support_checker.Get().pk11_decrypt_func();
if (pk11_decrypt_func != nullptr) {
return pk11_decrypt_func(key, mechanism, param, out, out_len, max_len, data,
data_len);
}
// Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
// has a bug in the AES GCM code
// (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
// the PK11_Decrypt function
// (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
// resolved in NSS 3.15.
CHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
CHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
const CK_GCM_PARAMS* gcm_params =
reinterpret_cast<CK_GCM_PARAMS*>(param->data);
const CK_ULONG auth_tag_size = gcm_params->ulTagBits / 8;
if (gcm_params->ulIvLen != 12u) {
DVLOG(1) << "ulIvLen is not equal to 12";
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
SECItem my_param = {siBuffer, nullptr, 0};
// Step 2. Let H = CIPH_K(128 '0' bits).
unsigned char ghash_key[16] = {0};
crypto::ScopedPK11Context ctx(
PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
if (!ctx) {
DVLOG(1) << "PK11_CreateContextBySymKey failed";
return SECFailure;
}
int output_len;
if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
ghash_key, sizeof(ghash_key)) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (PK11_Finalize(ctx.get()) != SECSuccess) {
DVLOG(1) << "PK11_Finalize failed";
return SECFailure;
}
if (output_len != sizeof(ghash_key)) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
// Step 3. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
CK_AES_CTR_PARAMS ctr_params = {0};
ctr_params.ulCounterBits = 32;
memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
ctr_params.cb[12] = 0;
ctr_params.cb[13] = 0;
ctr_params.cb[14] = 0;
ctr_params.cb[15] = 1;
my_param.type = siBuffer;
my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
my_param.len = sizeof(ctr_params);
ctx.reset(
PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key, &my_param));
if (!ctx) {
DVLOG(1) << "PK11_CreateContextBySymKey failed";
return SECFailure;
}
// Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
unsigned char tag_mask[16] = {0};
if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
tag_mask, sizeof(tag_mask)) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (output_len != sizeof(tag_mask)) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (data_len < auth_tag_size) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
// The const_cast for |data| can be removed if system NSS libraries are
// NSS 3.14.1 or later (NSS bug
// https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
const_cast<unsigned char*>(data),
data_len - auth_tag_size) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (PK11_Finalize(ctx.get()) != SECSuccess) {
DVLOG(1) << "PK11_Finalize failed";
return SECFailure;
}
if (static_cast<unsigned int>(output_len) != data_len - auth_tag_size) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
crypto::GaloisHash ghash(ghash_key);
ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
ghash.UpdateCiphertext(data, output_len);
unsigned char auth_tag[auth_tag_size];
ghash.Finish(auth_tag, auth_tag_size);
for (unsigned int i = 0; i < auth_tag_size; i++) {
auth_tag[i] ^= tag_mask[i];
}
if (NSS_SecureMemcmp(auth_tag, data + output_len, auth_tag_size) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*out_len = output_len;
return SECSuccess;
}
// Calls PK11_Encrypt if it's available. Otherwise, emulates CKM_AES_GCM using
// CKM_AES_CTR and the GaloisHash class.
SECStatus PK11EncryptHelper(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* out_len,
unsigned int max_len,
const unsigned char* data,
unsigned int data_len) {
// If PK11_Encrypt() was successfully resolved or if bundled version of NSS is
// being used, then NSS will support AES-GCM directly.
PK11_TransformFunction* pk11_encrypt_func =
g_gcm_support_checker.Get().pk11_encrypt_func();
if (pk11_encrypt_func != nullptr) {
return pk11_encrypt_func(key, mechanism, param, out, out_len, max_len, data,
data_len);
}
// Otherwise, the user has an older version of NSS. Regrettably, NSS 3.14.x
// has a bug in the AES GCM code
// (https://bugzilla.mozilla.org/show_bug.cgi?id=853285), as well as missing
// the PK11_Encrypt function
// (https://bugzilla.mozilla.org/show_bug.cgi?id=854063), both of which are
// resolved in NSS 3.15.
CHECK_EQ(mechanism, static_cast<CK_MECHANISM_TYPE>(CKM_AES_GCM));
CHECK_EQ(param->len, sizeof(CK_GCM_PARAMS));
const CK_GCM_PARAMS* gcm_params =
reinterpret_cast<CK_GCM_PARAMS*>(param->data);
const CK_ULONG auth_tag_size = gcm_params->ulTagBits / 8;
if (max_len < auth_tag_size) {
DVLOG(1) << "max_len is less than kAuthTagSize";
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
if (gcm_params->ulIvLen != 12u) {
DVLOG(1) << "ulIvLen is not equal to 12";
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
SECItem my_param = {siBuffer, nullptr, 0};
// Step 1. Let H = CIPH_K(128 '0' bits).
unsigned char ghash_key[16] = {0};
crypto::ScopedPK11Context ctx(
PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, key, &my_param));
if (!ctx) {
DVLOG(1) << "PK11_CreateContextBySymKey failed";
return SECFailure;
}
int output_len;
if (PK11_CipherOp(ctx.get(), ghash_key, &output_len, sizeof(ghash_key),
ghash_key, sizeof(ghash_key)) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (PK11_Finalize(ctx.get()) != SECSuccess) {
DVLOG(1) << "PK11_Finalize failed";
return SECFailure;
}
if (output_len != sizeof(ghash_key)) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
// Step 2. If len(IV)=96, then let J0 = IV || 31 '0' bits || 1.
CK_AES_CTR_PARAMS ctr_params = {0};
ctr_params.ulCounterBits = 32;
memcpy(ctr_params.cb, gcm_params->pIv, gcm_params->ulIvLen);
ctr_params.cb[12] = 0;
ctr_params.cb[13] = 0;
ctr_params.cb[14] = 0;
ctr_params.cb[15] = 1;
my_param.type = siBuffer;
my_param.data = reinterpret_cast<unsigned char*>(&ctr_params);
my_param.len = sizeof(ctr_params);
ctx.reset(
PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, key, &my_param));
if (!ctx) {
DVLOG(1) << "PK11_CreateContextBySymKey failed";
return SECFailure;
}
// Step 6. Calculate the encryption mask of GCTR_K(J0, ...).
unsigned char tag_mask[16] = {0};
if (PK11_CipherOp(ctx.get(), tag_mask, &output_len, sizeof(tag_mask),
tag_mask, sizeof(tag_mask)) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (output_len != sizeof(tag_mask)) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
// The const_cast for |data| can be removed if system NSS libraries are
// NSS 3.14.1 or later (NSS bug
// https://bugzilla.mozilla.org/show_bug.cgi?id=808218).
if (PK11_CipherOp(ctx.get(), out, &output_len, max_len,
const_cast<unsigned char*>(data), data_len) != SECSuccess) {
DVLOG(1) << "PK11_CipherOp failed";
return SECFailure;
}
if (PK11_Finalize(ctx.get()) != SECSuccess) {
DVLOG(1) << "PK11_Finalize failed";
return SECFailure;
}
if (static_cast<unsigned int>(output_len) != data_len) {
DVLOG(1) << "Wrong output length";
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if ((max_len - auth_tag_size) < static_cast<unsigned int>(output_len)) {
DVLOG(1) << "(max_len - kAuthTagSize) is less than output_len";
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
crypto::GaloisHash ghash(ghash_key);
ghash.UpdateAdditional(gcm_params->pAAD, gcm_params->ulAADLen);
ghash.UpdateCiphertext(out, output_len);
ghash.Finish(out + output_len, auth_tag_size);
for (unsigned int i = 0; i < auth_tag_size; i++) {
out[output_len + i] ^= tag_mask[i];
}
*out_len = output_len + auth_tag_size;
return SECSuccess;
}
} // namespace crypto
// Copyright 2015 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.
#ifndef CRYPTO_AES_128_GCM_HELPERS_NSS_H_
#define CRYPTO_AES_128_GCM_HELPERS_NSS_H_
#include <pk11pub.h>
#include <secerr.h>
#include "crypto/crypto_export.h"
namespace crypto {
// When using the CKM_AES_GCM mechanism, one must consider that the mechanism
// had a bug in NSS 3.14.x (https://bugzilla.mozilla.org/show_bug.cgi?id=853285)
// which also lacks the PK11_Decrypt and PK11_Encrypt functions.
// (https://bugzilla.mozilla.org/show_bug.cgi?id=854063)
//
// While both these bugs were resolved in NSS 3.15, certain builds of Chromium
// may still be loading older versions of NSS as the system libraries. These
// helper methods emulate support by using CKM_AES_CTR and the GaloisHash.
// Helper function for using PK11_Decrypt. |mechanism| must be set to
// CKM_AES_GCM for this method.
CRYPTO_EXPORT SECStatus PK11DecryptHelper(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* out_len,
unsigned int max_len,
const unsigned char* data,
unsigned int data_len);
// Helper function for using PK11_Encrypt. |mechanism| must be set to
// CKM_AES_GCM for this method.
CRYPTO_EXPORT SECStatus PK11EncryptHelper(PK11SymKey* key,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* out_len,
unsigned int max_len,
const unsigned char* data,
unsigned int data_len);
} // namespace crypto
#endif // CRYPTO_AES_128_GCM_HELPERS_NSS_H_
// Copyright 2015 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.
#include "crypto/aes_128_gcm_helpers_nss.h"
#include <pk11pub.h>
#include <secerr.h>
#include <string>
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "crypto/nss_util.h"
#include "crypto/random.h"
#include "crypto/scoped_nss_types.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace crypto {
namespace {
// The AES GCM test vectors come from the gcmDecrypt128.rsp and
// gcmEncryptExtIV128.rsp files downloaded from
// http://csrc.nist.gov/groups/STM/cavp/index.html on 2013-02-01. The test
// vectors in that file look like this:
//
// [Keylen = 128]
// [IVlen = 96]
// [PTlen = 0]
// [AADlen = 0]
// [Taglen = 128]
//
// Count = 0
// Key = cf063a34d4a9a76c2c86787d3f96db71
// IV = 113b9785971864c83b01c787
// CT =
// AAD =
// Tag = 72ac8493e3a5228b5d130a69d2510e42
// PT =
//
// Count = 1
// Key = a49a5e26a2f8cb63d05546c2a62f5343
// IV = 907763b19b9b4ab6bd4f0281
// CT =
// AAD =
// Tag = a2be08210d8c470a8df6e8fbd79ec5cf
// FAIL
//
// ...
//
// These files are huge (2.6 MB and 2.8 MB), so this file contains just a
// selection of test vectors.
// Describes a group of test vectors that all have a given key length, IV
// length, plaintext length, AAD length, and tag length.
struct TestGroupInfo {
size_t key_len;
size_t iv_len;
size_t input_len;
size_t aad_len;
size_t tag_len;
};
// Each test vector consists of six strings of lowercase hexadecimal digits.
// The strings may be empty (zero length). A test vector with a NULL |key|
// marks the end of an array of test vectors.
struct TestVector {
// Input:
const char* key;
const char* iv;
const char* input;
const char* aad;
const char* tag;
// Expected output:
const char* output; // An empty string "" means decryption or encryption
// succeeded and the plaintext is zero-length. NULL means
// that the decryption or encryption failed.
};
const TestGroupInfo test_group_info[] = {
{128, 96, 0, 0, 128},
{128, 96, 0, 128, 128},
{128, 96, 128, 0, 128},
{128, 96, 408, 160, 128},
{128, 96, 408, 720, 128},
{128, 96, 104, 0, 128},
};
const TestVector decryption_test_group_0[] = {
{"cf063a34d4a9a76c2c86787d3f96db71",
"113b9785971864c83b01c787",
"",
"",
"72ac8493e3a5228b5d130a69d2510e42",
""},
{
"a49a5e26a2f8cb63d05546c2a62f5343",
"907763b19b9b4ab6bd4f0281",
"",
"",
"a2be08210d8c470a8df6e8fbd79ec5cf",
NULL // FAIL
},
{NULL}};
const TestVector decryption_test_group_1[] = {
{
"d1f6af919cde85661208bdce0c27cb22",
"898c6929b435017bf031c3c5",
"",
"7c5faa40e636bbc91107e68010c92b9f",
"ae45f11777540a2caeb128be8092468a",
NULL // FAIL
},
{"2370e320d4344208e0ff5683f243b213",
"04dbb82f044d30831c441228",
"",
"d43a8e5089eea0d026c03a85178b27da",
"2a049c049d25aa95969b451d93c31c6e",
""},
{NULL}};
const TestVector decryption_test_group_2[] = {
{"e98b72a9881a84ca6b76e0f43e68647a",
"8b23299fde174053f3d652ba",
"5a3c1cf1985dbb8bed818036fdd5ab42",
"",
"23c7ab0f952b7091cd324835043b5eb5",
"28286a321293253c3e0aa2704a278032"},
{"33240636cd3236165f1a553b773e728e",
"17c4d61493ecdc8f31700b12",
"47bb7e23f7bdfe05a8091ac90e4f8b2e",
"",
"b723c70e931d9785f40fd4ab1d612dc9",
"95695a5b12f2870b9cc5fdc8f218a97d"},
{
"5164df856f1e9cac04a79b808dc5be39",
"e76925d5355e0584ce871b2b",
"0216c899c88d6e32c958c7e553daa5bc",
"",
"a145319896329c96df291f64efbe0e3a",
NULL // FAIL
},
{NULL}};
const TestVector decryption_test_group_3[] = {
{"af57f42c60c0fc5a09adb81ab86ca1c3",
"a2dc01871f37025dc0fc9a79",
"b9a535864f48ea7b6b1367914978f9bfa087d854bb0e269bed8d279d2eea1210e48947"
"338b22f9bad09093276a331e9c79c7f4",
"41dc38988945fcb44faf2ef72d0061289ef8efd8",
"4f71e72bde0018f555c5adcce062e005",
"3803a0727eeb0ade441e0ec107161ded2d425ec0d102f21f51bf2cf9947c7ec4aa7279"
"5b2f69b041596e8817d0a3c16f8fadeb"},
{"ebc753e5422b377d3cb64b58ffa41b61",
"2e1821efaced9acf1f241c9b",
"069567190554e9ab2b50a4e1fbf9c147340a5025fdbd201929834eaf6532325899ccb9"
"f401823e04b05817243d2142a3589878",
"b9673412fd4f88ba0e920f46dd6438ff791d8eef",
"534d9234d2351cf30e565de47baece0b",
"39077edb35e9c5a4b1e4c2a6b9bb1fce77f00f5023af40333d6d699014c2bcf4209c18"
"353a18017f5b36bfc00b1f6dcb7ed485"},
{
"52bdbbf9cf477f187ec010589cb39d58",
"d3be36d3393134951d324b31",
"700188da144fa692cf46e4a8499510a53d90903c967f7f13e8a1bd8151a74adc4fe63e"
"32b992760b3a5f99e9a47838867000a9",
"93c4fc6a4135f54d640b0c976bf755a06a292c33",
"8ca4e38aa3dfa6b1d0297021ccf3ea5f",
NULL // FAIL
},
{NULL}};
const TestVector decryption_test_group_4[] = {
{"da2bb7d581493d692380c77105590201",
"44aa3e7856ca279d2eb020c6",
"9290d430c9e89c37f0446dbd620c9a6b34b1274aeb6f911f75867efcf95b6feda69f1a"
"f4ee16c761b3c9aeac3da03aa9889c88",
"4cd171b23bddb3a53cdf959d5c1710b481eb3785a90eb20a2345ee00d0bb7868c367ab"
"12e6f4dd1dee72af4eee1d197777d1d6499cc541f34edbf45cda6ef90b3c024f9272d7"
"2ec1909fb8fba7db88a4d6f7d3d925980f9f9f72",
"9e3ac938d3eb0cadd6f5c9e35d22ba38",
"9bbf4c1a2742f6ac80cb4e8a052e4a8f4f07c43602361355b717381edf9fabd4cb7e3a"
"d65dbd1378b196ac270588dd0621f642"},
{"d74e4958717a9d5c0e235b76a926cae8",
"0b7471141e0c70b1995fd7b1",
"e701c57d2330bf066f9ff8cf3ca4343cafe4894651cd199bdaaa681ba486b4a65c5a22"
"b0f1420be29ea547d42c713bc6af66aa",
"4a42b7aae8c245c6f1598a395316e4b8484dbd6e64648d5e302021b1d3fa0a38f46e22"
"bd9c8080b863dc0016482538a8562a4bd0ba84edbe2697c76fd039527ac179ec5506cf"
"34a6039312774cedebf4961f3978b14a26509f96",
"e192c23cb036f0b31592989119eed55d",
"840d9fb95e32559fb3602e48590280a172ca36d9b49ab69510f5bd552bfab7a306f85f"
"f0a34bc305b88b804c60b90add594a17"},
{
"1986310c725ac94ecfe6422e75fc3ee7",
"93ec4214fa8e6dc4e3afc775",
"b178ec72f85a311ac4168f42a4b2c23113fbea4b85f4b9dabb74e143eb1b8b0a361e02"
"43edfd365b90d5b325950df0ada058f9",
"e80b88e62c49c958b5e0b8b54f532d9ff6aa84c8a40132e93e55b59fc24e8decf28463"
"139f155d1e8ce4ee76aaeefcd245baa0fc519f83a5fb9ad9aa40c4b21126013f576c42"
"72c2cb136c8fd091cc4539877a5d1e72d607f960",
"8b347853f11d75e81e8a95010be81f17",
NULL // FAIL
},
{NULL}};
const TestVector decryption_test_group_5[] = {
{"387218b246c1a8257748b56980e50c94",
"dd7e014198672be39f95b69d",
"cdba9e73eaf3d38eceb2b04a8d",
"",
"ecf90f4a47c9c626d6fb2c765d201556",
"48f5b426baca03064554cc2b30"},
{"294de463721e359863887c820524b3d4",
"3338b35c9d57a5d28190e8c9",
"2f46634e74b8e4c89812ac83b9",
"",
"dabd506764e68b82a7e720aa18da0abe",
"46a2e55c8e264df211bd112685"},
{"28ead7fd2179e0d12aa6d5d88c58c2dc",
"5055347f18b4d5add0ae5c41",
"142d8210c3fb84774cdbd0447a",
"",
"5fd321d9cdb01952dc85f034736c2a7d",
"3b95b981086ee73cc4d0cc1422"},
{
"7d7b6c988137b8d470c57bf674a09c87",
"9edf2aa970d016ac962e1fd8",
"a85b66c3cb5eab91d5bdc8bc0e",
"",
"dc054efc01f3afd21d9c2484819f569a",
NULL // FAIL
},
{NULL}};
const TestVector encryption_test_group_0[] = {
{"11754cd72aec309bf52f7687212e8957",
"3c819d9a9bed087615030b65",
"",
"",
"250327c674aaf477aef2675748cf6971",
""},
{"ca47248ac0b6f8372a97ac43508308ed",
"ffd2b598feabc9019262d2be",
"",
"",
"60d20404af527d248d893ae495707d1a",
""},
{NULL}};
const TestVector encryption_test_group_1[] = {
{"77be63708971c4e240d1cb79e8d77feb",
"e0e00f19fed7ba0136a797f3",
"",
"7a43ec1d9c0a5a78a0b16533a6213cab",
"209fcc8d3675ed938e9c7166709dd946",
""},
{"7680c5d3ca6154758e510f4d25b98820",
"f8f105f9c3df4965780321f8",
"",
"c94c410194c765e3dcc7964379758ed3",
"94dca8edfcf90bb74b153c8d48a17930",
""},
{NULL}};
const TestVector encryption_test_group_2[] = {
{"7fddb57453c241d03efbed3ac44e371c",
"ee283a3fc75575e33efd4887",
"d5de42b461646c255c87bd2962d3b9a2",
"",
"b36d1df9b9d5e596f83e8b7f52971cb3",
"2ccda4a5415cb91e135c2a0f78c9b2fd"},
{"ab72c77b97cb5fe9a382d9fe81ffdbed",
"54cc7dc2c37ec006bcc6d1da",
"007c5e5b3e59df24a7c355584fc1518d",
"",
"2b4401346697138c7a4891ee59867d0c",
"0e1bde206a07a9c2c1b65300f8c64997"},
{NULL}};
const TestVector encryption_test_group_3[] = {
{"fe47fcce5fc32665d2ae399e4eec72ba",
"5adb9609dbaeb58cbd6e7275",
"7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1"
"b840382c4bccaf3bafb4ca8429bea063",
"88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
"291ef1982e4defedaa2249f898556b47",
"98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf539304373636525"
"3ddbc5db8778371495da76d269e5db3e"},
{"ec0c2ba17aa95cd6afffe949da9cc3a8",
"296bce5b50b7d66096d627ef",
"b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987"
"b764b9611f6c0f8641843d5d58f3a242",
"f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
"890147971946b627c40016da1ecf3e77",
"a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a0716299"
"5506fde6309ffc19e716eddf1a828c5a"},
{NULL}};
const TestVector encryption_test_group_4[] = {
{"2c1f21cf0f6fb3661943155c3e3d8492",
"23cb5ff362e22426984d1907",
"42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d6"
"8b5615ba7c1220ff6510e259f06655d8",
"5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e"
"3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f"
"4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
"57a3ee28136e94c74838997ae9823f3a",
"81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222"
"b6ad57af43e1895df9dca2a5344a62cc"},
{"d9f7d2411091f947b4d6f1e2d1f0fb2e",
"e1934f5db57cc983e6b180e7",
"73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490"
"c2c6f6166f4a59431e182663fcaea05a",
"0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d"
"0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a201"
"15d2e51398344b16bee1ed7c499b353d6c597af8",
"21b51ca862cb637cdd03b99a0f93b134",
"aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d57"
"3c7891c2a91fbc48db29967ec9542b23"},
{NULL}};
const TestVector encryption_test_group_5[] = {
{"fe9bb47deb3a61e423c2231841cfd1fb",
"4d328eb776f500a2f7fb47aa",
"f1cc3818e421876bb6b8bbd6c9",
"",
"43fd4727fe5cdb4b5b42818dea7ef8c9",
"b88c5c1977b35b517b0aeae967"},
{"6703df3701a7f54911ca72e24dca046a",
"12823ab601c350ea4bc2488c",
"793cd125b0b84a043e3ac67717",
"",
"38e6bcd29962e5f2c13626b85a877101",
"b2051c80014f42f08735a7b0cd"},
{NULL}};
const TestVector* const decryption_test_group_array[] = {
decryption_test_group_0,
decryption_test_group_1,
decryption_test_group_2,
decryption_test_group_3,
decryption_test_group_4,
decryption_test_group_5,
};
const TestVector* const encryption_test_group_array[] = {
encryption_test_group_0,
encryption_test_group_1,
encryption_test_group_2,
encryption_test_group_3,
encryption_test_group_4,
encryption_test_group_5,
};
bool DecodeHexString(const base::StringPiece& hex, std::string* bytes) {
bytes->clear();
if (hex.empty())
return true;
std::vector<uint8> v;
if (!base::HexStringToBytes(hex.as_string(), &v))
return false;
if (!v.empty())
bytes->assign(reinterpret_cast<const char*>(&v[0]), v.size());
return true;
}
class Aes128GcmHelpersTest : public ::testing::Test {
public:
enum Mode { DECRYPT, ENCRYPT };
void SetUp() override { EnsureNSSInit(); }
bool DecryptOrEncrypt(Mode mode,
const base::StringPiece& input,
const base::StringPiece& key,
const base::StringPiece& nonce,
const base::StringPiece& aad,
size_t auth_tag_size,
std::string* output) {
DCHECK(output);
const CK_ATTRIBUTE_TYPE cka_mode =
mode == DECRYPT ? CKA_DECRYPT : CKA_ENCRYPT;
SECItem key_item;
key_item.type = siBuffer;
key_item.data = const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(key.data()));
key_item.len = key.size();
crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
DCHECK(slot);
crypto::ScopedPK11SymKey aead_key(
PK11_ImportSymKey(slot.get(), CKM_AES_GCM, PK11_OriginUnwrap, cka_mode,
&key_item, nullptr));
CK_GCM_PARAMS gcm_params;
gcm_params.pIv = const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(nonce.data()));
gcm_params.ulIvLen = nonce.size();
gcm_params.pAAD = const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(aad.data()));
gcm_params.ulAADLen = aad.size();
gcm_params.ulTagBits = auth_tag_size * 8;
SECItem param;
param.type = siBuffer;
param.data = reinterpret_cast<unsigned char*>(&gcm_params);
param.len = sizeof(CK_GCM_PARAMS);
size_t maximum_output_length = input.size();
if (mode == ENCRYPT)
maximum_output_length += auth_tag_size;
unsigned int output_length = 0;
unsigned char* raw_input = const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(input.data()));
unsigned char* raw_output = reinterpret_cast<unsigned char*>(
base::WriteInto(output, maximum_output_length + 1 /* null */));
PK11Helper_TransformFunction* transform_function =
mode == DECRYPT ? PK11DecryptHelper : PK11EncryptHelper;
const SECStatus result = transform_function(
aead_key.get(), CKM_AES_GCM, &param, raw_output, &output_length,
maximum_output_length, raw_input, input.size());
if (result != SECSuccess)
return false;
const size_t expected_output_length = mode == DECRYPT
? input.size() - auth_tag_size
: input.size() + auth_tag_size;
EXPECT_EQ(expected_output_length, output_length);
output->resize(expected_output_length);
return true;
}
private:
// The prototype of PK11_Decrypt and PK11_Encrypt.
using PK11Helper_TransformFunction = SECStatus(PK11SymKey* symKey,
CK_MECHANISM_TYPE mechanism,
SECItem* param,
unsigned char* out,
unsigned int* outLen,
unsigned int maxLen,
const unsigned char* data,
unsigned int dataLen);
};
} // namespace
TEST_F(Aes128GcmHelpersTest, RoundTrip) {
const std::string message = "Hello, world!";
const size_t kKeySize = 16;
const size_t kNonceSize = 16;
std::string key, nonce;
RandBytes(base::WriteInto(&key, kKeySize + 1), kKeySize);
RandBytes(base::WriteInto(&nonce, kNonceSize + 1), kNonceSize);
// AEAD_AES_128_GCM is defined with a default authentication tag size of 16,
// but RFC 5282 extends this to authentication tag sizes of 8 and 12 as well.
size_t auth_tag_size = base::RandInt(2, 4) * 4;
std::string encrypted;
ASSERT_TRUE(DecryptOrEncrypt(ENCRYPT, message, key, nonce,
base::StringPiece(), auth_tag_size, &encrypted));
std::string decrypted;
ASSERT_TRUE(DecryptOrEncrypt(DECRYPT, encrypted, key, nonce,
base::StringPiece(), auth_tag_size, &decrypted));
EXPECT_EQ(message, decrypted);
}
TEST_F(Aes128GcmHelpersTest, DecryptionVectors) {
for (size_t i = 0; i < arraysize(decryption_test_group_array); i++) {
SCOPED_TRACE(i);
const TestVector* test_vectors = decryption_test_group_array[i];
const TestGroupInfo& test_info = test_group_info[i];
for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
// If not present then decryption is expected to fail.
bool has_output = test_vectors[j].output;
// Decode the test vector.
std::string key, iv, input, aad, tag, expected_output;
ASSERT_TRUE(DecodeHexString(test_vectors[j].key, &key));
ASSERT_TRUE(DecodeHexString(test_vectors[j].iv, &iv));
ASSERT_TRUE(DecodeHexString(test_vectors[j].input, &input));
ASSERT_TRUE(DecodeHexString(test_vectors[j].aad, &aad));
ASSERT_TRUE(DecodeHexString(test_vectors[j].tag, &tag));
if (has_output)
ASSERT_TRUE(DecodeHexString(test_vectors[j].output, &expected_output));
// The test vector's lengths should look sane. Note that the lengths
// in |test_info| are in bits.
EXPECT_EQ(test_info.key_len, key.length() * 8);
EXPECT_EQ(test_info.iv_len, iv.length() * 8);
EXPECT_EQ(test_info.input_len, input.length() * 8);
EXPECT_EQ(test_info.aad_len, aad.length() * 8);
EXPECT_EQ(test_info.tag_len, tag.length() * 8);
if (has_output)
EXPECT_EQ(test_info.input_len, expected_output.length() * 8);
const std::string ciphertext = input + tag;
std::string output;
if (!DecryptOrEncrypt(DECRYPT, ciphertext, key, iv, aad, tag.length(),
&output)) {
EXPECT_FALSE(has_output);
continue;
}
EXPECT_TRUE(has_output);
EXPECT_EQ(expected_output, output);
}
}
}
TEST_F(Aes128GcmHelpersTest, EncryptionVectors) {
for (size_t i = 0; i < arraysize(encryption_test_group_array); i++) {
SCOPED_TRACE(i);
const TestVector* test_vectors = encryption_test_group_array[i];
const TestGroupInfo& test_info = test_group_info[i];
for (size_t j = 0; test_vectors[j].key != nullptr; j++) {
// If not present then decryption is expected to fail.
bool has_output = test_vectors[j].output;
// Decode the test vector.
std::string key, iv, input, aad, tag, expected_output;
ASSERT_TRUE(DecodeHexString(test_vectors[j].key, &key));
ASSERT_TRUE(DecodeHexString(test_vectors[j].iv, &iv));
ASSERT_TRUE(DecodeHexString(test_vectors[j].input, &input));
ASSERT_TRUE(DecodeHexString(test_vectors[j].aad, &aad));
ASSERT_TRUE(DecodeHexString(test_vectors[j].tag, &tag));
if (has_output)
ASSERT_TRUE(DecodeHexString(test_vectors[j].output, &expected_output));
// The test vector's lengths should look sane. Note that the lengths
// in |test_info| are in bits.
EXPECT_EQ(test_info.key_len, key.length() * 8);
EXPECT_EQ(test_info.iv_len, iv.length() * 8);
EXPECT_EQ(test_info.input_len, input.length() * 8);
EXPECT_EQ(test_info.aad_len, aad.length() * 8);
EXPECT_EQ(test_info.tag_len, tag.length() * 8);
if (has_output)
EXPECT_EQ(test_info.input_len, expected_output.length() * 8);
std::string output;
if (!DecryptOrEncrypt(ENCRYPT, input, key, iv, aad, tag.length(),
&output)) {
EXPECT_FALSE(has_output);
continue;
}
const std::string expected_output_with_tag = expected_output + tag;
EXPECT_TRUE(has_output);
EXPECT_EQ(expected_output_with_tag, output);
}
}
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_KEYCHAIN_MAC_H_
#define CRYPTO_KEYCHAIN_MAC_H_
#include <Security/Security.h>
#include "base/basictypes.h"
#include "crypto/crypto_export.h"
#if defined (OS_IOS)
typedef void* SecKeychainRef;
typedef void* SecKeychainItemRef;
typedef void SecKeychainAttributeList;
#endif
namespace crypto {
// Wraps the KeychainServices API in a very thin layer, to allow it to be
// mocked out for testing.
// See Keychain Services documentation for function documentation, as these call
// through directly to their Keychain Services equivalents (Foo ->
// SecKeychainFoo). The only exception is Free, which should be used for
// anything returned from this class that would normally be freed with
// CFRelease (to aid in testing).
class CRYPTO_EXPORT AppleKeychain {
public:
AppleKeychain();
virtual ~AppleKeychain();
virtual OSStatus FindGenericPassword(CFTypeRef keychainOrArray,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32* passwordLength,
void** passwordData,
SecKeychainItemRef* itemRef) const;
virtual OSStatus ItemFreeContent(SecKeychainAttributeList* attrList,
void* data) const;
virtual OSStatus AddGenericPassword(SecKeychainRef keychain,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32 passwordLength,
const void* passwordData,
SecKeychainItemRef* itemRef) const;
#if !defined(OS_IOS)
virtual OSStatus ItemCopyAttributesAndData(
SecKeychainItemRef itemRef,
SecKeychainAttributeInfo* info,
SecItemClass* itemClass,
SecKeychainAttributeList** attrList,
UInt32* length,
void** outData) const;
virtual OSStatus ItemModifyAttributesAndData(
SecKeychainItemRef itemRef,
const SecKeychainAttributeList* attrList,
UInt32 length,
const void* data) const;
virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList* attrList,
void* data) const;
virtual OSStatus ItemDelete(SecKeychainItemRef itemRef) const;
virtual OSStatus SearchCreateFromAttributes(
CFTypeRef keychainOrArray,
SecItemClass itemClass,
const SecKeychainAttributeList* attrList,
SecKeychainSearchRef* searchRef) const;
virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
SecKeychainItemRef* itemRef) const;
virtual OSStatus AddInternetPassword(SecKeychainRef keychain,
UInt32 serverNameLength,
const char* serverName,
UInt32 securityDomainLength,
const char* securityDomain,
UInt32 accountNameLength,
const char* accountName,
UInt32 pathLength, const char* path,
UInt16 port, SecProtocolType protocol,
SecAuthenticationType authenticationType,
UInt32 passwordLength,
const void* passwordData,
SecKeychainItemRef* itemRef) const;
// Calls CFRelease on the given ref, after checking that |ref| is non-NULL.
virtual void Free(CFTypeRef ref) const;
#endif // !defined(OS_IOS)
private:
DISALLOW_COPY_AND_ASSIGN(AppleKeychain);
};
} // namespace crypto
#endif // CRYPTO_KEYCHAIN_MAC_H_
// Copyright (c) 2012 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.
#include "crypto/apple_keychain.h"
#import <Foundation/Foundation.h>
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
namespace {
enum KeychainAction {
kKeychainActionCreate,
kKeychainActionUpdate
};
// Creates a dictionary that can be used to query the keystore.
// Ownership follows the Create rule.
CFDictionaryRef CreateGenericPasswordQuery(UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName) {
CFMutableDictionaryRef query =
CFDictionaryCreateMutable(NULL,
5,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Type of element is generic password.
CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
// Set the service name.
base::scoped_nsobject<NSString> service_name_ns(
[[NSString alloc] initWithBytes:serviceName
length:serviceNameLength
encoding:NSUTF8StringEncoding]);
CFDictionarySetValue(query, kSecAttrService,
base::mac::NSToCFCast(service_name_ns));
// Set the account name.
base::scoped_nsobject<NSString> account_name_ns(
[[NSString alloc] initWithBytes:accountName
length:accountNameLength
encoding:NSUTF8StringEncoding]);
CFDictionarySetValue(query, kSecAttrAccount,
base::mac::NSToCFCast(account_name_ns));
// Use the proper search constants, return only the data of the first match.
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
return query;
}
// Creates a dictionary conatining the data to save into the keychain.
// Ownership follows the Create rule.
CFDictionaryRef CreateKeychainData(UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32 passwordLength,
const void* passwordData,
KeychainAction action) {
CFMutableDictionaryRef keychain_data =
CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Set the password.
NSData* password = [NSData dataWithBytes:passwordData length:passwordLength];
CFDictionarySetValue(keychain_data, kSecValueData,
base::mac::NSToCFCast(password));
// If this is not a creation, no structural information is needed.
if (action != kKeychainActionCreate)
return keychain_data;
// Set the type of the data.
CFDictionarySetValue(keychain_data, kSecClass, kSecClassGenericPassword);
// Only allow access when the device has been unlocked.
CFDictionarySetValue(keychain_data,
kSecAttrAccessible,
kSecAttrAccessibleWhenUnlocked);
// Set the service name.
base::scoped_nsobject<NSString> service_name_ns(
[[NSString alloc] initWithBytes:serviceName
length:serviceNameLength
encoding:NSUTF8StringEncoding]);
CFDictionarySetValue(keychain_data, kSecAttrService,
base::mac::NSToCFCast(service_name_ns));
// Set the account name.
base::scoped_nsobject<NSString> account_name_ns(
[[NSString alloc] initWithBytes:accountName
length:accountNameLength
encoding:NSUTF8StringEncoding]);
CFDictionarySetValue(keychain_data, kSecAttrAccount,
base::mac::NSToCFCast(account_name_ns));
return keychain_data;
}
} // namespace
namespace crypto {
AppleKeychain::AppleKeychain() {}
AppleKeychain::~AppleKeychain() {}
OSStatus AppleKeychain::ItemFreeContent(SecKeychainAttributeList* attrList,
void* data) const {
free(data);
return noErr;
}
OSStatus AppleKeychain::AddGenericPassword(SecKeychainRef keychain,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32 passwordLength,
const void* passwordData,
SecKeychainItemRef* itemRef) const {
base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery(
serviceNameLength, serviceName, accountNameLength, accountName));
// Check that there is not already a password.
OSStatus status = SecItemCopyMatching(query, NULL);
if (status == errSecItemNotFound) {
// A new entry must be created.
base::ScopedCFTypeRef<CFDictionaryRef> keychain_data(
CreateKeychainData(serviceNameLength,
serviceName,
accountNameLength,
accountName,
passwordLength,
passwordData,
kKeychainActionCreate));
status = SecItemAdd(keychain_data, NULL);
} else if (status == noErr) {
// The entry must be updated.
base::ScopedCFTypeRef<CFDictionaryRef> keychain_data(
CreateKeychainData(serviceNameLength,
serviceName,
accountNameLength,
accountName,
passwordLength,
passwordData,
kKeychainActionUpdate));
status = SecItemUpdate(query, keychain_data);
}
return status;
}
OSStatus AppleKeychain::FindGenericPassword(CFTypeRef keychainOrArray,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32* passwordLength,
void** passwordData,
SecKeychainItemRef* itemRef) const {
DCHECK((passwordData && passwordLength) ||
(!passwordData && !passwordLength));
base::ScopedCFTypeRef<CFDictionaryRef> query(CreateGenericPasswordQuery(
serviceNameLength, serviceName, accountNameLength, accountName));
// Get the keychain item containing the password.
CFTypeRef resultRef = NULL;
OSStatus status = SecItemCopyMatching(query, &resultRef);
base::ScopedCFTypeRef<CFTypeRef> result(resultRef);
if (status != noErr) {
if (passwordData) {
*passwordData = NULL;
*passwordLength = 0;
}
return status;
}
if (passwordData) {
CFDataRef data = base::mac::CFCast<CFDataRef>(result);
NSUInteger length = CFDataGetLength(data);
*passwordData = malloc(length * sizeof(UInt8));
CFDataGetBytes(data, CFRangeMake(0, length), (UInt8*)*passwordData);
*passwordLength = length;
}
return status;
}
} // namespace crypto
// Copyright (c) 2012 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.
#include "crypto/apple_keychain.h"
#import <Foundation/Foundation.h>
#include "base/synchronization/lock.h"
#include "crypto/mac_security_services_lock.h"
namespace crypto {
AppleKeychain::AppleKeychain() {}
AppleKeychain::~AppleKeychain() {}
OSStatus AppleKeychain::ItemCopyAttributesAndData(
SecKeychainItemRef itemRef,
SecKeychainAttributeInfo* info,
SecItemClass* itemClass,
SecKeychainAttributeList** attrList,
UInt32* length,
void** outData) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
attrList, length, outData);
}
OSStatus AppleKeychain::ItemModifyAttributesAndData(
SecKeychainItemRef itemRef,
const SecKeychainAttributeList* attrList,
UInt32 length,
const void* data) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainItemModifyAttributesAndData(itemRef, attrList, length,
data);
}
OSStatus AppleKeychain::ItemFreeAttributesAndData(
SecKeychainAttributeList* attrList,
void* data) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainItemFreeAttributesAndData(attrList, data);
}
OSStatus AppleKeychain::ItemDelete(SecKeychainItemRef itemRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainItemDelete(itemRef);
}
OSStatus AppleKeychain::SearchCreateFromAttributes(
CFTypeRef keychainOrArray,
SecItemClass itemClass,
const SecKeychainAttributeList* attrList,
SecKeychainSearchRef* searchRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainSearchCreateFromAttributes(keychainOrArray, itemClass,
attrList, searchRef);
}
OSStatus AppleKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
SecKeychainItemRef* itemRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainSearchCopyNext(searchRef, itemRef);
}
OSStatus AppleKeychain::AddInternetPassword(
SecKeychainRef keychain,
UInt32 serverNameLength,
const char* serverName,
UInt32 securityDomainLength,
const char* securityDomain,
UInt32 accountNameLength,
const char* accountName,
UInt32 pathLength,
const char* path,
UInt16 port,
SecProtocolType protocol,
SecAuthenticationType authenticationType,
UInt32 passwordLength,
const void* passwordData,
SecKeychainItemRef* itemRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainAddInternetPassword(keychain,
serverNameLength, serverName,
securityDomainLength, securityDomain,
accountNameLength, accountName,
pathLength, path,
port, protocol, authenticationType,
passwordLength, passwordData,
itemRef);
}
OSStatus AppleKeychain::FindGenericPassword(CFTypeRef keychainOrArray,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32* passwordLength,
void** passwordData,
SecKeychainItemRef* itemRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainFindGenericPassword(keychainOrArray,
serviceNameLength,
serviceName,
accountNameLength,
accountName,
passwordLength,
passwordData,
itemRef);
}
OSStatus AppleKeychain::ItemFreeContent(SecKeychainAttributeList* attrList,
void* data) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainItemFreeContent(attrList, data);
}
OSStatus AppleKeychain::AddGenericPassword(SecKeychainRef keychain,
UInt32 serviceNameLength,
const char* serviceName,
UInt32 accountNameLength,
const char* accountName,
UInt32 passwordLength,
const void* passwordData,
SecKeychainItemRef* itemRef) const {
base::AutoLock lock(GetMacSecurityServicesLock());
return SecKeychainAddGenericPassword(keychain,
serviceNameLength,
serviceName,
accountNameLength,
accountName,
passwordLength,
passwordData,
itemRef);
}
void AppleKeychain::Free(CFTypeRef ref) const {
if (ref)
CFRelease(ref);
}
} // namespace crypto
// Copyright (c) 2011 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.
#include "crypto/capi_util.h"
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
namespace {
class CAPIUtilSingleton {
public:
static CAPIUtilSingleton* GetInstance() {
return Singleton<CAPIUtilSingleton>::get();
}
// Returns a lock to guard calls to CryptAcquireContext with
// CRYPT_DELETEKEYSET or CRYPT_NEWKEYSET.
base::Lock& acquire_context_lock() {
return acquire_context_lock_;
}
private:
friend class Singleton<CAPIUtilSingleton>;
friend struct DefaultSingletonTraits<CAPIUtilSingleton>;
CAPIUtilSingleton() {}
base::Lock acquire_context_lock_;
DISALLOW_COPY_AND_ASSIGN(CAPIUtilSingleton);
};
} // namespace
namespace crypto {
BOOL CryptAcquireContextLocked(HCRYPTPROV* prov,
LPCWSTR container,
LPCWSTR provider,
DWORD prov_type,
DWORD flags) {
base::AutoLock lock(CAPIUtilSingleton::GetInstance()->acquire_context_lock());
return CryptAcquireContext(prov, container, provider, prov_type, flags);
}
void* WINAPI CryptAlloc(size_t size) {
return malloc(size);
}
void WINAPI CryptFree(void* p) {
free(p);
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_CAPI_UTIL_H_
#define CRYPTO_CAPI_UTIL_H_
#include <windows.h>
#include "crypto/crypto_export.h"
#include "crypto/wincrypt_shim.h"
namespace crypto {
// CryptAcquireContext when passed CRYPT_NEWKEYSET or CRYPT_DELETEKEYSET in
// flags is not thread-safe. For such calls, we create a global lock to
// synchronize it.
//
// From "Threading Issues with Cryptographic Service Providers",
// <http://msdn.microsoft.com/en-us/library/aa388149(v=VS.85).aspx>:
//
// "The CryptAcquireContext function is generally thread safe unless
// CRYPT_NEWKEYSET or CRYPT_DELETEKEYSET is specified in the dwFlags
// parameter."
CRYPTO_EXPORT BOOL CryptAcquireContextLocked(HCRYPTPROV* prov,
LPCWSTR container,
LPCWSTR provider,
DWORD prov_type,
DWORD flags);
// Wrappers of malloc and free for CryptoAPI routines that need memory
// allocators, such as in CRYPT_DECODE_PARA. Such routines require WINAPI
// calling conventions.
CRYPTO_EXPORT void* WINAPI CryptAlloc(size_t size);
CRYPTO_EXPORT void WINAPI CryptFree(void* p);
} // namespace crypto
#endif // CRYPTO_CAPI_UTIL_H_
# Copyright (c) 2012 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.
{
'variables': {
'chromium_code': 1,
},
'includes': [
'crypto.gypi',
],
'targets': [
{
'target_name': 'crypto',
'type': '<(component)',
'product_name': 'crcrypto', # Avoid colliding with OpenSSL's libcrypto
'dependencies': [
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
],
'defines': [
'CRYPTO_IMPLEMENTATION',
],
'conditions': [
[ 'os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
'dependencies': [
'../build/linux/system.gyp:ssl',
],
'export_dependent_settings': [
'../build/linux/system.gyp:ssl',
],
'conditions': [
[ 'chromeos==1', {
'sources/': [ ['include', '_chromeos\\.cc$'] ]
},
],
],
}, { # os_posix != 1 or OS == "mac" or OS == "ios" or OS == "android"
'sources!': [
'hmac_win.cc',
'symmetric_key_win.cc',
],
}],
[ 'OS != "mac" and OS != "ios"', {
'sources!': [
'apple_keychain.h',
'mock_apple_keychain.cc',
'mock_apple_keychain.h',
],
}],
[ 'OS == "android"', {
'dependencies': [
'../build/android/ndk.gyp:cpu_features',
],
}],
[ 'os_bsd==1', {
'link_settings': {
'libraries': [
'-L/usr/local/lib -lexecinfo',
],
},
},
],
[ 'OS == "mac"', {
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
],
},
}, { # OS != "mac"
'sources!': [
'cssm_init.cc',
'cssm_init.h',
'mac_security_services_lock.cc',
'mac_security_services_lock.h',
],
}],
[ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', {
'dependencies': [
'../third_party/nss/nss.gyp:nspr',
'../third_party/nss/nss.gyp:nss',
],
'export_dependent_settings': [
'../third_party/nss/nss.gyp:nspr',
'../third_party/nss/nss.gyp:nss',
],
}],
[ 'OS != "win"', {
'sources!': [
'capi_util.h',
'capi_util.cc',
],
}],
[ 'OS == "win"', {
'msvs_disabled_warnings': [
4267, # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
4018,
],
}],
[ 'use_openssl==1', {
'dependencies': [
'../third_party/boringssl/boringssl.gyp:boringssl',
],
# TODO(joth): Use a glob to match exclude patterns once the
# OpenSSL file set is complete.
'sources!': [
'aes_128_gcm_helpers_nss.cc',
'aes_128_gcm_helpers_nss.h',
'ec_private_key_nss.cc',
'ec_signature_creator_nss.cc',
'encryptor_nss.cc',
'hmac_nss.cc',
'rsa_private_key_nss.cc',
'secure_hash_default.cc',
'signature_creator_nss.cc',
'signature_verifier_nss.cc',
'symmetric_key_nss.cc',
'third_party/nss/chromium-blapi.h',
'third_party/nss/chromium-blapit.h',
'third_party/nss/chromium-nss.h',
'third_party/nss/chromium-prtypes.h',
'third_party/nss/chromium-sha256.h',
'third_party/nss/pk11akey.cc',
'third_party/nss/rsawrapr.c',
'third_party/nss/secsign.cc',
'third_party/nss/sha512.cc',
],
}, {
'sources!': [
'aead_openssl.cc',
'aead_openssl.h',
'ec_private_key_openssl.cc',
'ec_signature_creator_openssl.cc',
'encryptor_openssl.cc',
'hmac_openssl.cc',
'openssl_bio_string.cc',
'openssl_bio_string.h',
'openssl_util.cc',
'openssl_util.h',
'rsa_private_key_openssl.cc',
'secure_hash_openssl.cc',
'signature_creator_openssl.cc',
'signature_verifier_openssl.cc',
'symmetric_key_openssl.cc',
],
},],
[ 'use_openssl==1 and use_nss_certs==0', {
# Some files are built when NSS is used at all, either for the
# internal crypto library or the platform certificate library.
'sources!': [
'nss_key_util.cc',
'nss_key_util.h',
'nss_util.cc',
'nss_util.h',
'nss_util_internal.h',
],
},],
],
'sources': [
'<@(crypto_sources)',
],
},
{
'target_name': 'crypto_unittests',
'type': 'executable',
'sources': [
'aead_openssl_unittest.cc',
'aes_128_gcm_helpers_nss_unittest.cc',
'curve25519_unittest.cc',
'ec_private_key_unittest.cc',
'ec_signature_creator_unittest.cc',
'encryptor_unittest.cc',
'ghash_unittest.cc',
'hkdf_unittest.cc',
'hmac_unittest.cc',
'nss_key_util_unittest.cc',
'nss_util_unittest.cc',
'openssl_bio_string_unittest.cc',
'p224_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',
],
'dependencies': [
'crypto',
'crypto_test_support',
'../base/base.gyp:base',
'../base/base.gyp:run_all_unittests',
'../base/base.gyp:test_support_base',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
],
'conditions': [
[ 'use_nss_certs == 1', {
'conditions': [
[ 'use_allocator!="none"', {
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
],
},
],
],
'dependencies': [
'../build/linux/system.gyp:ssl',
],
}],
[ 'use_openssl == 1 and use_nss_certs == 0', {
# Some files are built when NSS is used at all, either for the
# internal crypto library or the platform certificate library.
'sources!': [
'nss_key_util_unittest.cc',
'nss_util_unittest.cc',
],
}],
[ 'use_openssl == 0 and (OS == "mac" or OS == "ios" or OS == "win")', {
'dependencies': [
'../third_party/nss/nss.gyp:nspr',
],
}],
[ 'OS == "win"', {
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [4267, ],
}],
[ 'use_openssl==1', {
'dependencies': [
'../third_party/boringssl/boringssl.gyp:boringssl',
],
'sources!': [
'aes_128_gcm_helpers_nss_unittest.cc',
],
}, {
'sources!': [
'openssl_bio_string_unittest.cc',
],
}],
],
},
],
'conditions': [
['OS == "win" and target_arch=="ia32"', {
'targets': [
{
'target_name': 'crypto_nacl_win64',
# We do not want nacl_helper to depend on NSS because this would
# require including a 64-bit copy of NSS. Thus, use the native APIs
# for the helper.
'type': '<(component)',
'dependencies': [
'../base/base.gyp:base_win64',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
],
'sources': [
'<@(nacl_win64_sources)',
],
'defines': [
'CRYPTO_IMPLEMENTATION',
'<@(nacl_win64_defines)',
],
'msvs_disabled_warnings': [
4018,
],
'configurations': {
'Common_Base': {
'msvs_target_platform': 'x64',
},
},
},
],
}],
['use_nss_certs==1', {
'targets': [
{
'target_name': 'crypto_test_support',
'type': 'static_library',
'dependencies': [
'../base/base.gyp:base',
'crypto',
],
'sources': [
'scoped_test_nss_db.cc',
'scoped_test_nss_db.h',
'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',
],
'conditions': [
['use_nss_certs==0', {
'sources!': [
'scoped_test_nss_db.cc',
'scoped_test_nss_db.h',
],
}],
[ 'chromeos==0', {
'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',
],
}],
],
}
]}, { # use_nss_certs==0
'targets': [
{
'target_name': 'crypto_test_support',
'type': 'none',
'sources': [],
}
]}],
['test_isolation_mode != "noop"', {
'targets': [
{
'target_name': 'crypto_unittests_run',
'type': 'none',
'dependencies': [
'crypto_unittests',
],
'includes': [
'../build/isolate.gypi',
],
'sources': [
'crypto_unittests.isolate',
],
},
],
}],
],
}
# Copyright 2014 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.
{
'variables': {
# Put all transitive dependencies for Windows HMAC here.
# This is required so that we can build them for nacl win64.
'variables': {
'hmac_win64_related_sources': [
'hmac.cc',
'hmac.h',
'hmac_win.cc',
'secure_util.cc',
'secure_util.h',
'symmetric_key.h',
'symmetric_key_win.cc',
'third_party/nss/chromium-blapi.h',
'third_party/nss/chromium-blapit.h',
'third_party/nss/chromium-prtypes.h',
'third_party/nss/chromium-sha256.h',
'third_party/nss/sha512.cc',
'wincrypt_shim.h',
],
},
'crypto_sources': [
# NOTE: all transitive dependencies of HMAC on windows need
# to be placed in the source list above.
'<@(hmac_win64_related_sources)',
'aead_openssl.cc',
'aead_openssl.h',
'aes_128_gcm_helpers_nss.cc',
'aes_128_gcm_helpers_nss.h',
'apple_keychain.h',
'apple_keychain_ios.mm',
'apple_keychain_mac.mm',
'capi_util.cc',
'capi_util.h',
'crypto_export.h',
'cssm_init.cc',
'cssm_init.h',
'curve25519.cc',
'curve25519.h',
'curve25519-donna.c',
'ghash.cc',
'ghash.h',
'ec_private_key.h',
'ec_private_key_nss.cc',
'ec_private_key_openssl.cc',
'ec_signature_creator.cc',
'ec_signature_creator.h',
'ec_signature_creator_impl.h',
'ec_signature_creator_nss.cc',
'ec_signature_creator_openssl.cc',
'encryptor.cc',
'encryptor.h',
'encryptor_nss.cc',
'encryptor_openssl.cc',
'hkdf.cc',
'hkdf.h',
'hmac_nss.cc',
'hmac_openssl.cc',
'mac_security_services_lock.cc',
'mac_security_services_lock.h',
'mock_apple_keychain.cc',
'mock_apple_keychain.h',
'mock_apple_keychain_ios.cc',
'mock_apple_keychain_mac.cc',
'p224_spake.cc',
'p224_spake.h',
'nss_crypto_module_delegate.h',
'nss_key_util.cc',
'nss_key_util.h',
'nss_util.cc',
'nss_util.h',
'nss_util_internal.h',
'openssl_bio_string.cc',
'openssl_bio_string.h',
'openssl_util.cc',
'openssl_util.h',
'p224.cc',
'p224.h',
'random.h',
'random.cc',
'rsa_private_key.cc',
'rsa_private_key.h',
'rsa_private_key_nss.cc',
'rsa_private_key_openssl.cc',
'scoped_capi_types.h',
'scoped_nss_types.h',
'secure_hash.h',
'secure_hash_default.cc',
'secure_hash_openssl.cc',
'sha2.cc',
'sha2.h',
'signature_creator.h',
'signature_creator_nss.cc',
'signature_creator_openssl.cc',
'signature_verifier.h',
'signature_verifier_nss.cc',
'signature_verifier_openssl.cc',
'symmetric_key_nss.cc',
'symmetric_key_openssl.cc',
'third_party/nss/chromium-nss.h',
'third_party/nss/pk11akey.cc',
'third_party/nss/rsawrapr.c',
'third_party/nss/secsign.cc',
],
'nacl_win64_sources': [
'<@(hmac_win64_related_sources)',
'random.cc',
'random.h',
],
}
}
// Copyright (c) 2012 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.
#ifndef CRYPTO_CRYPTO_EXPORT_H_
#define CRYPTO_CRYPTO_EXPORT_H_
// Defines CRYPTO_EXPORT so that functionality implemented by the crypto module
// can be exported to consumers, and CRYPTO_EXPORT_PRIVATE that allows unit
// tests to access features not intended to be used directly by real consumers.
#if defined(COMPONENT_BUILD)
#if defined(WIN32)
#if defined(CRYPTO_IMPLEMENTATION)
#define CRYPTO_EXPORT __declspec(dllexport)
#define CRYPTO_EXPORT_PRIVATE __declspec(dllexport)
#else
#define CRYPTO_EXPORT __declspec(dllimport)
#define CRYPTO_EXPORT_PRIVATE __declspec(dllimport)
#endif // defined(CRYPTO_IMPLEMENTATION)
#else // defined(WIN32)
#if defined(CRYPTO_IMPLEMENTATION)
#define CRYPTO_EXPORT __attribute__((visibility("default")))
#define CRYPTO_EXPORT_PRIVATE __attribute__((visibility("default")))
#else
#define CRYPTO_EXPORT
#define CRYPTO_EXPORT_PRIVATE
#endif
#endif
#else // defined(COMPONENT_BUILD)
#define CRYPTO_EXPORT
#define CRYPTO_EXPORT_PRIVATE
#endif
#endif // CRYPTO_CRYPTO_EXPORT_H_
# Copyright 2014 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.
{
'variables': {
'chromium_code': 1,
},
'includes': [
'../native_client/build/untrusted.gypi',
'crypto.gypi',
],
'targets': [
{
'target_name': 'crypto_nacl',
'type': 'none',
'variables': {
'nacl_untrusted_build': 1,
'nlib_target': 'libcrypto_nacl.a',
'build_glibc': 0,
'build_newlib': 0,
'build_pnacl_newlib': 1,
},
'dependencies': [
'../third_party/boringssl/boringssl_nacl.gyp:boringssl_nacl',
'../native_client_sdk/native_client_sdk_untrusted.gyp:nacl_io_untrusted',
],
'defines': [
'CRYPTO_IMPLEMENTATION',
],
'sources': [
'<@(crypto_sources)',
],
'sources/': [
['exclude', '_nss\.(cc|h)$'],
['exclude', '^(mock_)?apple_'],
['exclude', '^capi_'],
['exclude', '^cssm_'],
['exclude', '^nss_'],
['exclude', '^mac_'],
['exclude', '^third_party/nss/'],
['include', '^third_party/nss/sha512.cc'],
],
},
],
}
# Copyright 2015 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.
{
'variables': {
'command': [
'../testing/test_env.py',
'<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
'--brave-new-test-launcher',
'--test-launcher-bot-mode',
'--asan=<(asan)',
'--msan=<(msan)',
'--tsan=<(tsan)',
],
},
'conditions': [
['OS=="linux" or OS=="mac" or OS=="win"', {
'variables': {
'files': [
'../testing/test_env.py',
'<(PRODUCT_DIR)/crypto_unittests<(EXECUTABLE_SUFFIX)',
],
'read_only': 1,
},
}],
['OS=="mac" and asan==1 and fastbuild==0', {
'variables': {
'files': [
'<(PRODUCT_DIR)/crypto_unittests.dSYM/',
],
},
}],
['OS=="win" and (fastbuild==0 or fastbuild==1)', {
'variables': {
'files': [
'<(PRODUCT_DIR)/crypto_unittests.exe.pdb',
],
},
}],
],
'includes': [
'../base/base.isolate',
],
}
// Copyright (c) 2012 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.
#include "crypto/cssm_init.h"
#include <Security/SecBase.h>
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/singleton.h"
#include "base/strings/sys_string_conversions.h"
// When writing crypto code for Mac OS X, you may find the following
// documentation useful:
// - Common Security: CDSA and CSSM, Version 2 (with corrigenda)
// http://www.opengroup.org/security/cdsa.htm
// - Apple Cryptographic Service Provider Functional Specification
// - CryptoSample: http://developer.apple.com/SampleCode/CryptoSample/
namespace {
void* CSSMMalloc(CSSM_SIZE size, void* alloc_ref) {
return malloc(size);
}
void CSSMFree(void* mem_ptr, void* alloc_ref) {
free(mem_ptr);
}
void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
return realloc(ptr, size);
}
void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
return calloc(num, size);
}
class CSSMInitSingleton {
public:
static CSSMInitSingleton* GetInstance() {
return Singleton<CSSMInitSingleton,
LeakySingletonTraits<CSSMInitSingleton> >::get();
}
CSSM_CSP_HANDLE csp_handle() const { return csp_handle_; }
CSSM_CL_HANDLE cl_handle() const { return cl_handle_; }
CSSM_TP_HANDLE tp_handle() const { return tp_handle_; }
private:
CSSMInitSingleton()
: inited_(false), csp_loaded_(false), cl_loaded_(false),
tp_loaded_(false), csp_handle_(CSSM_INVALID_HANDLE),
cl_handle_(CSSM_INVALID_HANDLE), tp_handle_(CSSM_INVALID_HANDLE) {
static CSSM_VERSION version = {2, 0};
// TODO(wtc): what should our caller GUID be?
static const CSSM_GUID test_guid = {
0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 }
};
CSSM_RETURN crtn;
CSSM_PVC_MODE pvc_policy = CSSM_PVC_NONE;
crtn = CSSM_Init(&version, CSSM_PRIVILEGE_SCOPE_NONE, &test_guid,
CSSM_KEY_HIERARCHY_NONE, &pvc_policy, NULL);
if (crtn) {
NOTREACHED();
return;
}
inited_ = true;
crtn = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
if (crtn) {
NOTREACHED();
return;
}
csp_loaded_ = true;
crtn = CSSM_ModuleLoad(
&gGuidAppleX509CL, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
if (crtn) {
NOTREACHED();
return;
}
cl_loaded_ = true;
crtn = CSSM_ModuleLoad(
&gGuidAppleX509TP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
if (crtn) {
NOTREACHED();
return;
}
tp_loaded_ = true;
const CSSM_API_MEMORY_FUNCS cssmMemoryFunctions = {
CSSMMalloc,
CSSMFree,
CSSMRealloc,
CSSMCalloc,
NULL
};
crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &cssmMemoryFunctions, 0,
CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &csp_handle_);
DCHECK_EQ(CSSM_OK, crtn);
crtn = CSSM_ModuleAttach(&gGuidAppleX509CL, &version, &cssmMemoryFunctions,
0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &cl_handle_);
DCHECK_EQ(CSSM_OK, crtn);
crtn = CSSM_ModuleAttach(&gGuidAppleX509TP, &version, &cssmMemoryFunctions,
0, CSSM_SERVICE_TP, 0, CSSM_KEY_HIERARCHY_NONE,
NULL, 0, NULL, &tp_handle_);
DCHECK_EQ(CSSM_OK, crtn);
}
~CSSMInitSingleton() {
CSSM_RETURN crtn;
if (csp_handle_) {
CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_);
DCHECK_EQ(CSSM_OK, crtn);
}
if (cl_handle_) {
CSSM_RETURN crtn = CSSM_ModuleDetach(cl_handle_);
DCHECK_EQ(CSSM_OK, crtn);
}
if (tp_handle_) {
CSSM_RETURN crtn = CSSM_ModuleDetach(tp_handle_);
DCHECK_EQ(CSSM_OK, crtn);
}
if (csp_loaded_) {
crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL);
DCHECK_EQ(CSSM_OK, crtn);
}
if (cl_loaded_) {
crtn = CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
DCHECK_EQ(CSSM_OK, crtn);
}
if (tp_loaded_) {
crtn = CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL);
DCHECK_EQ(CSSM_OK, crtn);
}
if (inited_) {
crtn = CSSM_Terminate();
DCHECK_EQ(CSSM_OK, crtn);
}
}
bool inited_; // True if CSSM_Init has been called successfully.
bool csp_loaded_; // True if gGuidAppleCSP has been loaded
bool cl_loaded_; // True if gGuidAppleX509CL has been loaded.
bool tp_loaded_; // True if gGuidAppleX509TP has been loaded.
CSSM_CSP_HANDLE csp_handle_;
CSSM_CL_HANDLE cl_handle_;
CSSM_TP_HANDLE tp_handle_;
friend struct DefaultSingletonTraits<CSSMInitSingleton>;
};
} // namespace
namespace crypto {
void EnsureCSSMInit() {
CSSMInitSingleton::GetInstance();
}
CSSM_CSP_HANDLE GetSharedCSPHandle() {
return CSSMInitSingleton::GetInstance()->csp_handle();
}
CSSM_CL_HANDLE GetSharedCLHandle() {
return CSSMInitSingleton::GetInstance()->cl_handle();
}
CSSM_TP_HANDLE GetSharedTPHandle() {
return CSSMInitSingleton::GetInstance()->tp_handle();
}
void* CSSMMalloc(CSSM_SIZE size) {
return ::CSSMMalloc(size, NULL);
}
void CSSMFree(void* ptr) {
::CSSMFree(ptr, NULL);
}
void LogCSSMError(const char* fn_name, CSSM_RETURN err) {
if (!err)
return;
base::ScopedCFTypeRef<CFStringRef> cfstr(
SecCopyErrorMessageString(err, NULL));
LOG(ERROR) << fn_name << " returned " << err
<< " (" << base::SysCFStringRefToUTF8(cfstr) << ")";
}
ScopedCSSMData::ScopedCSSMData() {
memset(&data_, 0, sizeof(data_));
}
ScopedCSSMData::~ScopedCSSMData() {
if (data_.Data) {
CSSMFree(data_.Data);
data_.Data = NULL;
}
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_CSSM_INIT_H_
#define CRYPTO_CSSM_INIT_H_
#include <Security/cssm.h>
#include "base/basictypes.h"
#include "crypto/crypto_export.h"
namespace crypto {
// Initialize CSSM if it isn't already initialized. This must be called before
// any other CSSM functions. This function is thread-safe, and CSSM will only
// ever be initialized once. CSSM will be properly shut down on program exit.
CRYPTO_EXPORT void EnsureCSSMInit();
// Returns the shared CSP handle used by CSSM functions.
CRYPTO_EXPORT CSSM_CSP_HANDLE GetSharedCSPHandle();
// Returns the shared CL handle used by CSSM functions.
CRYPTO_EXPORT CSSM_CL_HANDLE GetSharedCLHandle();
// Returns the shared TP handle used by CSSM functions.
CRYPTO_EXPORT CSSM_TP_HANDLE GetSharedTPHandle();
// Set of pointers to memory function wrappers that are required for CSSM
extern const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions;
// Utility function to log an error message including the error name.
CRYPTO_EXPORT void LogCSSMError(const char *function_name, CSSM_RETURN err);
// Utility functions to allocate and release CSSM memory.
void* CSSMMalloc(CSSM_SIZE size);
CRYPTO_EXPORT void CSSMFree(void* ptr);
// Wrapper class for CSSM_DATA type. This should only be used when using the
// CL/TP/CSP handles from above, since that's the only time we're guaranteed (or
// supposed to be guaranteed) that our memory management functions will be used.
// Apple's Sec* APIs manage their own memory so it shouldn't be used for those.
// The constructor initializes data_ to zero and the destructor releases the
// data properly.
class ScopedCSSMData {
public:
ScopedCSSMData();
~ScopedCSSMData();
operator CSSM_DATA*() { return &data_; }
CSSM_DATA* operator ->() { return &data_; }
private:
CSSM_DATA data_;
DISALLOW_COPY_AND_ASSIGN(ScopedCSSMData);
};
} // namespace crypto
#endif // CRYPTO_CSSM_INIT_H_
此差异已折叠。
// 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.
#include "crypto/curve25519.h"
// Curve25519 is specified in terms of byte strings, not numbers, so all
// implementations take and return the same sequence of bits. So the byte
// order is implicitly specified as in, say, SHA1.
//
// Prototype for |curve25519_donna| function in
// third_party/curve25519-donna/curve25519-donna.c
extern "C" int curve25519_donna(uint8*, const uint8*, const uint8*);
namespace crypto {
namespace curve25519 {
void ScalarMult(const uint8* private_key,
const uint8* peer_public_key,
uint8* shared_key) {
curve25519_donna(shared_key, private_key, peer_public_key);
}
// kBasePoint is the base point (generator) of the elliptic curve group.
// It is little-endian version of '9' followed by 31 zeros.
// See "Computing public keys" section of http://cr.yp.to/ecdh.html.
static const unsigned char kBasePoint[32] = {9};
void ScalarBaseMult(const uint8* private_key, uint8* public_key) {
curve25519_donna(public_key, private_key, kBasePoint);
}
} // namespace curve25519
} // namespace crypto
// 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.
#ifndef CRYPTO_CURVE25519_H
#define CRYPTO_CURVE25519_H
#include "base/basictypes.h"
#include "crypto/crypto_export.h"
namespace crypto {
// Curve25519 implements the elliptic curve group known as Curve25519, as
// described in "Curve 25519: new Diffie-Hellman Speed Records",
// by D.J. Bernstein. Additional information is available at
// http://cr.yp.to/ecdh.html.
namespace curve25519 {
// kBytes is the number of bytes in the result of the Diffie-Hellman operation,
// which is an element of GF(2^255-19).
static const size_t kBytes = 32;
// kScalarBytes is the number of bytes in an element of the scalar field:
// GF(2^252 + 27742317777372353535851937790883648493).
static const size_t kScalarBytes = 32;
// ScalarMult computes the |shared_key| from |private_key| and
// |peer_public_key|. This method is a wrapper for |curve25519_donna()|. It
// calls that function with |private_key| as |secret| and |peer_public_key| as
// basepoint. |private_key| should be of length |kScalarBytes| and
// |peer_public_key| should be of length |kBytes|.
// See "Computing shared secrets" section of/ http://cr.yp.to/ecdh.html.
CRYPTO_EXPORT void ScalarMult(const uint8* private_key,
const uint8* peer_public_key,
uint8* shared_key);
// ScalarBaseMult computes the |public_key| from |private_key|. This method is a
// wrapper for |curve25519_donna()|. It calls that function with |private_key|
// as |secret| and |kBasePoint| as basepoint. |private_key| should be of length
// |kScalarBytes|. See "Computing public keys" section of
// http://cr.yp.to/ecdh.html.
CRYPTO_EXPORT void ScalarBaseMult(const uint8* private_key, uint8* public_key);
} // namespace curve25519
} // namespace crypto
#endif // CRYPTO_CURVE25519_H
// 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.
#include "crypto/curve25519.h"
#include <string>
#include "crypto/random.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace crypto {
// Test that the basic shared key exchange identity holds: that both parties end
// up with the same shared key. This test starts with a fixed private key for
// two parties: alice and bob. Runs ScalarBaseMult and ScalarMult to compute
// public key and shared key for alice and bob. It asserts that alice and bob
// have the same shared key.
TEST(Curve25519, SharedKeyIdentity) {
uint8 alice_private_key[curve25519::kScalarBytes] = {3};
uint8 bob_private_key[curve25519::kScalarBytes] = {5};
// Get public key for alice and bob.
uint8 alice_public_key[curve25519::kBytes];
curve25519::ScalarBaseMult(alice_private_key, alice_public_key);
uint8 bob_public_key[curve25519::kBytes];
curve25519::ScalarBaseMult(bob_private_key, bob_public_key);
// Get the shared key for alice, by using alice's private key and bob's
// public key.
uint8 alice_shared_key[curve25519::kBytes];
curve25519::ScalarMult(alice_private_key, bob_public_key, alice_shared_key);
// Get the shared key for bob, by using bob's private key and alice's public
// key.
uint8 bob_shared_key[curve25519::kBytes];
curve25519::ScalarMult(bob_private_key, alice_public_key, bob_shared_key);
// Computed shared key of alice and bob should be the same.
ASSERT_EQ(0, memcmp(alice_shared_key, bob_shared_key, curve25519::kBytes));
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_EC_PRIVATE_KEY_H_
#define CRYPTO_EC_PRIVATE_KEY_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "build/build_config.h"
#include "crypto/crypto_export.h"
#if defined(USE_OPENSSL)
// Forward declaration for openssl/*.h
typedef struct evp_pkey_st EVP_PKEY;
#else
// Forward declaration.
typedef struct CERTSubjectPublicKeyInfoStr CERTSubjectPublicKeyInfo;
typedef struct PK11SlotInfoStr PK11SlotInfo;
typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
#endif
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();
// Returns whether the system supports elliptic curve cryptography.
static bool IsSupported();
// Creates a new random instance. Can return NULL if initialization fails.
// The created key will use the NIST P-256 curve.
// TODO(mattm): Add a curve parameter.
static ECPrivateKey* Create();
// Creates a new instance by importing an existing key pair.
// The key pair is given as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
// block and an X.509 SubjectPublicKeyInfo block.
// Returns NULL if initialization fails.
static ECPrivateKey* CreateFromEncryptedPrivateKeyInfo(
const std::string& password,
const std::vector<uint8>& encrypted_private_key_info,
const std::vector<uint8>& subject_public_key_info);
#if !defined(USE_OPENSSL)
// Imports the key pair into |slot| and returns in |public_key| and |key|.
// Shortcut for code that needs to keep a reference directly to NSS types
// without having to create a ECPrivateKey object and make a copy of them.
// TODO(mattm): move this function to some NSS util file.
static bool ImportFromEncryptedPrivateKeyInfo(
PK11SlotInfo* slot,
const std::string& password,
const uint8* encrypted_private_key_info,
size_t encrypted_private_key_info_len,
CERTSubjectPublicKeyInfo* decoded_spki,
bool permanent,
bool sensitive,
SECKEYPrivateKey** key,
SECKEYPublicKey** public_key);
#endif
// Returns a copy of the object.
ECPrivateKey* Copy() const;
#if defined(USE_OPENSSL)
EVP_PKEY* key() { return key_; }
#else
SECKEYPrivateKey* key() { return key_; }
SECKEYPublicKey* public_key() { return public_key_; }
#endif
// Exports the private key as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
// block and the public key as an X.509 SubjectPublicKeyInfo block.
// The |password| and |iterations| are used as inputs to the key derivation
// function for generating the encryption key. PKCS #5 recommends a minimum
// of 1000 iterations, on modern systems a larger value may be preferrable.
bool ExportEncryptedPrivateKey(const std::string& password,
int iterations,
std::vector<uint8>* output);
// Exports the public key to an X.509 SubjectPublicKeyInfo block.
bool ExportPublicKey(std::vector<uint8>* output);
// Exports the public key as an EC point in the uncompressed point format.
bool ExportRawPublicKey(std::string* output);
// Exports private key data for testing. The format of data stored into output
// doesn't matter other than that it is consistent for the same key.
bool ExportValue(std::vector<uint8>* output);
bool ExportECParams(std::vector<uint8>* output);
private:
// Constructor is private. Use one of the Create*() methods above instead.
ECPrivateKey();
#if defined(USE_OPENSSL)
EVP_PKEY* key_;
#else
SECKEYPrivateKey* key_;
SECKEYPublicKey* public_key_;
#endif
DISALLOW_COPY_AND_ASSIGN(ECPrivateKey);
};
} // namespace crypto
#endif // CRYPTO_EC_PRIVATE_KEY_H_
// Copyright (c) 2012 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.
#include "crypto/ec_private_key.h"
extern "C" {
// Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h. This must come before
// other NSS headers.
#include <secmodt.h>
}
#include <cryptohi.h>
#include <keyhi.h>
#include <pk11pub.h>
#include <secmod.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "crypto/nss_util.h"
#include "crypto/nss_util_internal.h"
#include "crypto/scoped_nss_types.h"
#include "crypto/third_party/nss/chromium-nss.h"
namespace {
PK11SlotInfo* GetTempKeySlot() {
return PK11_GetInternalSlot();
}
class EllipticCurveSupportChecker {
public:
EllipticCurveSupportChecker() {
// NOTE: we can do this check here only because we use the NSS internal
// slot. If we support other slots in the future, checking whether they
// support ECDSA may block NSS, and the value may also change as devices are
// inserted/removed, so we would need to re-check on every use.
crypto::EnsureNSSInit();
crypto::ScopedPK11Slot slot(GetTempKeySlot());
supported_ = PK11_DoesMechanism(slot.get(), CKM_EC_KEY_PAIR_GEN) &&
PK11_DoesMechanism(slot.get(), CKM_ECDSA);
}
bool Supported() {
return supported_;
}
private:
bool supported_;
};
static base::LazyInstance<EllipticCurveSupportChecker>::Leaky
g_elliptic_curve_supported = LAZY_INSTANCE_INITIALIZER;
// Copied from rsa_private_key_nss.cc.
static bool ReadAttribute(SECKEYPrivateKey* key,
CK_ATTRIBUTE_TYPE type,
std::vector<uint8>* output) {
SECItem item;
SECStatus rv;
rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
if (rv != SECSuccess) {
DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError();
return false;
}
output->assign(item.data, item.data + item.len);
SECITEM_FreeItem(&item, PR_FALSE);
return true;
}
} // namespace
namespace crypto {
ECPrivateKey::~ECPrivateKey() {
if (key_)
SECKEY_DestroyPrivateKey(key_);
if (public_key_)
SECKEY_DestroyPublicKey(public_key_);
}
// static
bool ECPrivateKey::IsSupported() {
return g_elliptic_curve_supported.Get().Supported();
}
// static
ECPrivateKey* ECPrivateKey::Create() {
EnsureNSSInit();
ScopedPK11Slot slot(GetTempKeySlot());
if (!slot)
return nullptr;
scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
if (!oid_data) {
DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
return nullptr;
}
// SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
// value. For a named curve, that is just the OBJECT IDENTIFIER of the curve.
// In addition to the oid data, the encoding requires one byte for the ASN.1
// tag and one byte for the length (assuming the length is <= 127).
CHECK_LE(oid_data->oid.len, 127U);
std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len);
SECKEYECParams ec_parameters = {
siDEROID, &parameters_buf[0],
static_cast<unsigned>(parameters_buf.size())
};
ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
ec_parameters.data[1] = static_cast<unsigned char>(oid_data->oid.len);
memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
result->key_ = PK11_GenerateKeyPair(slot.get(),
CKM_EC_KEY_PAIR_GEN,
&ec_parameters,
&result->public_key_,
PR_FALSE /* not permanent */,
PR_FALSE /* not sensitive */,
NULL);
if (!result->key_) {
DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError();
return nullptr;
}
CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
return result.release();
}
// static
ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
const std::string& password,
const std::vector<uint8>& encrypted_private_key_info,
const std::vector<uint8>& subject_public_key_info) {
EnsureNSSInit();
ScopedPK11Slot slot(GetTempKeySlot());
if (!slot)
return nullptr;
scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
SECItem encoded_spki = {
siBuffer,
const_cast<unsigned char*>(&subject_public_key_info[0]),
static_cast<unsigned>(subject_public_key_info.size())
};
CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo(
&encoded_spki);
if (!decoded_spki) {
DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
return nullptr;
}
bool success = ImportFromEncryptedPrivateKeyInfo(
slot.get(),
password,
&encrypted_private_key_info[0],
encrypted_private_key_info.size(),
decoded_spki,
false /* not permanent */,
false /* not sensitive */,
&result->key_,
&result->public_key_);
SECKEY_DestroySubjectPublicKeyInfo(decoded_spki);
if (success) {
CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
return result.release();
}
return nullptr;
}
// static
bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
PK11SlotInfo* slot,
const std::string& password,
const uint8* encrypted_private_key_info,
size_t encrypted_private_key_info_len,
CERTSubjectPublicKeyInfo* decoded_spki,
bool permanent,
bool sensitive,
SECKEYPrivateKey** key,
SECKEYPublicKey** public_key) {
if (!slot)
return false;
*public_key = SECKEY_ExtractPublicKey(decoded_spki);
if (!*public_key) {
DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
return false;
}
if (SECKEY_GetPublicKeyType(*public_key) != ecKey) {
DLOG(ERROR) << "The public key is not an EC key";
SECKEY_DestroyPublicKey(*public_key);
*public_key = NULL;
return false;
}
SECItem encoded_epki = {
siBuffer,
const_cast<unsigned char*>(encrypted_private_key_info),
static_cast<unsigned>(encrypted_private_key_info_len)
};
SECKEYEncryptedPrivateKeyInfo epki;
memset(&epki, 0, sizeof(epki));
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
SECStatus rv = SEC_QuickDERDecodeItem(
arena.get(),
&epki,
SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
&encoded_epki);
if (rv != SECSuccess) {
DLOG(ERROR) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
SECKEY_DestroyPublicKey(*public_key);
*public_key = NULL;
return false;
}
SECItem password_item = {
siBuffer,
reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
static_cast<unsigned>(password.size())
};
rv = ImportEncryptedECPrivateKeyInfoAndReturnKey(
slot,
&epki,
&password_item,
NULL, // nickname
&(*public_key)->u.ec.publicValue,
permanent,
sensitive,
key,
NULL); // wincx
if (rv != SECSuccess) {
DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
<< PORT_GetError();
SECKEY_DestroyPublicKey(*public_key);
*public_key = NULL;
return false;
}
return true;
}
ECPrivateKey* ECPrivateKey::Copy() const {
scoped_ptr<ECPrivateKey> copy(new ECPrivateKey);
if (key_) {
copy->key_ = SECKEY_CopyPrivateKey(key_);
if (!copy->key_)
return NULL;
}
if (public_key_) {
copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
if (!copy->public_key_)
return NULL;
}
return copy.release();
}
bool ECPrivateKey::ExportEncryptedPrivateKey(
const std::string& password,
int iterations,
std::vector<uint8>* output) {
// We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
// PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
// support EC keys.
// https://bugzilla.mozilla.org/show_bug.cgi?id=327773
SECItem password_item = {
siBuffer,
reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
static_cast<unsigned>(password.size())
};
SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo(
NULL, // Slot, optional.
SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
&password_item,
key_,
iterations,
NULL); // wincx.
if (!encrypted) {
DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
return false;
}
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
SECItem der_key = {siBuffer, NULL, 0};
SECItem* encoded_item = SEC_ASN1EncodeItem(
arena.get(),
&der_key,
encrypted,
SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate));
SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE);
if (!encoded_item) {
DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError();
return false;
}
output->assign(der_key.data, der_key.data + der_key.len);
return true;
}
bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
ScopedSECItem der_pubkey(
SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
if (!der_pubkey.get()) {
return false;
}
output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
return true;
}
bool ECPrivateKey::ExportRawPublicKey(std::string* output) {
// public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for
// a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
// elements as 32-byte, big-endian numbers.
static const unsigned int kExpectedKeyLength = 65;
CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(public_key_));
const unsigned char* const data = public_key_->u.ec.publicValue.data;
const unsigned int len = public_key_->u.ec.publicValue.len;
if (len != kExpectedKeyLength || data[0] != 0x04)
return false;
output->assign(reinterpret_cast<const char*>(data + 1),
kExpectedKeyLength - 1);
return true;
}
bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
return ReadAttribute(key_, CKA_VALUE, output);
}
bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
return ReadAttribute(key_, CKA_EC_PARAMS, output);
}
ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {}
} // namespace crypto
// Copyright (c) 2012 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.
#include "crypto/ec_private_key.h"
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/x509.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
namespace crypto {
namespace {
// Function pointer definition, for injecting the required key export function
// into ExportKeyWithBio, below. |bio| is a temporary memory BIO object, and
// |key| is a handle to the input key object. Return 1 on success, 0 otherwise.
// NOTE: Used with OpenSSL functions, which do not comply with the Chromium
// style guide, hence the unusual parameter placement / types.
typedef int (*ExportBioFunction)(BIO* bio, const void* key);
using ScopedPKCS8_PRIV_KEY_INFO =
ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
using ScopedX509_SIG = ScopedOpenSSL<X509_SIG, X509_SIG_free>;
// Helper to export |key| into |output| via the specified ExportBioFunction.
bool ExportKeyWithBio(const void* key,
ExportBioFunction export_fn,
std::vector<uint8>* output) {
if (!key)
return false;
ScopedBIO bio(BIO_new(BIO_s_mem()));
if (!bio.get())
return false;
if (!export_fn(bio.get(), key))
return false;
char* data = NULL;
long len = BIO_get_mem_data(bio.get(), &data);
if (!data || len < 0)
return false;
output->assign(data, data + len);
return true;
}
// Function pointer definition, for injecting the required key export function
// into ExportKey below. |key| is a pointer to the input key object,
// and |data| is either NULL, or the address of an 'unsigned char*' pointer
// that points to the start of the output buffer. The function must return
// the number of bytes required to export the data, or -1 in case of error.
typedef int (*ExportDataFunction)(const void* key, unsigned char** data);
// Helper to export |key| into |output| via the specified export function.
bool ExportKey(const void* key,
ExportDataFunction export_fn,
std::vector<uint8>* output) {
if (!key)
return false;
int data_len = export_fn(key, NULL);
if (data_len < 0)
return false;
output->resize(static_cast<size_t>(data_len));
unsigned char* data = &(*output)[0];
if (export_fn(key, &data) < 0)
return false;
return true;
}
} // namespace
ECPrivateKey::~ECPrivateKey() {
if (key_)
EVP_PKEY_free(key_);
}
ECPrivateKey* ECPrivateKey::Copy() const {
scoped_ptr<ECPrivateKey> copy(new ECPrivateKey);
if (key_)
copy->key_ = EVP_PKEY_up_ref(key_);
return copy.release();
}
// static
bool ECPrivateKey::IsSupported() { return true; }
// static
ECPrivateKey* ECPrivateKey::Create() {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedEC_KEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get()))
return NULL;
scoped_ptr<ECPrivateKey> result(new ECPrivateKey());
result->key_ = EVP_PKEY_new();
if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get()))
return NULL;
CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type));
return result.release();
}
// static
ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
const std::string& password,
const std::vector<uint8>& encrypted_private_key_info,
const std::vector<uint8>& subject_public_key_info) {
// NOTE: The |subject_public_key_info| can be ignored here, it is only
// useful for the NSS implementation (which uses the public key's SHA1
// as a lookup key when storing the private one in its store).
if (encrypted_private_key_info.empty())
return NULL;
OpenSSLErrStackTracer err_tracer(FROM_HERE);
const uint8_t* data = &encrypted_private_key_info[0];
const uint8_t* ptr = data;
ScopedX509_SIG p8_encrypted(
d2i_X509_SIG(NULL, &ptr, encrypted_private_key_info.size()));
if (!p8_encrypted || ptr != data + encrypted_private_key_info.size())
return NULL;
ScopedPKCS8_PRIV_KEY_INFO p8_decrypted;
if (password.empty()) {
// Hack for reading keys generated by an older version of the OpenSSL
// code. OpenSSL used to use "\0\0" rather than the empty string because it
// would treat the password as an ASCII string to be converted to UCS-2
// while NSS used a byte string.
p8_decrypted.reset(PKCS8_decrypt_pbe(
p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2));
}
if (!p8_decrypted) {
p8_decrypted.reset(PKCS8_decrypt_pbe(
p8_encrypted.get(),
reinterpret_cast<const uint8_t*>(password.data()),
password.size()));
}
if (!p8_decrypted)
return NULL;
// Create a new EVP_PKEY for it.
scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
result->key_ = EVP_PKCS82PKEY(p8_decrypted.get());
if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC)
return NULL;
return result.release();
}
bool ECPrivateKey::ExportEncryptedPrivateKey(
const std::string& password,
int iterations,
std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Convert into a PKCS#8 object.
ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(key_));
if (!pkcs8.get())
return false;
// 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.
ScopedX509_SIG encrypted(PKCS8_encrypt_pbe(
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
reinterpret_cast<const uint8_t*>(password.data()),
password.size(),
NULL,
0,
iterations,
pkcs8.get()));
if (!encrypted.get())
return false;
// Write it into |*output|
return ExportKeyWithBio(encrypted.get(),
reinterpret_cast<ExportBioFunction>(i2d_PKCS8_bio),
output);
}
bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
return ExportKeyWithBio(
key_, reinterpret_cast<ExportBioFunction>(i2d_PUBKEY_bio), output);
}
bool ECPrivateKey::ExportRawPublicKey(std::string* output) {
// i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256
// key, is 0x04 (meaning uncompressed) followed by the x and y field
// elements as 32-byte, big-endian numbers.
static const int kExpectedKeyLength = 65;
int len = i2d_PublicKey(key_, NULL);
if (len != kExpectedKeyLength)
return false;
uint8 buf[kExpectedKeyLength];
uint8* derp = buf;
len = i2d_PublicKey(key_, &derp);
if (len != kExpectedKeyLength)
return false;
output->assign(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1);
return true;
}
bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
return ExportKey(ec_key.get(),
reinterpret_cast<ExportDataFunction>(i2d_ECPrivateKey),
output);
}
bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
return ExportKey(ec_key.get(),
reinterpret_cast<ExportDataFunction>(i2d_ECParameters),
output);
}
ECPrivateKey::ECPrivateKey() : key_(NULL) {}
} // namespace crypto
// Copyright (c) 2011 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.
#include "crypto/ec_private_key.h"
#include <vector>
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
// Generate random private keys. Export, then re-import. 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) {
const std::string password1;
const std::string password2 = "test";
scoped_ptr<crypto::ECPrivateKey> keypair1(crypto::ECPrivateKey::Create());
scoped_ptr<crypto::ECPrivateKey> keypair2(crypto::ECPrivateKey::Create());
ASSERT_TRUE(keypair1.get());
ASSERT_TRUE(keypair2.get());
std::vector<uint8> key1value;
std::vector<uint8> key2value;
std::vector<uint8> key1params;
std::vector<uint8> key2params;
EXPECT_TRUE(keypair1->ExportValue(&key1value));
EXPECT_TRUE(keypair2->ExportValue(&key2value));
EXPECT_TRUE(keypair1->ExportECParams(&key1params));
EXPECT_TRUE(keypair2->ExportECParams(&key2params));
std::vector<uint8> privkey1;
std::vector<uint8> privkey2;
std::vector<uint8> pubkey1;
std::vector<uint8> pubkey2;
std::string raw_pubkey1;
std::string raw_pubkey2;
ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey(password1, 1, &privkey1));
ASSERT_TRUE(keypair2->ExportEncryptedPrivateKey(password2, 1, &privkey2));
EXPECT_TRUE(keypair1->ExportPublicKey(&pubkey1));
EXPECT_TRUE(keypair2->ExportPublicKey(&pubkey2));
EXPECT_TRUE(keypair1->ExportRawPublicKey(&raw_pubkey1));
EXPECT_TRUE(keypair2->ExportRawPublicKey(&raw_pubkey2));
scoped_ptr<crypto::ECPrivateKey> keypair3(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
password1, privkey1, pubkey1));
scoped_ptr<crypto::ECPrivateKey> keypair4(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
password2, privkey2, pubkey2));
ASSERT_TRUE(keypair3.get());
ASSERT_TRUE(keypair4.get());
std::vector<uint8> key3value;
std::vector<uint8> key4value;
std::vector<uint8> key3params;
std::vector<uint8> key4params;
EXPECT_TRUE(keypair3->ExportValue(&key3value));
EXPECT_TRUE(keypair4->ExportValue(&key4value));
EXPECT_TRUE(keypair3->ExportECParams(&key3params));
EXPECT_TRUE(keypair4->ExportECParams(&key4params));
EXPECT_EQ(key1value, key3value);
EXPECT_EQ(key2value, key4value);
EXPECT_EQ(key1params, key3params);
EXPECT_EQ(key2params, key4params);
std::vector<uint8> pubkey3;
std::vector<uint8> pubkey4;
std::string raw_pubkey3;
std::string raw_pubkey4;
EXPECT_TRUE(keypair3->ExportPublicKey(&pubkey3));
EXPECT_TRUE(keypair4->ExportPublicKey(&pubkey4));
EXPECT_TRUE(keypair3->ExportRawPublicKey(&raw_pubkey3));
EXPECT_TRUE(keypair4->ExportRawPublicKey(&raw_pubkey4));
EXPECT_EQ(pubkey1, pubkey3);
EXPECT_EQ(pubkey2, pubkey4);
EXPECT_EQ(raw_pubkey1, raw_pubkey3);
EXPECT_EQ(raw_pubkey2, raw_pubkey4);
}
TEST(ECPrivateKeyUnitTest, Copy) {
scoped_ptr<crypto::ECPrivateKey> keypair1(crypto::ECPrivateKey::Create());
scoped_ptr<crypto::ECPrivateKey> keypair2(keypair1->Copy());
ASSERT_TRUE(keypair1.get());
ASSERT_TRUE(keypair2.get());
std::vector<uint8> key1value;
std::vector<uint8> key2value;
EXPECT_TRUE(keypair1->ExportValue(&key1value));
EXPECT_TRUE(keypair2->ExportValue(&key2value));
EXPECT_EQ(key1value, key2value);
std::vector<uint8> key1params;
std::vector<uint8> key2params;
EXPECT_TRUE(keypair1->ExportECParams(&key1params));
EXPECT_TRUE(keypair2->ExportECParams(&key2params));
EXPECT_EQ(key1params, key2params);
std::vector<uint8> pubkey1;
std::vector<uint8> 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);
}
TEST(ECPrivateKeyUnitTest, BadPasswordTest) {
const std::string password1;
const std::string password2 = "test";
scoped_ptr<crypto::ECPrivateKey> keypair1(
crypto::ECPrivateKey::Create());
ASSERT_TRUE(keypair1.get());
std::vector<uint8> privkey1;
std::vector<uint8> pubkey1;
ASSERT_TRUE(keypair1->ExportEncryptedPrivateKey(
password1, 1, &privkey1));
ASSERT_TRUE(keypair1->ExportPublicKey(&pubkey1));
scoped_ptr<crypto::ECPrivateKey> keypair2(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
password2, privkey1, pubkey1));
ASSERT_FALSE(keypair2.get());
}
TEST(ECPrivateKeyUnitTest, LoadNSSKeyTest) {
static const unsigned char nss_key[] = {
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};
static const unsigned char nss_pub_key[] = {
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, 0x85, 0x92, 0x9e, 0x95, 0x5c, 0x6b, 0x9e, 0xd6, 0x1e,
0xb8, 0x64, 0xea, 0xc2, 0xb3, 0xef, 0x18, 0xed, 0x3a, 0x5e, 0xc4, 0x5c,
0x15, 0x37, 0x6a, 0xe9, 0xaa, 0x0b, 0x34, 0x03, 0xfd, 0xca, 0x83, 0x0f,
0xd7, 0x5c, 0x5d, 0xc5, 0x53, 0x6e, 0xe5, 0xa9, 0x33, 0xd5, 0xcc, 0xab,
0x53, 0x78, 0xdd, 0xd6, 0x12, 0x3a, 0x5e, 0xeb, 0xbf, 0xdf, 0x16, 0xd3,
0x2c, 0x3b, 0xe8, 0xdb, 0x19, 0xfc, 0x5e};
scoped_ptr<crypto::ECPrivateKey> keypair_nss(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
"",
std::vector<uint8>(nss_key, nss_key + arraysize(nss_key)),
std::vector<uint8>(nss_pub_key,
nss_pub_key + arraysize(nss_pub_key))));
EXPECT_TRUE(keypair_nss.get());
}
// Although the plan is to transition from OpenSSL to NSS, ensure NSS can import
// OpenSSL's format so that it is possible to rollback.
TEST(ECPrivateKeyUnitTest, LoadOpenSSLKeyTest) {
static const unsigned char openssl_key[] = {
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 unsigned char openssl_pub_key[] = {
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};
scoped_ptr<crypto::ECPrivateKey> keypair_openssl(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
"",
std::vector<uint8>(openssl_key, openssl_key + arraysize(openssl_key)),
std::vector<uint8>(openssl_pub_key,
openssl_pub_key + arraysize(openssl_pub_key))));
EXPECT_TRUE(keypair_openssl.get());
}
// 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.
#if defined(USE_OPENSSL)
TEST(ECPrivateKeyUnitTest, LoadOldOpenSSLKeyTest) {
static const unsigned char openssl_key[] = {
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};
static const unsigned char openssl_pub_key[] = {
0x30, 0x82, 0x01, 0x4b, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x30, 0x81, 0xf7, 0x02, 0x01, 0x01, 0x30,
0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21,
0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x5b, 0x04,
0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x20, 0x5a,
0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76,
0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b,
0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15, 0x00, 0xc4, 0x9d,
0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78, 0xe1, 0x13, 0x9d,
0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04, 0x6b, 0x17, 0xd1,
0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40,
0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39,
0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f,
0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33,
0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51,
0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad,
0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
0x02, 0x01, 0x01, 0x03, 0x42, 0x00, 0x04, 0xde, 0x09, 0x08, 0x07, 0x03,
0x2e, 0x8f, 0x37, 0x9a, 0xd5, 0xad, 0xe5, 0xc6, 0x9d, 0xd4, 0x63, 0xc7,
0x4a, 0xe7, 0x20, 0xcb, 0x90, 0xa0, 0x1f, 0x18, 0x18, 0x72, 0xb5, 0x21,
0x88, 0x38, 0xc0, 0xdb, 0xba, 0xf6, 0x99, 0xd8, 0xa5, 0x3b, 0x83, 0xe9,
0xe3, 0xd5, 0x61, 0x99, 0x73, 0x42, 0xc6, 0x6c, 0xe8, 0x0a, 0x95, 0x40,
0x41, 0x3b, 0x0d, 0x10, 0xa7, 0x4a, 0x93, 0xdb, 0x5a, 0xe7, 0xec};
scoped_ptr<crypto::ECPrivateKey> keypair_openssl(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
"",
std::vector<uint8>(openssl_key, openssl_key + arraysize(openssl_key)),
std::vector<uint8>(openssl_pub_key,
openssl_pub_key + arraysize(openssl_pub_key))));
EXPECT_TRUE(keypair_openssl.get());
}
#endif // defined(USE_OPENSSL)
// Copyright (c) 2012 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.
#include "crypto/ec_signature_creator.h"
#include "base/logging.h"
#include "crypto/ec_signature_creator_impl.h"
namespace crypto {
namespace {
ECSignatureCreatorFactory* g_factory_ = NULL;
} // namespace
// static
ECSignatureCreator* ECSignatureCreator::Create(ECPrivateKey* key) {
if (g_factory_)
return g_factory_->Create(key);
return new ECSignatureCreatorImpl(key);
}
// static
void ECSignatureCreator::SetFactoryForTesting(
ECSignatureCreatorFactory* factory) {
// We should always clear the factory after each test to avoid
// use-after-free problems.
DCHECK(!g_factory_ || !factory);
g_factory_ = factory;
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_EC_SIGNATURE_CREATOR_H_
#define CRYPTO_EC_SIGNATURE_CREATOR_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "crypto/crypto_export.h"
namespace crypto {
class ECPrivateKey;
class ECSignatureCreator;
class CRYPTO_EXPORT ECSignatureCreatorFactory {
public:
virtual ~ECSignatureCreatorFactory() {}
virtual ECSignatureCreator* Create(ECPrivateKey* key) = 0;
};
// 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 ECSignatureCreator* Create(ECPrivateKey* key);
// Set a factory to make the Create function return non-standard
// ECSignatureCreator objects. Because the ECDSA algorithm involves
// randomness, this is useful for higher-level tests that want to have
// deterministic mocked output to compare.
static void SetFactoryForTesting(ECSignatureCreatorFactory* factory);
// Signs |data_len| bytes from |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(const uint8* data,
int data_len,
std::vector<uint8>* 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>& signature,
std::vector<uint8>* out_raw_sig) = 0;
};
} // namespace crypto
#endif // CRYPTO_EC_SIGNATURE_CREATOR_H_
// Copyright (c) 2012 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.
#ifndef CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
#define CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
#include "base/compiler_specific.h"
#include "crypto/ec_signature_creator.h"
namespace crypto {
class ECSignatureCreatorImpl : public ECSignatureCreator {
public:
explicit ECSignatureCreatorImpl(ECPrivateKey* key);
~ECSignatureCreatorImpl() override;
bool Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) override;
bool DecodeSignature(const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) override;
private:
ECPrivateKey* key_;
size_t signature_len_;
DISALLOW_COPY_AND_ASSIGN(ECSignatureCreatorImpl);
};
} // namespace crypto
#endif // CRYPTO_EC_SIGNATURE_CREATOR_IMPL_H_
// Copyright (c) 2012 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.
#include "crypto/ec_signature_creator_impl.h"
#include <cryptohi.h>
#include <pk11pub.h>
#include <secerr.h>
#include <sechash.h>
#if defined(OS_POSIX)
#include <unistd.h>
#endif
#include "base/logging.h"
#include "crypto/ec_private_key.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"
namespace crypto {
namespace {
SECStatus SignData(SECItem* result,
SECItem* input,
SECKEYPrivateKey* key,
HASH_HashType hash_type,
size_t* out_signature_len) {
if (key->keyType != ecKey) {
DLOG(FATAL) << "Should be using an EC key.";
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
// Hash the input.
std::vector<uint8> hash_data(HASH_ResultLen(hash_type));
SECStatus rv = HASH_HashBuf(
hash_type, &hash_data[0], input->data, input->len);
if (rv != SECSuccess)
return rv;
SECItem hash = {siBuffer, &hash_data[0],
static_cast<unsigned int>(hash_data.size())};
// Compute signature of hash.
int signature_len = PK11_SignatureLen(key);
std::vector<uint8> signature_data(signature_len);
SECItem sig = {siBuffer, &signature_data[0],
static_cast<unsigned int>(signature_len)};
rv = PK11_Sign(key, &sig, &hash);
if (rv != SECSuccess)
return rv;
*out_signature_len = sig.len;
// DER encode the signature.
return DSAU_EncodeDerSigWithLen(result, &sig, sig.len);
}
} // namespace
ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key)
: key_(key),
signature_len_(0) {
EnsureNSSInit();
}
ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {}
bool ECSignatureCreatorImpl::Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) {
// Data to be signed
SECItem secret;
secret.type = siBuffer;
secret.len = data_len;
secret.data = const_cast<unsigned char*>(data);
// SECItem to receive the output buffer.
SECItem result;
result.type = siBuffer;
result.len = 0;
result.data = NULL;
// Sign the secret data and save it to |result|.
SECStatus rv =
SignData(&result, &secret, key_->key(), HASH_AlgSHA256, &signature_len_);
if (rv != SECSuccess) {
DLOG(ERROR) << "DerSignData: " << PORT_GetError();
return false;
}
// Copy the signed data into the output vector.
signature->assign(result.data, result.data + result.len);
SECITEM_FreeItem(&result, PR_FALSE /* only free |result.data| */);
return true;
}
bool ECSignatureCreatorImpl::DecodeSignature(
const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) {
SECItem der_sig_item;
der_sig_item.type = siBuffer;
der_sig_item.len = der_sig.size();
der_sig_item.data = const_cast<uint8*>(&der_sig[0]);
SECItem* raw_sig = DSAU_DecodeDerSigToLen(&der_sig_item, signature_len_);
if (!raw_sig)
return false;
out_raw_sig->assign(raw_sig->data, raw_sig->data + raw_sig->len);
SECITEM_FreeItem(raw_sig, PR_TRUE /* free SECItem structure itself. */);
return true;
}
} // namespace crypto
// Copyright (c) 2012 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.
#include "crypto/ec_signature_creator_impl.h"
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include "base/logging.h"
#include "crypto/ec_private_key.h"
#include "crypto/openssl_util.h"
#include "crypto/scoped_openssl_types.h"
namespace crypto {
ECSignatureCreatorImpl::ECSignatureCreatorImpl(ECPrivateKey* key)
: key_(key), signature_len_(0) {
EnsureOpenSSLInit();
}
ECSignatureCreatorImpl::~ECSignatureCreatorImpl() {}
bool ECSignatureCreatorImpl::Sign(const uint8* data,
int data_len,
std::vector<uint8>* signature) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
size_t sig_len = 0;
if (!ctx.get() ||
!EVP_DigestSignInit(ctx.get(), NULL, EVP_sha256(), NULL, key_->key()) ||
!EVP_DigestSignUpdate(ctx.get(), data, data_len) ||
!EVP_DigestSignFinal(ctx.get(), NULL, &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 NULL second parameter returns
// a maximum allocation size, while the call without a NULL returns the real
// one, which may be smaller.
signature->resize(sig_len);
return true;
}
bool ECSignatureCreatorImpl::DecodeSignature(const std::vector<uint8>& der_sig,
std::vector<uint8>* out_raw_sig) {
OpenSSLErrStackTracer err_tracer(FROM_HERE);
// Create ECDSA_SIG object from DER-encoded data.
const unsigned char* der_data = &der_sig.front();
ScopedECDSA_SIG ecdsa_sig(
d2i_ECDSA_SIG(NULL, &der_data, static_cast<long>(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> 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
// Copyright (c) 2012 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.
#include "crypto/ec_signature_creator.h"
#include <string>
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "crypto/ec_private_key.h"
#include "crypto/signature_verifier.h"
#include "testing/gtest/include/gtest/gtest.h"
// TODO(rch): Add some exported keys from each to
// test interop between NSS and OpenSSL.
TEST(ECSignatureCreatorTest, BasicTest) {
// Do a verify round trip.
scoped_ptr<crypto::ECPrivateKey> key_original(
crypto::ECPrivateKey::Create());
ASSERT_TRUE(key_original.get());
std::vector<uint8> key_info;
ASSERT_TRUE(
key_original->ExportEncryptedPrivateKey(std::string(), 1000, &key_info));
std::vector<uint8> pubkey_info;
ASSERT_TRUE(key_original->ExportPublicKey(&pubkey_info));
scoped_ptr<crypto::ECPrivateKey> key(
crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
std::string(), key_info, pubkey_info));
ASSERT_TRUE(key.get());
ASSERT_TRUE(key->key() != NULL);
scoped_ptr<crypto::ECSignatureCreator> signer(
crypto::ECSignatureCreator::Create(key.get()));
ASSERT_TRUE(signer.get());
std::string data("Hello, World!");
std::vector<uint8> signature;
ASSERT_TRUE(signer->Sign(reinterpret_cast<const uint8*>(data.c_str()),
data.size(),
&signature));
std::vector<uint8> public_key_info;
ASSERT_TRUE(key_original->ExportPublicKey(&public_key_info));
// This is the algorithm ID for ECDSA with SHA-256. Parameters are ABSENT.
// RFC 5758:
// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
// ...
// When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or
// ecdsa-with-SHA512 algorithm identifier appears in the algorithm field
// as an AlgorithmIdentifier, the encoding MUST omit the parameters
// field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one
// component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-
// SHA384, or ecdsa-with-SHA512.
// See also RFC 5480, Appendix A.
const uint8 kECDSAWithSHA256AlgorithmID[] = {
0x30, 0x0a,
0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
};
crypto::SignatureVerifier verifier;
ASSERT_TRUE(verifier.VerifyInit(
kECDSAWithSHA256AlgorithmID, sizeof(kECDSAWithSHA256AlgorithmID),
&signature[0], signature.size(),
&public_key_info.front(), public_key_info.size()));
verifier.VerifyUpdate(reinterpret_cast<const uint8*>(data.c_str()),
data.size());
ASSERT_TRUE(verifier.VerifyFinal());
}
// Copyright (c) 2012 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.
#include "crypto/encryptor.h"
#include "base/logging.h"
#include "base/sys_byteorder.h"
namespace crypto {
/////////////////////////////////////////////////////////////////////////////
// Encyptor::Counter Implementation.
Encryptor::Counter::Counter(const base::StringPiece& counter) {
CHECK(sizeof(counter_) == counter.length());
memcpy(&counter_, counter.data(), sizeof(counter_));
}
Encryptor::Counter::~Counter() {
}
bool Encryptor::Counter::Increment() {
uint64 low_num = base::NetToHost64(counter_.components64[1]);
uint64 new_low_num = low_num + 1;
counter_.components64[1] = base::HostToNet64(new_low_num);
// If overflow occured then increment the most significant component.
if (new_low_num < low_num) {
counter_.components64[0] =
base::HostToNet64(base::NetToHost64(counter_.components64[0]) + 1);
}
// TODO(hclam): Return false if counter value overflows.
return true;
}
void Encryptor::Counter::Write(void* buf) {
uint8* buf_ptr = reinterpret_cast<uint8*>(buf);
memcpy(buf_ptr, &counter_, sizeof(counter_));
}
size_t Encryptor::Counter::GetLengthInBytes() const {
return sizeof(counter_);
}
/////////////////////////////////////////////////////////////////////////////
// Partial Encryptor Implementation.
bool Encryptor::SetCounter(const base::StringPiece& counter) {
if (mode_ != CTR)
return false;
if (counter.length() != 16u)
return false;
counter_.reset(new Counter(counter));
return true;
}
bool Encryptor::GenerateCounterMask(size_t plaintext_len,
uint8* mask,
size_t* mask_len) {
DCHECK_EQ(CTR, mode_);
CHECK(mask);
CHECK(mask_len);
const size_t kBlockLength = counter_->GetLengthInBytes();
size_t blocks = (plaintext_len + kBlockLength - 1) / kBlockLength;
CHECK(blocks);
*mask_len = blocks * kBlockLength;
for (size_t i = 0; i < blocks; ++i) {
counter_->Write(mask);
mask += kBlockLength;
bool ret = counter_->Increment();
if (!ret)
return false;
}
return true;
}
void Encryptor::MaskMessage(const void* plaintext,
size_t plaintext_len,
const void* mask,
void* ciphertext) const {
DCHECK_EQ(CTR, mode_);
const uint8* plaintext_ptr = reinterpret_cast<const uint8*>(plaintext);
const uint8* mask_ptr = reinterpret_cast<const uint8*>(mask);
uint8* ciphertext_ptr = reinterpret_cast<uint8*>(ciphertext);
for (size_t i = 0; i < plaintext_len; ++i)
ciphertext_ptr[i] = plaintext_ptr[i] ^ mask_ptr[i];
}
} // namespace crypto
// Copyright (c) 2012 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.
#ifndef CRYPTO_ENCRYPTOR_H_
#define CRYPTO_ENCRYPTOR_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#include "crypto/crypto_export.h"
#if defined(USE_NSS_CERTS) || \
(!defined(USE_OPENSSL) && (defined(OS_WIN) || defined(OS_MACOSX)))
#include "crypto/scoped_nss_types.h"
#endif
namespace crypto {
class SymmetricKey;
class CRYPTO_EXPORT Encryptor {
public:
enum Mode {
CBC,
CTR,
};
// This class implements a 128-bits counter to be used in AES-CTR encryption.
// Only 128-bits counter is supported in this class.
class CRYPTO_EXPORT Counter {
public:
explicit Counter(const base::StringPiece& counter);
~Counter();
// Increment the counter value.
bool Increment();
// Write the content of the counter to |buf|. |buf| should have enough
// space for |GetLengthInBytes()|.
void Write(void* buf);
// Return the length of this counter.
size_t GetLengthInBytes() const;
private:
union {
uint32 components32[4];
uint64 components64[2];
} counter_;
};
Encryptor();
virtual ~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(SymmetricKey* key, Mode mode, const base::StringPiece& iv);
// Encrypts |plaintext| into |ciphertext|. |plaintext| may only be empty if
// the mode is CBC.
bool Encrypt(const base::StringPiece& plaintext, std::string* 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 cryptosystem.
bool Decrypt(const base::StringPiece& ciphertext, std::string* 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(const base::StringPiece& counter);
// TODO(albertb): Support streaming encryption.
private:
// Generates a mask using |counter_| to be used for encryption in CTR mode.
// Resulting mask will be written to |mask| with |mask_len| bytes.
//
// Make sure there's enough space in mask when calling this method.
// Reserve at least |plaintext_len| + 16 bytes for |mask|.
//
// The generated mask will always have at least |plaintext_len| bytes and
// will be a multiple of the counter length.
//
// This method is used only in CTR mode.
//
// Returns false if this call failed.
bool GenerateCounterMask(size_t plaintext_len,
uint8* mask,
size_t* mask_len);
// Mask the |plaintext| message using |mask|. The output will be written to
// |ciphertext|. |ciphertext| must have at least |plaintext_len| bytes.
void MaskMessage(const void* plaintext,
size_t plaintext_len,
const void* mask,
void* ciphertext) const;
SymmetricKey* key_;
Mode mode_;
scoped_ptr<Counter> counter_;
#if defined(USE_OPENSSL)
bool Crypt(bool do_encrypt, // Pass true to encrypt, false to decrypt.
const base::StringPiece& input,
std::string* output);
bool CryptCTR(bool do_encrypt,
const base::StringPiece& input,
std::string* output);
std::string iv_;
#elif defined(USE_NSS_CERTS) || defined(OS_WIN) || defined(OS_MACOSX)
bool Crypt(PK11Context* context,
const base::StringPiece& input,
std::string* output);
bool CryptCTR(PK11Context* context,
const base::StringPiece& input,
std::string* output);
ScopedSECItem param_;
#endif
};
} // namespace crypto
#endif // CRYPTO_ENCRYPTOR_H_
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册