0

Use NSS for symmetric key crypto operations on Windows and Mac.

Encryptor, HMAC, and SymmetricKey now use NSS on all platforms except Android.
This allows us to use them inside the sandbox, something that was not possible
when using the platform APIs.

On Windows, Native Client 64-bit builds still use the the platform APIs.

BUG=127803,124741
TEST=Existing tests since there is no change in functionality.

Review URL: https://chromiumcodereview.appspot.com/10543146

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142356 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
ddorwin@chromium.org
2012-06-15 08:11:52 +00:00
parent 8368a0a348
commit 45a445210f
10 changed files with 60 additions and 503 deletions

@ -190,7 +190,7 @@ ChromeRenderProcessObserver::ChromeRenderProcessObserver(
#endif
#if defined(OS_POSIX) && !defined(OS_MACOSX) && defined(USE_NSS)
// Remoting requires NSS to function properly.
// On platforms where we use system NSS libraries, the .so's must be loaded.
if (!command_line.HasSwitch(switches::kSingleProcess)) {
// We are going to fork to engage the sandbox and we have not loaded
// any security modules so it is safe to disable the fork check in NSS.

@ -53,10 +53,16 @@
['exclude', '_nss\.cc$'],
['include', 'ec_private_key_nss\.cc$'],
['include', 'ec_signature_creator_nss\.cc$'],
['include', 'encryptor_nss\.cc$'],
['include', 'hmac_nss\.cc$'],
['include', 'signature_verifier_nss\.cc$'],
['include', 'symmetric_key_nss\.cc$'],
],
'sources!': [
'hmac_win.cc',
'openpgp_symmetric_encryption.cc',
'openpgp_symmetric_encryption.h',
'symmetric_key_win.cc',
],
}],
[ 'OS == "android"', {
@ -66,7 +72,10 @@
'sources/': [
['exclude', 'ec_private_key_nss\.cc$'],
['exclude', 'ec_signature_creator_nss\.cc$'],
['exclude', 'encryptor_nss\.cc$'],
['exclude', 'hmac_nss\.cc$'],
['exclude', 'signature_verifier_nss\.cc$'],
['exclude', 'symmetric_key_nss\.cc$'],
],
}],
[ 'os_bsd==1', {
@ -96,6 +105,10 @@
'../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!': [
@ -163,11 +176,8 @@
'ec_signature_creator_openssl.cc',
'encryptor.cc',
'encryptor.h',
'encryptor_mac.cc',
'encryptor_nss.cc',
'encryptor_openssl.cc',
'encryptor_win.cc',
'hmac_mac.cc',
'hmac_nss.cc',
'hmac_openssl.cc',
'keychain_mac.cc',
@ -208,7 +218,6 @@
'signature_verifier.h',
'signature_verifier_nss.cc',
'signature_verifier_openssl.cc',
'symmetric_key_mac.cc',
'symmetric_key_nss.cc',
'symmetric_key_openssl.cc',
'third_party/nss/chromium-blapi.h',
@ -293,6 +302,9 @@
'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_nacl_win64',
@ -303,6 +315,7 @@
],
'defines': [
'CRYPTO_IMPLEMENTATION',
'<@(nacl_win64_defines)',
],
'msvs_disabled_warnings': [
4018,

@ -14,10 +14,8 @@
#include "build/build_config.h"
#include "crypto/crypto_export.h"
#if defined(USE_NSS)
#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
#include "crypto/scoped_nss_types.h"
#elif defined(OS_WIN)
#include "crypto/scoped_capi_types.h"
#endif
namespace crypto {
@ -33,7 +31,7 @@ class CRYPTO_EXPORT Encryptor {
// This class implements a 128-bits counter to be used in AES-CTR encryption.
// Only 128-bits counter is supported in this class.
class Counter {
class CRYPTO_EXPORT Counter {
public:
explicit Counter(const base::StringPiece& counter);
~Counter();
@ -121,7 +119,7 @@ class CRYPTO_EXPORT Encryptor {
const base::StringPiece& input,
std::string* output);
std::string iv_;
#elif defined(USE_NSS)
#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
bool Crypt(PK11Context* context,
const base::StringPiece& input,
std::string* output);
@ -130,15 +128,6 @@ class CRYPTO_EXPORT Encryptor {
std::string* output);
ScopedPK11Slot slot_;
ScopedSECItem param_;
#elif defined(OS_MACOSX)
bool Crypt(int /*CCOperation*/ op,
const base::StringPiece& input,
std::string* output);
std::string iv_;
#elif defined(OS_WIN)
ScopedHCRYPTKEY capi_key_;
DWORD block_size_;
#endif
};

@ -1,84 +0,0 @@
// 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/encryptor.h"
#include <CommonCrypto/CommonCryptor.h>
#include "base/logging.h"
#include "base/string_util.h"
#include "crypto/symmetric_key.h"
namespace crypto {
Encryptor::Encryptor()
: key_(NULL),
mode_(CBC) {
}
Encryptor::~Encryptor() {
}
bool Encryptor::Init(SymmetricKey* key,
Mode mode,
const base::StringPiece& iv) {
DCHECK(key);
DCHECK_EQ(CBC, mode) << "Unsupported mode of operation";
CSSM_DATA raw_key = key->cssm_data();
if (raw_key.Length != kCCKeySizeAES128 &&
raw_key.Length != kCCKeySizeAES192 &&
raw_key.Length != kCCKeySizeAES256)
return false;
if (iv.size() != kCCBlockSizeAES128)
return false;
key_ = key;
mode_ = mode;
iv.CopyToString(&iv_);
return true;
}
bool Encryptor::Crypt(int /*CCOperation*/ op,
const base::StringPiece& input,
std::string* output) {
DCHECK(key_);
CSSM_DATA raw_key = key_->cssm_data();
// CommonCryptor.h: "A general rule for the size of the output buffer which
// must be provided by the caller is that for block ciphers, the output
// length is never larger than the input length plus the block size."
size_t output_size = input.size() + iv_.size();
CHECK_GT(output_size, 0u);
CHECK_GT(output_size + 1, input.size());
CCCryptorStatus err = CCCrypt(op,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding,
raw_key.Data, raw_key.Length,
iv_.data(),
input.data(), input.size(),
WriteInto(output, output_size + 1),
output_size,
&output_size);
if (err) {
output->clear();
LOG(ERROR) << "CCCrypt returned " << err;
return false;
}
output->resize(output_size);
return true;
}
bool Encryptor::Encrypt(const base::StringPiece& plaintext,
std::string* ciphertext) {
CHECK(!plaintext.empty() || (mode_ == CBC));
return Crypt(kCCEncrypt, plaintext, ciphertext);
}
bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
std::string* plaintext) {
CHECK(!ciphertext.empty());
return Crypt(kCCDecrypt, ciphertext, plaintext);
}
} // namespace crypto

@ -91,8 +91,8 @@ TEST(EncryptorTest, DecryptWrongKey) {
// invalid. If an implementation simply uses the last padding byte to
// determine the padding length without checking every padding byte,
// Encryptor::Decrypt() will still return true. This is the case for NSS
// (crbug.com/124434) and Mac OS X 10.7 (crbug.com/127586).
#if !defined(USE_NSS)
// (crbug.com/124434).
#if !defined(USE_NSS) && !defined(OS_WIN) && !defined(OS_MACOSX)
crypto::Encryptor decryptor;
EXPECT_TRUE(decryptor.Init(wrong_key.get(), crypto::Encryptor::CBC, iv));
EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decypted));
@ -113,7 +113,7 @@ TEST(EncryptorTest, DecryptWrongKey) {
}
// CTR mode encryption is only implemented using NSS.
#if defined(USE_NSS)
#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
TEST(EncryptorTest, EncryptDecryptCTR) {
scoped_ptr<crypto::SymmetricKey> key(
@ -149,11 +149,13 @@ TEST(EncryptorTest, EncryptDecryptCTR) {
TEST(EncryptorTest, CTRCounter) {
const int kCounterSize = 16;
const char kTest1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8 buf[16];
const unsigned char kTest1[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned char buf[16];
// Increment 10 times.
crypto::Encryptor::Counter counter1(std::string(kTest1, kCounterSize));
crypto::Encryptor::Counter counter1(
std::string(reinterpret_cast<const char*>(kTest1), kCounterSize));
for (int i = 0; i < 10; ++i)
counter1.Increment();
counter1.Write(buf);
@ -161,18 +163,26 @@ TEST(EncryptorTest, CTRCounter) {
EXPECT_TRUE(buf[15] == 10);
// Check corner cases.
const char kTest2[] = {0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const char kExpect2[] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
crypto::Encryptor::Counter counter2(std::string(kTest2, kCounterSize));
const unsigned char kTest2[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const unsigned char kExpect2[] =
{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0};
crypto::Encryptor::Counter counter2(
std::string(reinterpret_cast<const char*>(kTest2), kCounterSize));
counter2.Increment();
counter2.Write(buf);
EXPECT_EQ(0, memcmp(buf, kExpect2, kCounterSize));
const char kTest3[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const char kExpect3[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
crypto::Encryptor::Counter counter3(std::string(kTest3, kCounterSize));
const unsigned char kTest3[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const unsigned char kExpect3[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
crypto::Encryptor::Counter counter3(
std::string(reinterpret_cast<const char*>(kTest3), kCounterSize));
counter3.Increment();
counter3.Write(buf);
EXPECT_EQ(0, memcmp(buf, kExpect3, kCounterSize));
@ -312,7 +322,7 @@ TEST(EncryptorTest, EncryptAES192CBCRegression) {
// Not all platforms allow import/generation of symmetric keys with an
// unsupported size.
#if !defined(OS_WIN) && !defined(USE_NSS)
#if !defined(USE_NSS) && !defined(OS_WIN) && !defined(OS_MACOSX)
TEST(EncryptorTest, UnsupportedKeySize) {
std::string key = "7 = bad";
std::string iv = "Sweet Sixteen IV";

@ -1,128 +0,0 @@
// 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/encryptor.h"
#include <string.h>
#include "base/string_util.h"
#include "crypto/symmetric_key.h"
namespace crypto {
namespace {
// On success, returns the block size (in bytes) for the algorithm that |key|
// is for. On failure, returns 0.
DWORD GetCipherBlockSize(HCRYPTKEY key) {
DWORD block_size_in_bits = 0;
DWORD param_size = sizeof(block_size_in_bits);
BOOL ok = CryptGetKeyParam(key, KP_BLOCKLEN,
reinterpret_cast<BYTE*>(&block_size_in_bits),
&param_size, 0);
if (!ok)
return 0;
return block_size_in_bits / 8;
}
} // namespace
Encryptor::Encryptor()
: key_(NULL),
mode_(CBC),
block_size_(0) {
}
Encryptor::~Encryptor() {
}
bool Encryptor::Init(SymmetricKey* key,
Mode mode,
const base::StringPiece& iv) {
DCHECK(key);
DCHECK_EQ(CBC, mode) << "Unsupported mode of operation";
// In CryptoAPI, the IV, padding mode, and feedback register (for a chaining
// mode) are properties of a key, so we have to create a copy of the key for
// the Encryptor. See the Remarks section of the CryptEncrypt MSDN page.
BOOL ok = CryptDuplicateKey(key->key(), NULL, 0, capi_key_.receive());
if (!ok)
return false;
// CRYPT_MODE_CBC is the default for Microsoft Base Cryptographic Provider,
// but we set it anyway to be safe.
DWORD cipher_mode = CRYPT_MODE_CBC;
ok = CryptSetKeyParam(capi_key_.get(), KP_MODE,
reinterpret_cast<BYTE*>(&cipher_mode), 0);
if (!ok)
return false;
block_size_ = GetCipherBlockSize(capi_key_.get());
if (block_size_ == 0)
return false;
if (iv.size() != block_size_)
return false;
ok = CryptSetKeyParam(capi_key_.get(), KP_IV,
reinterpret_cast<const BYTE*>(iv.data()), 0);
if (!ok)
return false;
DWORD padding_method = PKCS5_PADDING;
ok = CryptSetKeyParam(capi_key_.get(), KP_PADDING,
reinterpret_cast<BYTE*>(&padding_method), 0);
if (!ok)
return false;
return true;
}
bool Encryptor::Encrypt(const base::StringPiece& plaintext,
std::string* ciphertext) {
DWORD data_len = plaintext.size();
CHECK((data_len > 0u) || (mode_ == CBC));
DWORD total_len = data_len + block_size_;
CHECK_GT(total_len, 0u);
CHECK_GT(total_len + 1, data_len);
// CryptoAPI encrypts/decrypts in place.
char* ciphertext_data = WriteInto(ciphertext, total_len + 1);
memcpy(ciphertext_data, plaintext.data(), data_len);
BOOL ok = CryptEncrypt(capi_key_.get(), NULL, TRUE, 0,
reinterpret_cast<BYTE*>(ciphertext_data), &data_len,
total_len);
if (!ok) {
ciphertext->clear();
return false;
}
ciphertext->resize(data_len);
return true;
}
bool Encryptor::Decrypt(const base::StringPiece& ciphertext,
std::string* plaintext) {
DWORD data_len = ciphertext.size();
CHECK_GT(data_len, 0u);
CHECK_GT(data_len + 1, data_len);
// CryptoAPI encrypts/decrypts in place.
char* plaintext_data = WriteInto(plaintext, data_len + 1);
memcpy(plaintext_data, ciphertext.data(), data_len);
BOOL ok = CryptDecrypt(capi_key_.get(), NULL, TRUE, 0,
reinterpret_cast<BYTE*>(plaintext_data), &data_len);
if (!ok) {
plaintext->clear();
return false;
}
plaintext->resize(data_len);
return true;
}
} // namespace crypto

@ -1,79 +0,0 @@
// 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/hmac.h"
#include <CommonCrypto/CommonHMAC.h>
#include "base/logging.h"
namespace crypto {
struct HMACPlatformData {
std::string key_;
};
HMAC::HMAC(HashAlgorithm hash_alg)
: hash_alg_(hash_alg), plat_(new HMACPlatformData()) {
// Only SHA-1 and SHA-256 hash algorithms are supported now.
DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256);
}
bool HMAC::Init(const unsigned char *key, int key_length) {
if (!plat_->key_.empty()) {
// Init must not be called more than once on the same HMAC object.
NOTREACHED();
return false;
}
plat_->key_.assign(reinterpret_cast<const char*>(key), key_length);
return true;
}
HMAC::~HMAC() {
// Zero out key copy.
plat_->key_.assign(plat_->key_.length(), std::string::value_type());
plat_->key_.clear();
plat_->key_.reserve(0);
}
bool HMAC::Sign(const base::StringPiece& data,
unsigned char* digest,
int digest_length) const {
if (plat_->key_.empty()) {
// Init has not been called or has failed.
NOTREACHED();
return false;
}
CCHmacAlgorithm algorithm;
int algorithm_digest_length;
switch (hash_alg_) {
case SHA1:
algorithm = kCCHmacAlgSHA1;
algorithm_digest_length = CC_SHA1_DIGEST_LENGTH;
break;
case SHA256:
algorithm = kCCHmacAlgSHA256;
algorithm_digest_length = CC_SHA256_DIGEST_LENGTH;
break;
default:
NOTREACHED();
return false;
}
if (digest_length < algorithm_digest_length) {
NOTREACHED();
return false;
}
CCHmac(algorithm,
plat_->key_.data(), plat_->key_.length(), data.data(), data.length(),
digest);
return true;
}
} // namespace crypto

@ -1,4 +1,4 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// 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.
@ -11,12 +11,12 @@
#include "base/basictypes.h"
#include "crypto/crypto_export.h"
#if defined(USE_NSS)
#include "crypto/scoped_nss_types.h"
#elif defined(OS_MACOSX)
#include <Security/cssmtype.h>
#elif defined(OS_WIN)
#if defined(NACL_WIN64)
// See comments for crypto_nacl_win64 in crypto.gyp.
// Must test for NACL_WIN64 before OS_WIN since former is a subset of latter.
#include "crypto/scoped_capi_types.h"
#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
#include "crypto/scoped_nss_types.h"
#endif
namespace crypto {
@ -59,12 +59,10 @@ class CRYPTO_EXPORT SymmetricKey {
#if defined(USE_OPENSSL)
const std::string& key() { return key_; }
#elif defined(USE_NSS)
PK11SymKey* key() const { return key_.get(); }
#elif defined(OS_MACOSX)
CSSM_DATA cssm_data() const;
#elif defined(OS_WIN)
#elif defined(NACL_WIN64)
HCRYPTKEY key() const { return key_.get(); }
#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
PK11SymKey* key() const { return key_.get(); }
#endif
// Extracts the raw key from the platform specific data.
@ -81,13 +79,7 @@ class CRYPTO_EXPORT SymmetricKey {
#if defined(USE_OPENSSL)
SymmetricKey() {}
std::string key_;
#elif defined(USE_NSS)
explicit SymmetricKey(PK11SymKey* key);
ScopedPK11SymKey key_;
#elif defined(OS_MACOSX)
SymmetricKey(const void* key_data, size_t key_size_in_bits);
std::string key_;
#elif defined(OS_WIN)
#elif defined(NACL_WIN64)
SymmetricKey(HCRYPTPROV provider, HCRYPTKEY key,
const void* key_data, size_t key_size_in_bytes);
@ -101,6 +93,9 @@ class CRYPTO_EXPORT SymmetricKey {
// TODO(rsleevi): See if KP_EFFECTIVE_KEYLEN is the reason why CryptExportKey
// fails with NTE_BAD_KEY/NTE_BAD_LEN
std::string raw_key_;
#elif defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
explicit SymmetricKey(PK11SymKey* key);
ScopedPK11SymKey key_;
#endif
DISALLOW_COPY_AND_ASSIGN(SymmetricKey);

@ -1,159 +0,0 @@
// 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/symmetric_key.h"
#include <CommonCrypto/CommonCryptor.h>
#include <CoreFoundation/CFString.h>
#include <Security/cssm.h>
#include "base/logging.h"
#include "crypto/cssm_init.h"
namespace {
CSSM_KEY_TYPE CheckKeyParams(crypto::SymmetricKey::Algorithm algorithm,
size_t key_size_in_bits) {
if (algorithm == crypto::SymmetricKey::AES) {
CHECK(key_size_in_bits == 128 ||
key_size_in_bits == 192 ||
key_size_in_bits == 256)
<< "Invalid key size " << key_size_in_bits << " bits";
return CSSM_ALGID_AES;
} else {
// FIPS 198 Section 3 requires a HMAC-SHA-1 derived keys to be at least
// (HMAC-SHA-1 output size / 2) to be compliant. Since the ouput size of
// HMAC-SHA-1 is 160 bits, we require at least 80 bits here.
CHECK(algorithm == crypto::SymmetricKey::HMAC_SHA1);
CHECK(key_size_in_bits >= 80 && (key_size_in_bits % 8) == 0)
<< "Invalid key size " << key_size_in_bits << " bits";
return CSSM_ALGID_SHA1HMAC_LEGACY;
}
}
uint8_t* CreateRandomBytes(size_t size) {
CSSM_RETURN err;
CSSM_CC_HANDLE ctx;
err = CSSM_CSP_CreateRandomGenContext(crypto::GetSharedCSPHandle(),
CSSM_ALGID_APPLE_YARROW,
NULL,
size, &ctx);
if (err) {
crypto::LogCSSMError("CSSM_CSP_CreateRandomGenContext", err);
return NULL;
}
CSSM_DATA random_data = {};
err = CSSM_GenerateRandom(ctx, &random_data);
if (err) {
crypto::LogCSSMError("CSSM_GenerateRandom", err);
random_data.Data = NULL;
}
CSSM_DeleteContext(ctx);
return random_data.Data; // Caller responsible for freeing this.
}
inline CSSM_DATA StringToData(const std::string& str) {
CSSM_DATA data = {
str.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(str.data()))
};
return data;
}
} // namespace
namespace crypto {
SymmetricKey::~SymmetricKey() {
std::fill(key_.begin(), key_.end(), 0);
}
// static
SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
size_t key_size_in_bits) {
CheckKeyParams(algorithm, key_size_in_bits);
size_t key_size_in_bytes = (key_size_in_bits + 7) / 8;
uint8_t* random_bytes = CreateRandomBytes(key_size_in_bytes);
if (!random_bytes)
return NULL;
SymmetricKey *key = new SymmetricKey(random_bytes, key_size_in_bits);
std::fill(random_bytes, random_bytes + key_size_in_bytes, 0);
free(random_bytes);
return key;
}
// static
SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
const std::string& password,
const std::string& salt,
size_t iterations,
size_t key_size_in_bits) {
// Derived (haha) from cdsaDeriveKey() in Apple's CryptoSample.
CSSM_KEY_TYPE key_type = CheckKeyParams(algorithm, key_size_in_bits);
SymmetricKey* derived_key = NULL;
CSSM_KEY cssm_key = {};
CSSM_CC_HANDLE ctx = 0;
CSSM_ACCESS_CREDENTIALS credentials = {};
CSSM_RETURN err;
CSSM_DATA salt_data = StringToData(salt);
err = CSSM_CSP_CreateDeriveKeyContext(GetSharedCSPHandle(),
CSSM_ALGID_PKCS5_PBKDF2,
key_type, key_size_in_bits,
&credentials,
NULL,
iterations,
&salt_data,
NULL,
&ctx);
if (err) {
LogCSSMError("CSSM_CSP_CreateDeriveKeyContext", err);
return NULL;
}
CSSM_PKCS5_PBKDF2_PARAMS params = {};
params.Passphrase = StringToData(password);
params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
CSSM_DATA param_data = {sizeof(params), reinterpret_cast<uint8_t*>(&params)};
err = CSSM_DeriveKey(ctx,
&param_data,
CSSM_KEYUSE_ANY,
CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
NULL,
NULL,
&cssm_key);
if (err) {
LogCSSMError("CSSM_DeriveKey", err);
goto exit;
}
DCHECK_EQ(cssm_key.KeyData.Length, key_size_in_bits / 8);
derived_key = new SymmetricKey(cssm_key.KeyData.Data, key_size_in_bits);
exit:
CSSM_DeleteContext(ctx);
CSSM_FreeKey(GetSharedCSPHandle(), &credentials, &cssm_key, false);
return derived_key;
}
// static
SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
const std::string& raw_key) {
return new SymmetricKey(raw_key.data(), raw_key.size() * 8);
}
SymmetricKey::SymmetricKey(const void* key_data, size_t key_size_in_bits)
: key_(reinterpret_cast<const char*>(key_data), key_size_in_bits / 8) {
}
bool SymmetricKey::GetRawKey(std::string* raw_key) {
*raw_key = key_;
return true;
}
CSSM_DATA SymmetricKey::cssm_data() const {
return StringToData(key_);
}
} // namespace crypto

@ -435,7 +435,7 @@ TEST_F(FFmpegVideoDecoderTest, DecodeEncryptedFrame_WrongKey) {
VideoDecoder::DecoderStatus status;
scoped_refptr<VideoFrame> video_frame;
Read(&status, &video_frame);
#if defined(OS_LINUX)
#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
EXPECT_EQ(VideoDecoder::kDecodeError, status);
#else
EXPECT_EQ(VideoDecoder::kDecryptError, status);