diff options
author | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-29 18:22:24 +0000 |
---|---|---|
committer | snej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-29 18:22:24 +0000 |
commit | 10811823389d6dd702212008a8e9f3901b804641 (patch) | |
tree | 611200c403f60748d076b08814e78b9ef441cf0e /base/crypto | |
parent | 7fd5f9355f6c3443ca389c4910baf946892bb5da (diff) | |
download | chromium_src-10811823389d6dd702212008a8e9f3901b804641.zip chromium_src-10811823389d6dd702212008a8e9f3901b804641.tar.gz chromium_src-10811823389d6dd702212008a8e9f3901b804641.tar.bz2 |
Add Mac implementations of new SymmetricKey and Encryptor classes.
BUG=none
TEST=EncryptorTest, SymmetricKeyTest
Review URL: http://codereview.chromium.org/1347002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42964 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/crypto')
-rw-r--r-- | base/crypto/cssm_init.cc | 36 | ||||
-rw-r--r-- | base/crypto/cssm_init.h | 6 | ||||
-rw-r--r-- | base/crypto/encryptor.h | 6 | ||||
-rw-r--r-- | base/crypto/encryptor_mac.cc | 55 | ||||
-rw-r--r-- | base/crypto/encryptor_unittest.cc | 4 | ||||
-rw-r--r-- | base/crypto/rsa_private_key.h | 2 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_mac.cc | 25 | ||||
-rw-r--r-- | base/crypto/signature_creator.h | 1 | ||||
-rw-r--r-- | base/crypto/signature_creator_mac.cc | 16 | ||||
-rw-r--r-- | base/crypto/signature_verifier.h | 2 | ||||
-rw-r--r-- | base/crypto/signature_verifier_mac.cc | 18 | ||||
-rw-r--r-- | base/crypto/symmetric_key.h | 25 | ||||
-rw-r--r-- | base/crypto/symmetric_key_mac.cc | 130 | ||||
-rw-r--r-- | base/crypto/symmetric_key_nss.cc | 15 | ||||
-rw-r--r-- | base/crypto/symmetric_key_unittest.cc | 129 | ||||
-rw-r--r-- | base/crypto/symmetric_key_win.cc | 5 |
16 files changed, 379 insertions, 96 deletions
diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc index c3cbbd2..510ae0c 100644 --- a/base/crypto/cssm_init.cc +++ b/base/crypto/cssm_init.cc @@ -3,8 +3,12 @@ // found in the LICENSE file. #include "base/crypto/cssm_init.h" + +#include <Security/SecBase.h> + #include "base/logging.h" #include "base/singleton.h" +#include "base/sys_string_conversions.h" // When writing crypto code for Mac OS X, you may find the following // documentation useful: @@ -17,7 +21,7 @@ namespace { class CSSMInitSingleton { public: - CSSMInitSingleton() : inited_(false), loaded_(false) { + CSSMInitSingleton() : inited_(false), loaded_(false), csp_handle_(NULL) { static CSSM_VERSION version = {2, 0}; // TODO(wtc): what should our caller GUID be? static const CSSM_GUID test_guid = { @@ -39,10 +43,20 @@ class CSSMInitSingleton { return; } loaded_ = true; + + crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, + &base::kCssmMemoryFunctions, 0, + CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, + NULL, 0, NULL, &csp_handle_); + DCHECK(crtn == CSSM_OK); } ~CSSMInitSingleton() { CSSM_RETURN crtn; + if (csp_handle_) { + CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_); + DCHECK(crtn == CSSM_OK); + } if (loaded_) { crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL); DCHECK(crtn == CSSM_OK); @@ -53,9 +67,12 @@ class CSSMInitSingleton { } } + CSSM_CSP_HANDLE csp_handle() const {return csp_handle_;} + private: bool inited_; // True if CSSM_Init has been called successfully. bool loaded_; // True if CSSM_ModuleLoad has been called successfully. + CSSM_CSP_HANDLE csp_handle_; }; } // namespace @@ -66,6 +83,10 @@ void EnsureCSSMInit() { Singleton<CSSMInitSingleton>::get(); } +CSSM_CSP_HANDLE GetSharedCSPHandle() { + return Singleton<CSSMInitSingleton>::get()->csp_handle(); +} + void* CSSMMalloc(CSSM_SIZE size, void *alloc_ref) { return malloc(size); } @@ -90,4 +111,17 @@ const CSSM_API_MEMORY_FUNCS kCssmMemoryFunctions = { NULL }; +void LogCSSMError(const char *fn_name, CSSM_RETURN err) { + if (!err) + return; + CFStringRef cfstr = SecCopyErrorMessageString(err, NULL); + if (cfstr) { + std::string err_name = SysCFStringRefToUTF8(cfstr); + CFRelease(cfstr); + LOG(ERROR) << fn_name << " returned " << err << " (" << err_name << ")"; + } else { + LOG(ERROR) << fn_name << " returned " << err; + } +} + } // namespace base diff --git a/base/crypto/cssm_init.h b/base/crypto/cssm_init.h index 2637542..721b2e8 100644 --- a/base/crypto/cssm_init.h +++ b/base/crypto/cssm_init.h @@ -17,9 +17,15 @@ namespace base { // ever be initialized once. CSSM will be properly shut down on program exit. void EnsureCSSMInit(); +// Returns the shared CSP handle used by CSSM functions. +CSSM_CSP_HANDLE GetSharedCSPHandle(); + // 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. +void LogCSSMError(const char *function_name, CSSM_RETURN err); + } // namespace base #endif // BASE_CRYPTO_CSSM_INIT_H_ diff --git a/base/crypto/encryptor.h b/base/crypto/encryptor.h index 55199d5..a09c7cd 100644 --- a/base/crypto/encryptor.h +++ b/base/crypto/encryptor.h @@ -40,6 +40,12 @@ class Encryptor { #if defined(USE_NSS) ScopedPK11Slot slot_; ScopedSECItem param_; +#elif defined(OS_MACOSX) + bool Crypt(int /*CCOperation*/ op, + const std::string& input, + std::string* output); + + std::string iv_; #endif }; diff --git a/base/crypto/encryptor_mac.cc b/base/crypto/encryptor_mac.cc index 2b04537..4e8984a 100644 --- a/base/crypto/encryptor_mac.cc +++ b/base/crypto/encryptor_mac.cc @@ -4,10 +4,12 @@ #include "base/crypto/encryptor.h" -namespace base { +#include <CommonCrypto/CommonCryptor.h> + +#include "base/logging.h" +#include "base/string_util.h" -// TODO(albertb): Implement on Mac using the Common Crypto Library: -// http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/CCCryptor.3cc.html#//apple_ref/doc/man/10.5/3cc/CCCryptor?useVersion=10.5 +namespace base { Encryptor::Encryptor() { } @@ -16,15 +18,56 @@ Encryptor::~Encryptor() { } bool Encryptor::Init(SymmetricKey* key, Mode mode, const std::string& iv) { - return false; + 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_.reset(key); + mode_ = mode; + iv_ = iv; + return true; +} + +bool Encryptor::Crypt(int /*CCOperation*/ op, + const std::string& input, + std::string* output) { + DCHECK(key_.get()); + 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(); + CCCryptorStatus err = CCCrypt(op, + kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + raw_key.Data, raw_key.Length, + iv_.data(), + input.data(), input.size(), + WriteInto(output, output_size), + output_size, + &output_size); + if (err) { + output->resize(0); + LOG(ERROR) << "CCCrypt returned " << err; + return false; + } + output->resize(output_size); + return true; } bool Encryptor::Encrypt(const std::string& plaintext, std::string* ciphertext) { - return false; + return Crypt(kCCEncrypt, plaintext, ciphertext); } bool Encryptor::Decrypt(const std::string& ciphertext, std::string* plaintext) { - return false; + return Crypt(kCCDecrypt, ciphertext, plaintext); } } // namespace base diff --git a/base/crypto/encryptor_unittest.cc b/base/crypto/encryptor_unittest.cc index c183d90..218c7ba 100644 --- a/base/crypto/encryptor_unittest.cc +++ b/base/crypto/encryptor_unittest.cc @@ -11,7 +11,7 @@ #include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS) +#if defined(USE_NSS) || defined(OS_MACOSX) #define MAYBE(name) name #else #define MAYBE(name) DISABLED_ ## name @@ -19,7 +19,7 @@ TEST(EncryptorTest, MAYBE(EncryptDecrypt)) { scoped_ptr<base::SymmetricKey> key(base::SymmetricKey::DeriveKeyFromPassword( - base::SymmetricKey::AES, "password", "salt", 1000, 32)); + base::SymmetricKey::AES, "password", "saltiest", 1000, 256)); EXPECT_TRUE(NULL != key.get()); base::Encryptor encryptor; diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index 7f562ec..ae410e0 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -174,7 +174,6 @@ class RSAPrivateKey { HCRYPTPROV provider() { return provider_; } HCRYPTKEY key() { return key_; } #elif defined(OS_MACOSX) - CSSM_CSP_HANDLE csp_handle() { return csp_handle_; } CSSM_KEY_PTR key() { return &key_; } #endif @@ -199,7 +198,6 @@ private: HCRYPTKEY key_; #elif defined(OS_MACOSX) CSSM_KEY key_; - CSSM_CSP_HANDLE csp_handle_; #endif DISALLOW_COPY_AND_ASSIGN(RSAPrivateKey); diff --git a/base/crypto/rsa_private_key_mac.cc b/base/crypto/rsa_private_key_mac.cc index 61845e3..6dc6a42 100644 --- a/base/crypto/rsa_private_key_mac.cc +++ b/base/crypto/rsa_private_key_mac.cc @@ -18,7 +18,7 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { CSSM_CC_HANDLE cc_handle; CSSM_RETURN crtn; - crtn = CSSM_CSP_CreateKeyGenContext(result->csp_handle(), CSSM_ALGID_RSA, + crtn = CSSM_CSP_CreateKeyGenContext(GetSharedCSPHandle(), CSSM_ALGID_RSA, num_bits, NULL, NULL, NULL, NULL, NULL, &cc_handle); if (crtn) { @@ -43,7 +43,7 @@ RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { } // Public key is not needed. - CSSM_FreeKey(result->csp_handle(), NULL, &public_key, CSSM_FALSE); + CSSM_FreeKey(GetSharedCSPHandle(), NULL, &public_key, CSSM_FALSE); return result.release(); } @@ -70,7 +70,7 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( CSSM_KEY_SIZE key_size; CSSM_RETURN crtn; - crtn = CSSM_QueryKeySizeInBits(result->csp_handle(), NULL, &key, &key_size); + crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, &key, &key_size); if (crtn) { NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn; return NULL; @@ -82,7 +82,7 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( CSSM_ACCESS_CREDENTIALS creds; memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); CSSM_CC_HANDLE cc_handle; - crtn = CSSM_CSP_CreateSymmetricContext(result->csp_handle(), CSSM_ALGID_NONE, + crtn = CSSM_CSP_CreateSymmetricContext(GetSharedCSPHandle(), CSSM_ALGID_NONE, CSSM_ALGMODE_NONE, &creds, NULL, NULL, CSSM_PADDING_NONE, 0, &cc_handle); if (crtn) { NOTREACHED() << "CSSM_CSP_CreateSymmetricContext failed: " << crtn; @@ -103,26 +103,15 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( return result.release(); } -RSAPrivateKey::RSAPrivateKey() : csp_handle_(0) { +RSAPrivateKey::RSAPrivateKey() { memset(&key_, 0, sizeof(key_)); EnsureCSSMInit(); - - static CSSM_VERSION version = {2, 0}; - CSSM_RETURN crtn; - crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &kCssmMemoryFunctions, 0, - CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, - NULL, 0, NULL, &csp_handle_); - DCHECK(crtn == CSSM_OK); } RSAPrivateKey::~RSAPrivateKey() { - if (csp_handle_) { - if (key_.KeyData.Data) { - CSSM_FreeKey(csp_handle_, NULL, &key_, CSSM_FALSE); - } - CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_); - DCHECK(crtn == CSSM_OK); + if (key_.KeyData.Data) { + CSSM_FreeKey(GetSharedCSPHandle(), NULL, &key_, CSSM_FALSE); } } diff --git a/base/crypto/signature_creator.h b/base/crypto/signature_creator.h index a2d5cf6..9f5a909 100644 --- a/base/crypto/signature_creator.h +++ b/base/crypto/signature_creator.h @@ -49,7 +49,6 @@ class SignatureCreator { #if defined(USE_NSS) SGNContextStr* sign_context_; #elif defined(OS_MACOSX) - CSSM_CSP_HANDLE csp_handle_; CSSM_CC_HANDLE sig_handle_; #elif defined(OS_WIN) HCRYPTHASH hash_object_; diff --git a/base/crypto/signature_creator_mac.cc b/base/crypto/signature_creator_mac.cc index ee0ca05..f96b1d4 100644 --- a/base/crypto/signature_creator_mac.cc +++ b/base/crypto/signature_creator_mac.cc @@ -18,7 +18,7 @@ SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { result->key_ = key; CSSM_RETURN crtn; - crtn = CSSM_CSP_CreateSignatureContext(result->csp_handle_, + crtn = CSSM_CSP_CreateSignatureContext(GetSharedCSPHandle(), CSSM_ALGID_SHA1WithRSA, NULL, key->key(), @@ -37,15 +37,8 @@ SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { return result.release(); } -SignatureCreator::SignatureCreator() : csp_handle_(0), sig_handle_(0) { +SignatureCreator::SignatureCreator() : sig_handle_(0) { EnsureCSSMInit(); - - static CSSM_VERSION version = {2, 0}; - CSSM_RETURN crtn; - crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &kCssmMemoryFunctions, 0, - CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, - NULL, 0, NULL, &csp_handle_); - DCHECK(crtn == CSSM_OK); } SignatureCreator::~SignatureCreator() { @@ -54,11 +47,6 @@ SignatureCreator::~SignatureCreator() { crtn = CSSM_DeleteContext(sig_handle_); DCHECK(crtn == CSSM_OK); } - - if (csp_handle_) { - CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_); - DCHECK(crtn == CSSM_OK); - } } bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { diff --git a/base/crypto/signature_verifier.h b/base/crypto/signature_verifier.h index 89bf565..bfe6c332 100644 --- a/base/crypto/signature_verifier.h +++ b/base/crypto/signature_verifier.h @@ -86,8 +86,6 @@ class SignatureVerifier { #elif defined(OS_MACOSX) std::vector<uint8> public_key_info_; - CSSM_CSP_HANDLE csp_handle_; - CSSM_CC_HANDLE sig_handle_; CSSM_KEY public_key_; diff --git a/base/crypto/signature_verifier_mac.cc b/base/crypto/signature_verifier_mac.cc index a4c1870..c8bfa8b 100644 --- a/base/crypto/signature_verifier_mac.cc +++ b/base/crypto/signature_verifier_mac.cc @@ -11,23 +11,12 @@ namespace base { -SignatureVerifier::SignatureVerifier() : csp_handle_(0), sig_handle_(0) { +SignatureVerifier::SignatureVerifier() : sig_handle_(0) { EnsureCSSMInit(); - - static CSSM_VERSION version = {2, 0}; - CSSM_RETURN crtn; - crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &kCssmMemoryFunctions, 0, - CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, - NULL, 0, NULL, &csp_handle_); - DCHECK(crtn == CSSM_OK); } SignatureVerifier::~SignatureVerifier() { Reset(); - if (csp_handle_) { - CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_); - DCHECK(crtn == CSSM_OK); - } } bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, @@ -54,7 +43,8 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, public_key_.KeyHeader.KeyUsage = CSSM_KEYUSE_VERIFY; CSSM_KEY_SIZE key_size; CSSM_RETURN crtn; - crtn = CSSM_QueryKeySizeInBits(csp_handle_, NULL, &public_key_, &key_size); + crtn = CSSM_QueryKeySizeInBits(GetSharedCSPHandle(), NULL, + &public_key_, &key_size); if (crtn) { NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn; return false; @@ -64,7 +54,7 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, // TODO(wtc): decode signature_algorithm... CSSM_ALGORITHMS sig_alg = CSSM_ALGID_SHA1WithRSA; - crtn = CSSM_CSP_CreateSignatureContext(csp_handle_, sig_alg, NULL, + crtn = CSSM_CSP_CreateSignatureContext(GetSharedCSPHandle(), sig_alg, NULL, &public_key_, &sig_handle_); if (crtn) { NOTREACHED(); diff --git a/base/crypto/symmetric_key.h b/base/crypto/symmetric_key.h index 1e1aed5..f528213 100644 --- a/base/crypto/symmetric_key.h +++ b/base/crypto/symmetric_key.h @@ -11,7 +11,9 @@ #if defined(USE_NSS) #include "base/crypto/scoped_nss_types.h" -#endif // USE_NSS +#elif defined(OS_MACOSX) +#include <Security/cssmtype.h> +#endif namespace base { @@ -26,21 +28,25 @@ class SymmetricKey { virtual ~SymmetricKey() {} - // Generates a random key suitable to be used with |cipher| and of |key_size| - // bytes. The caller is responsible for deleting the returned SymmetricKey. - static SymmetricKey* GenerateRandomKey(Algorithm algorithm, size_t key_size); + // Generates a random key suitable to be used with |cipher| and of + // |key_size_in_bits| bits. + // The caller is responsible for deleting the returned SymmetricKey. + static SymmetricKey* GenerateRandomKey(Algorithm algorithm, + size_t key_size_in_bits); // Derives a key from the supplied password and salt using PBKDF2. The caller - // is respnosible for deleting the returned SymmetricKey. + // is responsible for deleting the returned SymmetricKey. static SymmetricKey* DeriveKeyFromPassword(Algorithm algorithm, const std::string& password, const std::string& salt, size_t iterations, - size_t key_size); + size_t key_size_in_bits); #if defined(USE_NSS) PK11SymKey* key() const { return key_.get(); } -#endif // USE_NSS +#elif defined(OS_MACOSX) + CSSM_DATA cssm_data() const; +#endif // Extracts the raw key from the platform specific data. This should only be // done in unit tests to verify that keys are generated correctly. @@ -50,7 +56,10 @@ class SymmetricKey { #if defined(USE_NSS) explicit SymmetricKey(PK11SymKey* key) : key_(key) {} ScopedPK11SymKey key_; -#endif // USE_NSS +#elif defined(OS_MACOSX) + SymmetricKey(const void* key_data, size_t key_size_in_bits); + std::string key_; +#endif DISALLOW_COPY_AND_ASSIGN(SymmetricKey); }; diff --git a/base/crypto/symmetric_key_mac.cc b/base/crypto/symmetric_key_mac.cc index 8290e71..89277c6 100644 --- a/base/crypto/symmetric_key_mac.cc +++ b/base/crypto/symmetric_key_mac.cc @@ -4,13 +4,75 @@ #include "base/crypto/symmetric_key.h" -namespace base { +#include <CommonCrypto/CommonCryptor.h> +#include <CoreFoundation/CFString.h> +#include <Security/cssm.h> + +#include "base/crypto/cssm_init.h" +#include "base/logging.h" +#include "base/rand_util.h" + +namespace { + +CSSM_KEY_TYPE CheckKeyParams(base::SymmetricKey::Algorithm algorithm, + size_t key_size_in_bits) { + if (algorithm == base::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 { + CHECK(algorithm == base::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; + } +} + +void* CreateRandomBytes(size_t size) { + CSSM_RETURN err; + CSSM_CC_HANDLE ctx; + err = CSSM_CSP_CreateRandomGenContext(base::GetSharedCSPHandle(), + CSSM_ALGID_APPLE_YARROW, + NULL, + size, &ctx); + if (err) { + base::LogCSSMError("CSSM_CSP_CreateRandomGenContext", err); + return NULL; + } + CSSM_DATA random_data = {}; + err = CSSM_GenerateRandom(ctx, &random_data); + if (err) { + base::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; +} -// TODO(albertb): Implement on Mac. +} // namespace + +namespace base { // static -SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, size_t key_size) { - return NULL; +SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, + size_t key_size_in_bits) { + CheckKeyParams(algorithm, key_size_in_bits); + void* random_bytes = CreateRandomBytes((key_size_in_bits + 7) / 8); + if (!random_bytes) + return NULL; + SymmetricKey *key = new SymmetricKey(random_bytes, key_size_in_bits); + free(random_bytes); + return key; } // static @@ -18,12 +80,66 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, const std::string& password, const std::string& salt, size_t iterations, - size_t key_size) { - return NULL; + 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*>(¶ms)}; + err = CSSM_DeriveKey(ctx, + ¶m_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; } +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) { - return false; + *raw_key = key_; + return true; +} + +CSSM_DATA SymmetricKey::cssm_data() const { + return StringToData(key_); } } // namespace base diff --git a/base/crypto/symmetric_key_nss.cc b/base/crypto/symmetric_key_nss.cc index 7196ae4..0fb8cfa 100644 --- a/base/crypto/symmetric_key_nss.cc +++ b/base/crypto/symmetric_key_nss.cc @@ -13,19 +13,20 @@ namespace base { // static -SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, size_t key_size) { +SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, + size_t key_size_in_bits) { DCHECK_EQ(AES, algorithm); EnsureNSSInit(); - if (key_size == 0) + if (key_size_in_bits == 0) return NULL; ScopedPK11Slot slot(PK11_GetBestSlot(CKM_AES_KEY_GEN, NULL)); if (!slot.get()) return NULL; - PK11SymKey* sym_key = PK11_KeyGen(slot.get(), CKM_AES_KEY_GEN, NULL, key_size, - NULL); + PK11SymKey* sym_key = PK11_KeyGen(slot.get(), CKM_AES_KEY_GEN, NULL, + key_size_in_bits / 8, NULL); if (!sym_key) return NULL; @@ -37,9 +38,9 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, const std::string& password, const std::string& salt, size_t iterations, - size_t key_size) { + size_t key_size_in_bits) { EnsureNSSInit(); - if (salt.empty() || iterations == 0 || key_size == 0) + if (salt.empty() || iterations == 0 || key_size_in_bits == 0) return NULL; SECItem password_item; @@ -60,7 +61,7 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, cipher_algorithm, SEC_OID_HMAC_SHA1, - key_size, + key_size_in_bits / 8, iterations, &salt_item)); if (!alg_id.get()) diff --git a/base/crypto/symmetric_key_unittest.cc b/base/crypto/symmetric_key_unittest.cc index fe94b61..486052d 100644 --- a/base/crypto/symmetric_key_unittest.cc +++ b/base/crypto/symmetric_key_unittest.cc @@ -10,7 +10,7 @@ #include "base/string_util.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS) +#if defined(USE_NSS) || defined(OS_MACOSX) #define MAYBE(name) name #else #define MAYBE(name) DISABLED_ ## name @@ -18,26 +18,41 @@ TEST(SymmetricKeyTest, MAYBE(GenerateRandomKey)) { scoped_ptr<base::SymmetricKey> key( - base::SymmetricKey::GenerateRandomKey(base::SymmetricKey::AES, 32)); + base::SymmetricKey::GenerateRandomKey(base::SymmetricKey::AES, 256)); EXPECT_TRUE(NULL != key.get()); + std::string raw_key; + EXPECT_TRUE(key->GetRawKey(&raw_key)); + EXPECT_EQ(32U, raw_key.size()); + + // Do it again and check that the keys are different. + // (Note: this has a one-in-10^77 chance of failure!) + scoped_ptr<base::SymmetricKey> key2( + base::SymmetricKey::GenerateRandomKey(base::SymmetricKey::AES, 256)); + EXPECT_TRUE(NULL != key2.get()); + std::string raw_key2; + EXPECT_TRUE(key2->GetRawKey(&raw_key2)); + EXPECT_EQ(32U, raw_key2.size()); + EXPECT_NE(raw_key, raw_key2); } struct PBKDF2TestVector { const char* password; const char* salt; unsigned int rounds; - unsigned int key_size; - const char* expected; + unsigned int key_size_in_bits; + const uint8 expected[21]; // string literals need 1 extra NUL byte }; // These are the test vectors suggested in: // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt static const PBKDF2TestVector test_vectors[] = { + // These tests come from + // http://www.ietf.org/id/draft-josefsson-pbkdf2-test-vectors-00.txt { "password", "salt", 1, - 20, + 160, "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9" "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", }, @@ -45,7 +60,7 @@ static const PBKDF2TestVector test_vectors[] = { "password", "salt", 2, - 20, + 160, "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e" "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", }, @@ -53,7 +68,7 @@ static const PBKDF2TestVector test_vectors[] = { "password", "salt", 4096, - 20, + 160, "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad" "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", }, @@ -63,26 +78,116 @@ static const PBKDF2TestVector test_vectors[] = { "password", "salt", 16777216, - 20, + 160, "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94" "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", }, #endif + + // These tests come from RFC 3962, via BSD source code at + // http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/bioctl/pbkdf2.c?rev=HEAD&content-type=text/plain + { + "password", + "ATHENA.MIT.EDUraeburn", + 1, + 160, + { + 0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01, + 0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15, + 0x0a, 0xd1, 0xf7, 0xa0 + }, + }, + { + "password", + "ATHENA.MIT.EDUraeburn", + 2, + 160, + { + 0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e, + 0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d, + 0xa0, 0x53, 0x78, 0xb9 + }, + }, + { + "password", + "ATHENA.MIT.EDUraeburn", + 1200, + 160, + { + 0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e, + 0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b, + 0xa7, 0xe5, 0x2d, 0xdb + }, + }, + { + "password", + "\0224VxxV4\022", /* 0x1234567878563412 */ + 5, + 160, + { + 0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6, + 0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49, + 0x3f, 0x98, 0xd2, 0x03 + }, + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase equals block size", + 1200, + 160, + { + 0x13, 0x9c, 0x30, 0xc0, 0x96, 0x6b, 0xc3, 0x2b, + 0xa5, 0x5f, 0xdb, 0xf2, 0x12, 0x53, 0x0a, 0xc9, + 0xc5, 0xec, 0x59, 0xf1 + }, + }, + { + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "pass phrase exceeds block size", + 1200, + 160, + { + 0x9c, 0xca, 0xd6, 0xd4, 0x68, 0x77, 0x0c, 0xd5, + 0x1b, 0x10, 0xe6, 0xa6, 0x87, 0x21, 0xbe, 0x61, + 0x1a, 0x8b, 0x4d, 0x28 + }, + }, + { + "\360\235\204\236", /* g-clef (0xf09d849e) */ + "EXAMPLE.COMpianist", + 50, + 160, + { + 0x6b, 0x9c, 0xf2, 0x6d, 0x45, 0x45, 0x5a, 0x43, + 0xa5, 0xb8, 0xbb, 0x27, 0x6a, 0x40, 0x3b, 0x39, + 0xe7, 0xfe, 0x37, 0xa0 + }, + } }; TEST(SymmetricKeyTest, MAYBE(DeriveKeyFromPassword)) { for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_vectors); ++i) { SCOPED_TRACE(StringPrintf("Test[%u]", i)); +#if defined(OS_MACOSX) + // The OS X crypto libraries have minimum salt and iteration requirements + // so some of the above tests will cause them to barf. Skip these. + if (strlen(test_vectors[i].salt) < 8 || test_vectors[i].rounds < 1000) { + LOG(INFO) << "Skipped test vector #" << i; + continue; + } +#endif // OS_MACOSX scoped_ptr<base::SymmetricKey> key( base::SymmetricKey::DeriveKeyFromPassword( base::SymmetricKey::HMAC_SHA1, test_vectors[i].password, test_vectors[i].salt, - test_vectors[i].rounds, test_vectors[i].key_size)); - EXPECT_TRUE(NULL != key.get()); + test_vectors[i].rounds, test_vectors[i].key_size_in_bits)); + ASSERT_TRUE(NULL != key.get()); std::string raw_key; key->GetRawKey(&raw_key); - EXPECT_EQ(test_vectors[i].key_size, raw_key.size()); - EXPECT_STREQ(test_vectors[i].expected, raw_key.c_str()); + EXPECT_EQ(test_vectors[i].key_size_in_bits / 8, raw_key.size()); + EXPECT_EQ(0, memcmp(test_vectors[i].expected, + raw_key.data(), + raw_key.size())); } } diff --git a/base/crypto/symmetric_key_win.cc b/base/crypto/symmetric_key_win.cc index 014e1ba..c9be914 100644 --- a/base/crypto/symmetric_key_win.cc +++ b/base/crypto/symmetric_key_win.cc @@ -9,7 +9,8 @@ namespace base { // TODO(albertb): Implement on Windows. // static -SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, unsigned int key_size) { +SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, + size_t key_size_in_bits) { return NULL; } @@ -18,7 +19,7 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, const std::string& password, const std::string& salt, size_t iterations, - size_t key_size) { + size_t key_size_in_bits) { return NULL; } |