• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CheckKeyParams(crypto::SymmetricKey::Algorithm algorithm,size_t key_size_in_bits)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 
CreateRandomBytes(size_t size)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 
StringToData(const std::string & str)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 
~SymmetricKey()68 SymmetricKey::~SymmetricKey() {}
69 
70 // static
GenerateRandomKey(Algorithm algorithm,size_t key_size_in_bits)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
DeriveKeyFromPassword(Algorithm algorithm,const std::string & password,const std::string & salt,size_t iterations,size_t key_size_in_bits)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
Import(Algorithm algorithm,const std::string & raw_key)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 
SymmetricKey(const void * key_data,size_t key_size_in_bits)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 
GetRawKey(std::string * raw_key)146 bool SymmetricKey::GetRawKey(std::string* raw_key) {
147   *raw_key = key_;
148   return true;
149 }
150 
cssm_data() const151 CSSM_DATA SymmetricKey::cssm_data() const {
152   return StringToData(key_);
153 }
154 
155 }  // namespace crypto
156