15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/symmetric_key.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <nss.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pk11pub.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey::~SymmetricKey() {}
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              size_t key_size_in_bits) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(AES, algorithm);
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureNSSInit();
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Whitelist supported key sizes to avoid accidentaly relying on
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // algorithms available in NSS but not BoringSSL and vice
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // versa. Note that BoringSSL does not support AES-192.
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (key_size_in_bits != 128 && key_size_in_bits != 256)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPK11Slot slot(PK11_GetInternalSlot());
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!slot.get())
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11SymKey* sym_key = PK11_KeyGen(slot.get(), CKM_AES_KEY_GEN, NULL,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    key_size_in_bits / 8, NULL);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sym_key)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new SymmetricKey(sym_key);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const std::string& password,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const std::string& salt,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  size_t iterations,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  size_t key_size_in_bits) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureNSSInit();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (salt.empty() || iterations == 0 || key_size_in_bits == 0)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (algorithm == AES) {
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Whitelist supported key sizes to avoid accidentaly relying on
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // algorithms available in NSS but not BoringSSL and vice
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // versa. Note that BoringSSL does not support AES-192.
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (key_size_in_bits != 128 && key_size_in_bits != 256)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return NULL;
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem password_item;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  password_item.type = siBuffer;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  password_item.data = reinterpret_cast<unsigned char*>(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<char *>(password.data()));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  password_item.len = password.size();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem salt_item;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  salt_item.type = siBuffer;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  salt_item.data = reinterpret_cast<unsigned char*>(
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<char *>(salt.data()));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  salt_item.len = salt.size();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidTag cipher_algorithm =
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      algorithm == AES ? SEC_OID_AES_256_CBC : SEC_OID_HMAC_SHA1;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedSECAlgorithmID alg_id(PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          cipher_algorithm,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          SEC_OID_HMAC_SHA1,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          key_size_in_bits / 8,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          iterations,
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                          &salt_item));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!alg_id.get())
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPK11Slot slot(PK11_GetInternalSlot());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!slot.get())
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11SymKey* sym_key = PK11_PBEKeyGen(slot.get(), alg_id.get(), &password_item,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       PR_FALSE, NULL);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sym_key)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new SymmetricKey(sym_key);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& raw_key) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureNSSInit();
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (algorithm == AES) {
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // Whitelist supported key sizes to avoid accidentaly relying on
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // algorithms available in NSS but not BoringSSL and vice
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // versa. Note that BoringSSL does not support AES-192.
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (raw_key.size() != 128/8 && raw_key.size() != 256/8)
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return NULL;
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CK_MECHANISM_TYPE cipher =
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      algorithm == AES ? CKM_AES_CBC : CKM_SHA_1_HMAC;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem key_item;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_item.type = siBuffer;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_item.data = reinterpret_cast<unsigned char*>(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<char *>(raw_key.data()));
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_item.len = raw_key.size();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPK11Slot slot(PK11_GetInternalSlot());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!slot.get())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The exact value of the |origin| argument doesn't matter to NSS as long as
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // placeholder.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PK11SymKey* sym_key = PK11_ImportSymKey(slot.get(), cipher, PK11_OriginUnwrap,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          CKA_ENCRYPT, &key_item, NULL);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sym_key)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new SymmetricKey(sym_key);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SymmetricKey::GetRawKey(std::string* raw_key) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = PK11_ExtractKeyValue(key_.get());
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (SECSuccess != rv)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem* key_item = PK11_GetKeyData(key_.get());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!key_item)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  raw_key->assign(reinterpret_cast<char*>(key_item->data), key_item->len);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey::SymmetricKey(PK11SymKey* key) : key_(key) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
150