symmetric_key_win.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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), ¶m_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