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