Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2921)

Unified Diff: base/crypto/symmetric_key_win.cc

Issue 6805019: Move crypto files out of base, to a top level directory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/crypto/symmetric_key_win.cc
===================================================================
--- base/crypto/symmetric_key_win.cc (revision 80572)
+++ base/crypto/symmetric_key_win.cc (working copy)
@@ -1,536 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/crypto/symmetric_key.h"
-
-#include <winsock2.h> // For htonl.
-
-#include <vector>
-
-// TODO(wtc): replace scoped_array by std::vector.
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-
-namespace {
-
-// The following is a non-public Microsoft header documented in MSDN under
-// CryptImportKey / CryptExportKey. Following the header is the byte array of
-// the actual plaintext key.
-struct PlaintextBlobHeader {
- BLOBHEADER hdr;
- DWORD cbKeySize;
-};
-
-// CryptoAPI makes use of three distinct ALG_IDs for AES, rather than just
-// CALG_AES (which exists, but depending on the functions you are calling, may
-// result in function failure, whereas the subtype would succeed).
-ALG_ID GetAESAlgIDForKeySize(size_t key_size_in_bits) {
- // Only AES-128/-192/-256 is supported in CryptoAPI.
- switch (key_size_in_bits) {
- case 128:
- return CALG_AES_128;
- case 192:
- return CALG_AES_192;
- case 256:
- return CALG_AES_256;
- default:
- NOTREACHED();
- return 0;
- }
-};
-
-// Imports a raw/plaintext key of |key_size| stored in |*key_data| into a new
-// key created for the specified |provider|. |alg| contains the algorithm of
-// the key being imported.
-// If |key_data| is intended to be used as an HMAC key, then |alg| should be
-// CALG_HMAC.
-// If successful, returns true and stores the imported key in |*key|.
-// TODO(wtc): use this function in hmac_win.cc.
-bool ImportRawKey(HCRYPTPROV provider,
- ALG_ID alg,
- const void* key_data, DWORD key_size,
- ScopedHCRYPTKEY* key) {
- DCHECK_GT(key_size, 0);
-
- DWORD actual_size = sizeof(PlaintextBlobHeader) + key_size;
- std::vector<BYTE> tmp_data(actual_size);
- BYTE* actual_key = &tmp_data[0];
- memcpy(actual_key + sizeof(PlaintextBlobHeader), key_data, key_size);
- PlaintextBlobHeader* key_header =
- reinterpret_cast<PlaintextBlobHeader*>(actual_key);
- memset(key_header, 0, sizeof(PlaintextBlobHeader));
-
- key_header->hdr.bType = PLAINTEXTKEYBLOB;
- key_header->hdr.bVersion = CUR_BLOB_VERSION;
- key_header->hdr.aiKeyAlg = alg;
-
- key_header->cbKeySize = key_size;
-
- HCRYPTKEY unsafe_key = NULL;
- DWORD flags = CRYPT_EXPORTABLE;
- if (alg == CALG_HMAC) {
- // Though it may appear odd that IPSEC and RC2 are being used, this is
- // done in accordance with Microsoft's FIPS 140-2 Security Policy for the
- // RSA Enhanced Provider, as the approved means of using arbitrary HMAC
- // key material.
- key_header->hdr.aiKeyAlg = CALG_RC2;
- flags |= CRYPT_IPSEC_HMAC_KEY;
- }
-
- BOOL ok =
- CryptImportKey(provider, actual_key, actual_size, 0, flags, &unsafe_key);
-
- // Clean up the temporary copy of key, regardless of whether it was imported
- // sucessfully or not.
- SecureZeroMemory(actual_key, actual_size);
-
- if (!ok)
- return false;
-
- key->reset(unsafe_key);
- return true;
-}
-
-// Attempts to generate a random AES key of |key_size_in_bits|. Returns true
-// if generation is successful, storing the generated key in |*key| and the
-// key provider (CSP) in |*provider|.
-bool GenerateAESKey(size_t key_size_in_bits,
- ScopedHCRYPTPROV* provider,
- ScopedHCRYPTKEY* key) {
- DCHECK(provider);
- DCHECK(key);
-
- ALG_ID alg = GetAESAlgIDForKeySize(key_size_in_bits);
- if (alg == 0)
- return false;
-
- ScopedHCRYPTPROV safe_provider;
- // Note: The only time NULL is safe to be passed as pszContainer is when
- // dwFlags contains CRYPT_VERIFYCONTEXT, as all keys generated and/or used
- // will be treated as ephemeral keys and not persisted.
- BOOL ok = CryptAcquireContext(safe_provider.receive(), NULL, NULL,
- PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
- if (!ok)
- return false;
-
- ScopedHCRYPTKEY safe_key;
- // In the FIPS 140-2 Security Policy for CAPI on XP/Vista+, Microsoft notes
- // that CryptGenKey makes use of the same functionality exposed via
- // CryptGenRandom. The reason this is being used, as opposed to
- // CryptGenRandom and CryptImportKey is for compliance with the security
- // policy
- ok = CryptGenKey(safe_provider.get(), alg, CRYPT_EXPORTABLE,
- safe_key.receive());
- if (!ok)
- return false;
-
- key->swap(safe_key);
- provider->swap(safe_provider);
-
- return true;
-}
-
-// Returns true if the HMAC key size meets the requirement of FIPS 198
-// Section 3. |alg| is the hash function used in the HMAC.
-bool CheckHMACKeySize(size_t key_size_in_bits, ALG_ID alg) {
- DWORD hash_size = 0;
- switch (alg) {
- case CALG_SHA1:
- hash_size = 20;
- break;
- case CALG_SHA_256:
- hash_size = 32;
- break;
- case CALG_SHA_384:
- hash_size = 48;
- break;
- case CALG_SHA_512:
- hash_size = 64;
- break;
- }
- if (hash_size == 0)
- return false;
-
- // An HMAC key must be >= L/2, where L is the output size of the hash
- // function being used.
- return (key_size_in_bits >= (hash_size / 2 * 8) &&
- (key_size_in_bits % 8) == 0);
-}
-
-// Attempts to generate a random, |key_size_in_bits|-long HMAC key, for use
-// with the hash function |alg|.
-// |key_size_in_bits| must be >= 1/2 the hash size of |alg| for security.
-// Returns true if generation is successful, storing the generated key in
-// |*key| and the key provider (CSP) in |*provider|.
-bool GenerateHMACKey(size_t key_size_in_bits,
- ALG_ID alg,
- ScopedHCRYPTPROV* provider,
- ScopedHCRYPTKEY* key,
- scoped_array<BYTE>* raw_key) {
- DCHECK(provider);
- DCHECK(key);
- DCHECK(raw_key);
-
- if (!CheckHMACKeySize(key_size_in_bits, alg))
- return false;
-
- ScopedHCRYPTPROV safe_provider;
- // See comment in GenerateAESKey as to why NULL is acceptable for the
- // container name.
- BOOL ok = CryptAcquireContext(safe_provider.receive(), NULL, NULL,
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
- if (!ok)
- return false;
-
- DWORD key_size_in_bytes = key_size_in_bits / 8;
- scoped_array<BYTE> random(new BYTE[key_size_in_bytes]);
- ok = CryptGenRandom(safe_provider, key_size_in_bytes, random.get());
- if (!ok)
- return false;
-
- ScopedHCRYPTKEY safe_key;
- bool rv = ImportRawKey(safe_provider, CALG_HMAC, random.get(),
- key_size_in_bytes, &safe_key);
- if (rv) {
- key->swap(safe_key);
- provider->swap(safe_provider);
- raw_key->swap(random);
- }
-
- SecureZeroMemory(random.get(), key_size_in_bytes);
- return rv;
-}
-
-// Attempts to create an HMAC hash instance using the specified |provider|
-// and |key|. The inner hash function will be |hash_alg|. If successful,
-// returns true and stores the hash in |*hash|.
-// TODO(wtc): use this function in hmac_win.cc.
-bool CreateHMACHash(HCRYPTPROV provider,
- HCRYPTKEY key,
- ALG_ID hash_alg,
- ScopedHCRYPTHASH* hash) {
- ScopedHCRYPTHASH safe_hash;
- BOOL ok = CryptCreateHash(provider, CALG_HMAC, key, 0, safe_hash.receive());
- if (!ok)
- return false;
-
- HMAC_INFO hmac_info;
- memset(&hmac_info, 0, sizeof(hmac_info));
- hmac_info.HashAlgid = hash_alg;
-
- ok = CryptSetHashParam(safe_hash, HP_HMAC_INFO,
- reinterpret_cast<const BYTE*>(&hmac_info), 0);
- if (!ok)
- return false;
-
- hash->swap(safe_hash);
- return true;
-}
-
-// Computes a block of the derived key using the PBKDF2 function F for the
-// specified |block_index| using the PRF |hash|, writing the output to
-// |output_buf|.
-// |output_buf| must have enough space to accomodate the output of the PRF
-// specified by |hash|.
-// Returns true if the block was successfully computed.
-bool ComputePBKDF2Block(HCRYPTHASH hash,
- DWORD hash_size,
- const std::string& salt,
- size_t iterations,
- uint32 block_index,
- BYTE* output_buf) {
- // From RFC 2898:
- // 3. <snip> The function F is defined as the exclusive-or sum of the first
- // c iterates of the underlying pseudorandom function PRF applied to the
- // password P and the concatenation of the salt S and the block index i:
- // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
- // where
- // U_1 = PRF(P, S || INT (i))
- // U_2 = PRF(P, U_1)
- // ...
- // U_c = PRF(P, U_{c-1})
- ScopedHCRYPTHASH safe_hash;
- BOOL ok = CryptDuplicateHash(hash, NULL, 0, safe_hash.receive());
- if (!ok)
- return false;
-
- // Iteration U_1: Compute PRF for S.
- ok = CryptHashData(safe_hash, reinterpret_cast<const BYTE*>(salt.data()),
- salt.size(), 0);
- if (!ok)
- return false;
-
- // Iteration U_1: and append (big-endian) INT (i).
- uint32 big_endian_block_index = htonl(block_index);
- ok = CryptHashData(safe_hash,
- reinterpret_cast<BYTE*>(&big_endian_block_index),
- sizeof(big_endian_block_index), 0);
-
- std::vector<BYTE> hash_value(hash_size);
-
- DWORD size = hash_size;
- ok = CryptGetHashParam(safe_hash, HP_HASHVAL, &hash_value[0], &size, 0);
- if (!ok || size != hash_size)
- return false;
-
- memcpy(output_buf, &hash_value[0], hash_size);
-
- // Iteration 2 - c: Compute U_{iteration} by applying the PRF to
- // U_{iteration - 1}, then xor the resultant hash with |output|, which
- // contains U_1 ^ U_2 ^ ... ^ U_{iteration - 1}.
- for (size_t iteration = 2; iteration <= iterations; ++iteration) {
- safe_hash.reset();
- ok = CryptDuplicateHash(hash, NULL, 0, safe_hash.receive());
- if (!ok)
- return false;
-
- ok = CryptHashData(safe_hash, &hash_value[0], hash_size, 0);
- if (!ok)
- return false;
-
- size = hash_size;
- ok = CryptGetHashParam(safe_hash, HP_HASHVAL, &hash_value[0], &size, 0);
- if (!ok || size != hash_size)
- return false;
-
- for (int i = 0; i < hash_size; ++i)
- output_buf[i] ^= hash_value[i];
- }
-
- return true;
-}
-
-} // namespace
-
-SymmetricKey::~SymmetricKey() {
- // TODO(wtc): create a "secure" string type that zeroes itself in the
- // destructor.
- if (!raw_key_.empty())
- SecureZeroMemory(const_cast<char *>(raw_key_.data()), raw_key_.size());
-}
-
-// static
-SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm,
- size_t key_size_in_bits) {
- DCHECK_GE(key_size_in_bits, 8);
-
- ScopedHCRYPTPROV provider;
- ScopedHCRYPTKEY key;
-
- bool ok = false;
- scoped_array<BYTE> raw_key;
-
- switch (algorithm) {
- case AES:
- ok = GenerateAESKey(key_size_in_bits, &provider, &key);
- break;
- case HMAC_SHA1:
- ok = GenerateHMACKey(key_size_in_bits, CALG_SHA1, &provider,
- &key, &raw_key);
- break;
- }
-
- if (!ok) {
- NOTREACHED();
- return NULL;
- }
-
- size_t key_size_in_bytes = key_size_in_bits / 8;
- if (raw_key == NULL)
- key_size_in_bytes = 0;
-
- SymmetricKey* result = new SymmetricKey(provider.release(),
- key.release(),
- raw_key.get(),
- key_size_in_bytes);
- if (raw_key != NULL)
- SecureZeroMemory(raw_key.get(), key_size_in_bytes);
-
- return result;
-}
-
-// static
-SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm,
- const std::string& password,
- const std::string& salt,
- size_t iterations,
- size_t key_size_in_bits) {
- // CryptoAPI lacks routines to perform PBKDF2 derivation as specified
- // in RFC 2898, so it must be manually implemented. Only HMAC-SHA1 is
- // supported as the PRF.
-
- // While not used until the end, sanity-check the input before proceeding
- // with the expensive computation.
- DWORD provider_type = 0;
- ALG_ID alg = 0;
- switch (algorithm) {
- case AES:
- provider_type = PROV_RSA_AES;
- alg = GetAESAlgIDForKeySize(key_size_in_bits);
- break;
- case HMAC_SHA1:
- provider_type = PROV_RSA_FULL;
- alg = CALG_HMAC;
- break;
- default:
- NOTREACHED();
- break;
- }
- if (provider_type == 0 || alg == 0)
- return NULL;
-
- ScopedHCRYPTPROV provider;
- BOOL ok = CryptAcquireContext(provider.receive(), NULL, NULL, provider_type,
- CRYPT_VERIFYCONTEXT);
- if (!ok)
- return NULL;
-
- // Convert the user password into a key suitable to be fed into the PRF
- // function.
- ScopedHCRYPTKEY password_as_key;
- BYTE* password_as_bytes =
- const_cast<BYTE*>(reinterpret_cast<const BYTE*>(password.data()));
- if (!ImportRawKey(provider, CALG_HMAC, password_as_bytes,
- password.size(), &password_as_key))
- return NULL;
-
- // Configure the PRF function. Only HMAC variants are supported, with the
- // only hash function supported being SHA1.
- // TODO(rsleevi): Support SHA-256 on XP SP3+.
- ScopedHCRYPTHASH prf;
- if (!CreateHMACHash(provider, password_as_key, CALG_SHA1, &prf))
- return NULL;
-
- DWORD hLen = 0;
- DWORD param_size = sizeof(hLen);
- ok = CryptGetHashParam(prf, HP_HASHSIZE,
- reinterpret_cast<BYTE*>(&hLen), &param_size, 0);
- if (!ok || hLen == 0)
- return NULL;
-
- // 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and stop.
- size_t dkLen = key_size_in_bits / 8;
- DCHECK_GT(dkLen, 0);
-
- if ((dkLen / hLen) > 0xFFFFFFFF) {
- DLOG(ERROR) << "Derived key too long.";
- return NULL;
- }
-
- // 2. Let l be the number of hLen-octet blocks in the derived key,
- // rounding up, and let r be the number of octets in the last
- // block:
- size_t L = (dkLen + hLen - 1) / hLen;
- DCHECK_GT(L, 0);
-
- size_t total_generated_size = L * hLen;
- std::vector<BYTE> generated_key(total_generated_size);
- BYTE* block_offset = &generated_key[0];
-
- // 3. For each block of the derived key apply the function F defined below
- // to the password P, the salt S, the iteration count c, and the block
- // index to compute the block:
- // T_1 = F (P, S, c, 1)
- // T_2 = F (P, S, c, 2)
- // ...
- // T_l = F (P, S, c, l)
- // <snip>
- // 4. Concatenate the blocks and extract the first dkLen octets to produce
- // a derived key DK:
- // DK = T_1 || T_2 || ... || T_l<0..r-1>
- for (uint32 block_index = 1; block_index <= L; ++block_index) {
- if (!ComputePBKDF2Block(prf, hLen, salt, iterations, block_index,
- block_offset))
- return NULL;
- block_offset += hLen;
- }
-
- // Convert the derived key bytes into a key handle for the desired algorithm.
- ScopedHCRYPTKEY key;
- if (!ImportRawKey(provider, alg, &generated_key[0], dkLen, &key))
- return NULL;
-
- SymmetricKey* result = new SymmetricKey(provider.release(), key.release(),
- &generated_key[0], dkLen);
-
- SecureZeroMemory(&generated_key[0], total_generated_size);
-
- return result;
-}
-
-// static
-SymmetricKey* SymmetricKey::Import(Algorithm algorithm,
- const std::string& raw_key) {
- DWORD provider_type = 0;
- ALG_ID alg = 0;
- switch (algorithm) {
- case AES:
- provider_type = PROV_RSA_AES;
- alg = GetAESAlgIDForKeySize(raw_key.size() * 8);
- break;
- case HMAC_SHA1:
- provider_type = PROV_RSA_FULL;
- alg = CALG_HMAC;
- break;
- default:
- NOTREACHED();
- break;
- }
- if (provider_type == 0 || alg == 0)
- return NULL;
-
- ScopedHCRYPTPROV provider;
- BOOL ok = CryptAcquireContext(provider.receive(), NULL, NULL, provider_type,
- CRYPT_VERIFYCONTEXT);
- if (!ok)
- return NULL;
-
- ScopedHCRYPTKEY key;
- if (!ImportRawKey(provider, alg, raw_key.data(), raw_key.size(), &key))
- return NULL;
-
- return new SymmetricKey(provider.release(), key.release(),
- raw_key.data(), raw_key.size());
-}
-
-bool SymmetricKey::GetRawKey(std::string* raw_key) {
- // Short circuit for when the key was supplied to the constructor.
- if (!raw_key_.empty()) {
- *raw_key = raw_key_;
- return true;
- }
-
- DWORD size = 0;
- BOOL ok = CryptExportKey(key_, 0, PLAINTEXTKEYBLOB, 0, NULL, &size);
- if (!ok)
- return false;
-
- std::vector<BYTE> result(size);
-
- ok = CryptExportKey(key_, 0, PLAINTEXTKEYBLOB, 0, &result[0], &size);
- if (!ok)
- return false;
-
- PlaintextBlobHeader* header =
- reinterpret_cast<PlaintextBlobHeader*>(&result[0]);
- raw_key->assign(reinterpret_cast<char*>(&result[sizeof(*header)]),
- header->cbKeySize);
-
- SecureZeroMemory(&result[0], size);
-
- return true;
-}
-
-SymmetricKey::SymmetricKey(HCRYPTPROV provider,
- HCRYPTKEY key,
- const void* key_data, size_t key_size_in_bytes)
- : provider_(provider), key_(key) {
- if (key_data) {
- raw_key_.assign(reinterpret_cast<const char*>(key_data),
- key_size_in_bytes);
- }
-}
-
-} // namespace base
« no previous file with comments | « base/crypto/symmetric_key_unittest.cc ('k') | base/hmac.h » ('j') | base/nss_util.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698