1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/symmetric_key.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <CommonCrypto/CommonCryptor.h> 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <CoreFoundation/CFString.h> 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <Security/cssm.h> 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/cssm_init.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenCSSM_KEY_TYPE CheckKeyParams(crypto::SymmetricKey::Algorithm algorithm, 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t key_size_in_bits) { 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (algorithm == crypto::SymmetricKey::AES) { 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(key_size_in_bits == 128 || 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch key_size_in_bits == 192 || 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch key_size_in_bits == 256) 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "Invalid key size " << key_size_in_bits << " bits"; 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CSSM_ALGID_AES; 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // FIPS 198 Section 3 requires a HMAC-SHA-1 derived keys to be at least 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // (HMAC-SHA-1 output size / 2) to be compliant. Since the ouput size of 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // HMAC-SHA-1 is 160 bits, we require at least 80 bits here. 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CHECK(algorithm == crypto::SymmetricKey::HMAC_SHA1); 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CHECK(key_size_in_bits >= 80 && (key_size_in_bits % 8) == 0) 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << "Invalid key size " << key_size_in_bits << " bits"; 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return CSSM_ALGID_SHA1HMAC_LEGACY; 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid* CreateRandomBytes(size_t size) { 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_RETURN err; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_CC_HANDLE ctx; 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen err = CSSM_CSP_CreateRandomGenContext(crypto::GetSharedCSPHandle(), 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_ALGID_APPLE_YARROW, 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size, &ctx); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (err) { 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crypto::LogCSSMError("CSSM_CSP_CreateRandomGenContext", err); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DATA random_data = {}; 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch err = CSSM_GenerateRandom(ctx, &random_data); 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (err) { 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen crypto::LogCSSMError("CSSM_GenerateRandom", err); 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch random_data.Data = NULL; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DeleteContext(ctx); 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return random_data.Data; // Caller responsible for freeing this 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochinline CSSM_DATA StringToData(const std::string& str) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DATA data = { 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch str.size(), 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<uint8_t*>(const_cast<char*>(str.data())) 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return data; 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace crypto { 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSymmetricKey::~SymmetricKey() {} 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t key_size_in_bits) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CheckKeyParams(algorithm, key_size_in_bits); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch void* random_bytes = CreateRandomBytes((key_size_in_bits + 7) / 8); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!random_bytes) 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SymmetricKey *key = new SymmetricKey(random_bytes, key_size_in_bits); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch free(random_bytes); 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return key; 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& password, 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string& salt, 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t iterations, 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t key_size_in_bits) { 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Derived (haha) from cdsaDeriveKey() in Apple's CryptoSample. 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_KEY_TYPE key_type = CheckKeyParams(algorithm, key_size_in_bits); 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SymmetricKey* derived_key = NULL; 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_KEY cssm_key = {}; 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_CC_HANDLE ctx = 0; 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_ACCESS_CREDENTIALS credentials = {}; 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_RETURN err; 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DATA salt_data = StringToData(salt); 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch err = CSSM_CSP_CreateDeriveKeyContext(GetSharedCSPHandle(), 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_ALGID_PKCS5_PBKDF2, 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch key_type, key_size_in_bits, 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &credentials, 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch iterations, 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &salt_data, 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ctx); 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (err) { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LogCSSMError("CSSM_CSP_CreateDeriveKeyContext", err); 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_PKCS5_PBKDF2_PARAMS params = {}; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch params.Passphrase = StringToData(password); 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch params.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1; 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DATA param_data = {sizeof(params), reinterpret_cast<uint8_t*>(¶ms)}; 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch err = CSSM_DeriveKey(ctx, 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ¶m_data, 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_KEYUSE_ANY, 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE, 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NULL, 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &cssm_key); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (err) { 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch LogCSSMError("CSSM_DeriveKey", err); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch goto exit; 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(cssm_key.KeyData.Length, key_size_in_bits / 8); 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch derived_key = new SymmetricKey(cssm_key.KeyData.Data, key_size_in_bits); 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch exit: 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_DeleteContext(ctx); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch CSSM_FreeKey(GetSharedCSPHandle(), &credentials, &cssm_key, false); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return derived_key; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// static 1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSymmetricKey* SymmetricKey::Import(Algorithm algorithm, 1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick const std::string& raw_key) { 1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return new SymmetricKey(raw_key.data(), raw_key.size() * 8); 1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSymmetricKey::SymmetricKey(const void *key_data, size_t key_size_in_bits) 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : key_(reinterpret_cast<const char*>(key_data), 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch key_size_in_bits / 8) {} 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SymmetricKey::GetRawKey(std::string* raw_key) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch *raw_key = key_; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochCSSM_DATA SymmetricKey::cssm_data() const { 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return StringToData(key_); 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace crypto 156