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*>(&params)};
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  err = CSSM_DeriveKey(ctx,
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                       &param_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