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.
5 #include "crypto/symmetric_key.h"
7 #include <CommonCrypto/CommonCryptor.h>
8 #include <CoreFoundation/CFString.h>
9 #include <Security/cssm.h>
11 #include "base/logging.h"
12 #include "crypto/cssm_init.h"
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
;
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
;
35 uint8_t* CreateRandomBytes(size_t size
) {
38 err
= CSSM_CSP_CreateRandomGenContext(crypto::GetSharedCSPHandle(),
39 CSSM_ALGID_APPLE_YARROW
,
43 crypto::LogCSSMError("CSSM_CSP_CreateRandomGenContext", err
);
46 CSSM_DATA random_data
= {};
47 err
= CSSM_GenerateRandom(ctx
, &random_data
);
49 crypto::LogCSSMError("CSSM_GenerateRandom", err
);
50 random_data
.Data
= NULL
;
52 CSSM_DeleteContext(ctx
);
53 return random_data
.Data
; // Caller responsible for freeing this.
56 inline CSSM_DATA
StringToData(const std::string
& str
) {
59 reinterpret_cast<uint8_t*>(const_cast<char*>(str
.data()))
68 SymmetricKey::~SymmetricKey() {
69 std::fill(key_
.begin(), key_
.end(), 0);
73 SymmetricKey
* SymmetricKey::GenerateRandomKey(Algorithm algorithm
,
74 size_t key_size_in_bits
) {
75 CheckKeyParams(algorithm
, key_size_in_bits
);
76 size_t key_size_in_bytes
= (key_size_in_bits
+ 7) / 8;
77 uint8_t* random_bytes
= CreateRandomBytes(key_size_in_bytes
);
80 SymmetricKey
*key
= new SymmetricKey(random_bytes
, key_size_in_bits
);
81 std::fill(random_bytes
, random_bytes
+ key_size_in_bytes
, 0);
87 SymmetricKey
* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm
,
88 const std::string
& password
,
89 const std::string
& salt
,
91 size_t key_size_in_bits
) {
92 // Derived (haha) from cdsaDeriveKey() in Apple's CryptoSample.
93 CSSM_KEY_TYPE key_type
= CheckKeyParams(algorithm
, key_size_in_bits
);
94 SymmetricKey
* derived_key
= NULL
;
95 CSSM_KEY cssm_key
= {};
97 CSSM_CC_HANDLE ctx
= 0;
98 CSSM_ACCESS_CREDENTIALS credentials
= {};
100 CSSM_DATA salt_data
= StringToData(salt
);
101 err
= CSSM_CSP_CreateDeriveKeyContext(GetSharedCSPHandle(),
102 CSSM_ALGID_PKCS5_PBKDF2
,
103 key_type
, key_size_in_bits
,
111 LogCSSMError("CSSM_CSP_CreateDeriveKeyContext", err
);
115 CSSM_PKCS5_PBKDF2_PARAMS params
= {};
116 params
.Passphrase
= StringToData(password
);
117 params
.PseudoRandomFunction
= CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1
;
118 CSSM_DATA param_data
= {sizeof(params
), reinterpret_cast<uint8_t*>(¶ms
)};
119 err
= CSSM_DeriveKey(ctx
,
122 CSSM_KEYATTR_RETURN_DATA
| CSSM_KEYATTR_EXTRACTABLE
,
127 LogCSSMError("CSSM_DeriveKey", err
);
131 DCHECK_EQ(cssm_key
.KeyData
.Length
, key_size_in_bits
/ 8);
132 derived_key
= new SymmetricKey(cssm_key
.KeyData
.Data
, key_size_in_bits
);
135 CSSM_DeleteContext(ctx
);
136 CSSM_FreeKey(GetSharedCSPHandle(), &credentials
, &cssm_key
, false);
141 SymmetricKey
* SymmetricKey::Import(Algorithm algorithm
,
142 const std::string
& raw_key
) {
143 return new SymmetricKey(raw_key
.data(), raw_key
.size() * 8);
146 SymmetricKey::SymmetricKey(const void* key_data
, size_t key_size_in_bits
)
147 : key_(reinterpret_cast<const char*>(key_data
), key_size_in_bits
/ 8) {
150 bool SymmetricKey::GetRawKey(std::string
* raw_key
) {
155 CSSM_DATA
SymmetricKey::cssm_data() const {
156 return StringToData(key_
);
159 } // namespace crypto