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 <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(wtc): replace scoped_array by std::vector.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sys_byteorder.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following is a non-public Microsoft header documented in MSDN under
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CryptImportKey / CryptExportKey. Following the header is the byte array of
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the actual plaintext key.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct PlaintextBlobHeader {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BLOBHEADER hdr;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD cbKeySize;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CryptoAPI makes use of three distinct ALG_IDs for AES, rather than just
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CALG_AES (which exists, but depending on the functions you are calling, may
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// result in function failure, whereas the subtype would succeed).
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ALG_ID GetAESAlgIDForKeySize(size_t key_size_in_bits) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only AES-128/-192/-256 is supported in CryptoAPI.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (key_size_in_bits) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 128:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return CALG_AES_128;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 192:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return CALG_AES_192;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 256:
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return CALG_AES_256;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Imports a raw/plaintext key of |key_size| stored in |*key_data| into a new
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// key created for the specified |provider|. |alg| contains the algorithm of
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the key being imported.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If |key_data| is intended to be used as an HMAC key, then |alg| should be
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CALG_HMAC.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If successful, returns true and stores the imported key in |*key|.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(wtc): use this function in hmac_win.cc.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ImportRawKey(HCRYPTPROV provider,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ALG_ID alg,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const void* key_data, size_t key_size,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ScopedHCRYPTKEY* key) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(key_size, 0);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD actual_size =
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<DWORD>(sizeof(PlaintextBlobHeader) + key_size);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BYTE> tmp_data(actual_size);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BYTE* actual_key = &tmp_data[0];
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(actual_key + sizeof(PlaintextBlobHeader), key_data, key_size);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlaintextBlobHeader* key_header =
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PlaintextBlobHeader*>(actual_key);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(key_header, 0, sizeof(PlaintextBlobHeader));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_header->hdr.bType = PLAINTEXTKEYBLOB;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_header->hdr.bVersion = CUR_BLOB_VERSION;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_header->hdr.aiKeyAlg = alg;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key_header->cbKeySize = static_cast<DWORD>(key_size);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HCRYPTKEY unsafe_key = NULL;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD flags = CRYPT_EXPORTABLE;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alg == CALG_HMAC) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Though it may appear odd that IPSEC and RC2 are being used, this is
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // done in accordance with Microsoft's FIPS 140-2 Security Policy for the
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // RSA Enhanced Provider, as the approved means of using arbitrary HMAC
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // key material.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_header->hdr.aiKeyAlg = CALG_RC2;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    flags |= CRYPT_IPSEC_HMAC_KEY;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok =
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CryptImportKey(provider, actual_key, actual_size, 0, flags, &unsafe_key);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clean up the temporary copy of key, regardless of whether it was imported
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sucessfully or not.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecureZeroMemory(actual_key, actual_size);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key->reset(unsafe_key);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to generate a random AES key of |key_size_in_bits|. Returns true
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// if generation is successful, storing the generated key in |*key| and the
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// key provider (CSP) in |*provider|.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GenerateAESKey(size_t key_size_in_bits,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ScopedHCRYPTPROV* provider,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ScopedHCRYPTKEY* key) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(provider);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ALG_ID alg = GetAESAlgIDForKeySize(key_size_in_bits);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (alg == 0)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTPROV safe_provider;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: The only time NULL is safe to be passed as pszContainer is when
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dwFlags contains CRYPT_VERIFYCONTEXT, as all keys generated and/or used
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will be treated as ephemeral keys and not persisted.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptAcquireContext(safe_provider.receive(), NULL, NULL,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY safe_key;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the FIPS 140-2 Security Policy for CAPI on XP/Vista+, Microsoft notes
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that CryptGenKey makes use of the same functionality exposed via
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CryptGenRandom. The reason this is being used, as opposed to
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CryptGenRandom and CryptImportKey is for compliance with the security
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // policy
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptGenKey(safe_provider.get(), alg, CRYPT_EXPORTABLE,
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   safe_key.receive());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key->swap(safe_key);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->swap(safe_provider);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the HMAC key size meets the requirement of FIPS 198
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Section 3.  |alg| is the hash function used in the HMAC.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CheckHMACKeySize(size_t key_size_in_bits, ALG_ID alg) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD hash_size = 0;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (alg) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CALG_SHA1:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash_size = 20;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CALG_SHA_256:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash_size = 32;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CALG_SHA_384:
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash_size = 48;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CALG_SHA_512:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hash_size = 64;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hash_size == 0)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An HMAC key must be >= L/2, where L is the output size of the hash
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // function being used.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (key_size_in_bits >= (hash_size / 2 * 8) &&
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (key_size_in_bits % 8) == 0);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to generate a random, |key_size_in_bits|-long HMAC key, for use
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with the hash function |alg|.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |key_size_in_bits| must be >= 1/2 the hash size of |alg| for security.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if generation is successful, storing the generated key in
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |*key| and the key provider (CSP) in |*provider|.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GenerateHMACKey(size_t key_size_in_bits,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     ALG_ID alg,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     ScopedHCRYPTPROV* provider,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     ScopedHCRYPTKEY* key,
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     scoped_ptr<BYTE[]>* raw_key) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(provider);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(key);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(raw_key);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CheckHMACKeySize(key_size_in_bits, alg))
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTPROV safe_provider;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comment in GenerateAESKey as to why NULL is acceptable for the
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // container name.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptAcquireContext(safe_provider.receive(), NULL, NULL,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD key_size_in_bytes = static_cast<DWORD>(key_size_in_bits / 8);
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<BYTE[]> random(new BYTE[key_size_in_bytes]);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptGenRandom(safe_provider, key_size_in_bytes, random.get());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY safe_key;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool rv = ImportRawKey(safe_provider, CALG_HMAC, random.get(),
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         key_size_in_bytes, &safe_key);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key->swap(safe_key);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider->swap(safe_provider);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raw_key->swap(random);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecureZeroMemory(random.get(), key_size_in_bytes);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Attempts to create an HMAC hash instance using the specified |provider|
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and |key|. The inner hash function will be |hash_alg|. If successful,
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returns true and stores the hash in |*hash|.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(wtc): use this function in hmac_win.cc.
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateHMACHash(HCRYPTPROV provider,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    HCRYPTKEY key,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ALG_ID hash_alg,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    ScopedHCRYPTHASH* hash) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTHASH safe_hash;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptCreateHash(provider, CALG_HMAC, key, 0, safe_hash.receive());
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMAC_INFO hmac_info;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&hmac_info, 0, sizeof(hmac_info));
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hmac_info.HashAlgid = hash_alg;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptSetHashParam(safe_hash, HP_HMAC_INFO,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<const BYTE*>(&hmac_info), 0);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  hash->swap(safe_hash);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Computes a block of the derived key using the PBKDF2 function F for the
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified |block_index| using the PRF |hash|, writing the output to
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |output_buf|.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |output_buf| must have enough space to accomodate the output of the PRF
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specified by |hash|.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if the block was successfully computed.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ComputePBKDF2Block(HCRYPTHASH hash,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        DWORD hash_size,
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const std::string& salt,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        size_t iterations,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        uint32 block_index,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        BYTE* output_buf) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // From RFC 2898:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. <snip> The function F is defined as the exclusive-or sum of the first
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    c iterates of the underlying pseudorandom function PRF applied to the
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    password P and the concatenation of the salt S and the block index i:
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    where
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      U_1 = PRF(P, S || INT (i))
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      U_2 = PRF(P, U_1)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      ...
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //      U_c = PRF(P, U_{c-1})
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTHASH safe_hash;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptDuplicateHash(hash, NULL, 0, safe_hash.receive());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iteration U_1: Compute PRF for S.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptHashData(safe_hash, reinterpret_cast<const BYTE*>(salt.data()),
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     static_cast<DWORD>(salt.size()), 0);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iteration U_1: and append (big-endian) INT (i).
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 big_endian_block_index = base::HostToNet32(block_index);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptHashData(safe_hash,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     reinterpret_cast<BYTE*>(&big_endian_block_index),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     sizeof(big_endian_block_index), 0);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BYTE> hash_value(hash_size);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD size = hash_size;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptGetHashParam(safe_hash, HP_HASHVAL, &hash_value[0], &size, 0);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok  || size != hash_size)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(output_buf, &hash_value[0], hash_size);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iteration 2 - c: Compute U_{iteration} by applying the PRF to
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // U_{iteration - 1}, then xor the resultant hash with |output|, which
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contains U_1 ^ U_2 ^ ... ^ U_{iteration - 1}.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t iteration = 2; iteration <= iterations; ++iteration) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    safe_hash.reset();
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = CryptDuplicateHash(hash, NULL, 0, safe_hash.receive());
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ok)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = CryptHashData(safe_hash, &hash_value[0], hash_size, 0);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ok)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size = hash_size;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ok = CryptGetHashParam(safe_hash, HP_HASHVAL, &hash_value[0], &size, 0);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ok || size != hash_size)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < hash_size; ++i)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      output_buf[i] ^= hash_value[i];
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey::~SymmetricKey() {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(wtc): create a "secure" string type that zeroes itself in the
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // destructor.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!raw_key_.empty())
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecureZeroMemory(const_cast<char *>(raw_key_.data()), raw_key_.size());
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              size_t key_size_in_bits) {
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(key_size_in_bits, 8);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTPROV provider;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY key;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = false;
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<BYTE[]> raw_key;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (algorithm) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case AES:
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = GenerateAESKey(key_size_in_bits, &provider, &key);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HMAC_SHA1:
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ok = GenerateHMACKey(key_size_in_bits, CALG_SHA1, &provider,
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &key, &raw_key);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok) {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t key_size_in_bytes = key_size_in_bits / 8;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (raw_key == NULL)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key_size_in_bytes = 0;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SymmetricKey* result = new SymmetricKey(provider.release(),
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          key.release(),
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          raw_key.get(),
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          key_size_in_bytes);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (raw_key != NULL)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SecureZeroMemory(raw_key.get(), key_size_in_bytes);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const std::string& password,
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  const std::string& salt,
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  size_t iterations,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  size_t key_size_in_bits) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CryptoAPI lacks routines to perform PBKDF2 derivation as specified
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in RFC 2898, so it must be manually implemented. Only HMAC-SHA1 is
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // supported as the PRF.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // While not used until the end, sanity-check the input before proceeding
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with the expensive computation.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD provider_type = 0;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ALG_ID alg = 0;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (algorithm) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case AES:
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provider_type = PROV_RSA_AES;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alg = GetAESAlgIDForKeySize(key_size_in_bits);
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HMAC_SHA1:
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provider_type = PROV_RSA_FULL;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alg = CALG_HMAC;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provider_type == 0 || alg == 0)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTPROV provider;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptAcquireContext(provider.receive(), NULL, NULL, provider_type,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                CRYPT_VERIFYCONTEXT);
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert the user password into a key suitable to be fed into the PRF
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // function.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY password_as_key;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BYTE* password_as_bytes =
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const_cast<BYTE*>(reinterpret_cast<const BYTE*>(password.data()));
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ImportRawKey(provider, CALG_HMAC, password_as_bytes,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    password.size(), &password_as_key))
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Configure the PRF function. Only HMAC variants are supported, with the
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only hash function supported being SHA1.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rsleevi): Support SHA-256 on XP SP3+.
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTHASH prf;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateHMACHash(provider, password_as_key, CALG_SHA1, &prf))
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD hLen = 0;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD param_size = sizeof(hLen);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptGetHashParam(prf, HP_HASHSIZE,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         reinterpret_cast<BYTE*>(&hLen), &param_size, 0);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok || hLen == 0)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and stop.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t dkLen = key_size_in_bits / 8;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(dkLen, 0);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((dkLen / hLen) > 0xFFFFFFFF) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "Derived key too long.";
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2. Let l be the number of hLen-octet blocks in the derived key,
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    rounding up, and let r be the number of octets in the last
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    block:
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t L = (dkLen + hLen - 1) / hLen;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(L, 0);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t total_generated_size = L * hLen;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BYTE> generated_key(total_generated_size);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BYTE* block_offset = &generated_key[0];
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. For each block of the derived key apply the function F defined below
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    to the password P, the salt S, the iteration count c, and the block
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    index to compute the block:
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    T_1 = F (P, S, c, 1)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    T_2 = F (P, S, c, 2)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    ...
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    T_l = F (P, S, c, l)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // <snip>
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 4. Concatenate the blocks and extract the first dkLen octets to produce
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    a derived key DK:
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    DK = T_1 || T_2 || ... || T_l<0..r-1>
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (uint32 block_index = 1; block_index <= L; ++block_index) {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ComputePBKDF2Block(prf, hLen, salt, iterations, block_index,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            block_offset))
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return NULL;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    block_offset += hLen;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert the derived key bytes into a key handle for the desired algorithm.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY key;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ImportRawKey(provider, alg, &generated_key[0], dkLen, &key))
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SymmetricKey* result = new SymmetricKey(provider.release(), key.release(),
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          &generated_key[0], dkLen);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecureZeroMemory(&generated_key[0], total_generated_size);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const std::string& raw_key) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD provider_type = 0;
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ALG_ID alg = 0;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (algorithm) {
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case AES:
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provider_type = PROV_RSA_AES;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alg = GetAESAlgIDForKeySize(raw_key.size() * 8);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case HMAC_SHA1:
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provider_type = PROV_RSA_FULL;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      alg = CALG_HMAC;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provider_type == 0 || alg == 0)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTPROV provider;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptAcquireContext(provider.receive(), NULL, NULL, provider_type,
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                CRYPT_VERIFYCONTEXT);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedHCRYPTKEY key;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ImportRawKey(provider, alg, raw_key.data(), raw_key.size(), &key))
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new SymmetricKey(provider.release(), key.release(),
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          raw_key.data(), raw_key.size());
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SymmetricKey::GetRawKey(std::string* raw_key) {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Short circuit for when the key was supplied to the constructor.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!raw_key_.empty()) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *raw_key = raw_key_;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD size = 0;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ok = CryptExportKey(key_, 0, PLAINTEXTKEYBLOB, 0, NULL, &size);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<BYTE> result(size);
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CryptExportKey(key_, 0, PLAINTEXTKEYBLOB, 0, &result[0], &size);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ok)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PlaintextBlobHeader* header =
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PlaintextBlobHeader*>(&result[0]);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  raw_key->assign(reinterpret_cast<char*>(&result[sizeof(*header)]),
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  header->cbKeySize);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SecureZeroMemory(&result[0], size);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SymmetricKey::SymmetricKey(HCRYPTPROV provider,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           HCRYPTKEY key,
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const void* key_data, size_t key_size_in_bytes)
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : provider_(provider), key_(key) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key_data) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raw_key_.assign(reinterpret_cast<const char*>(key_data),
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    key_size_in_bytes);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
537