summaryrefslogtreecommitdiffstats
path: root/base/crypto
diff options
context:
space:
mode:
authorsnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-29 18:22:24 +0000
committersnej@chromium.org <snej@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-29 18:22:24 +0000
commit10811823389d6dd702212008a8e9f3901b804641 (patch)
tree611200c403f60748d076b08814e78b9ef441cf0e /base/crypto
parent7fd5f9355f6c3443ca389c4910baf946892bb5da (diff)
downloadchromium_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.cc36
-rw-r--r--base/crypto/cssm_init.h6
-rw-r--r--base/crypto/encryptor.h6
-rw-r--r--base/crypto/encryptor_mac.cc55
-rw-r--r--base/crypto/encryptor_unittest.cc4
-rw-r--r--base/crypto/rsa_private_key.h2
-rw-r--r--base/crypto/rsa_private_key_mac.cc25
-rw-r--r--base/crypto/signature_creator.h1
-rw-r--r--base/crypto/signature_creator_mac.cc16
-rw-r--r--base/crypto/signature_verifier.h2
-rw-r--r--base/crypto/signature_verifier_mac.cc18
-rw-r--r--base/crypto/symmetric_key.h25
-rw-r--r--base/crypto/symmetric_key_mac.cc130
-rw-r--r--base/crypto/symmetric_key_nss.cc15
-rw-r--r--base/crypto/symmetric_key_unittest.cc129
-rw-r--r--base/crypto/symmetric_key_win.cc5
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*>(&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;
}
+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;
}