michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #include "pathhash.h" michael@0: michael@0: michael@0: /** michael@0: * Converts a binary sequence into a hex string michael@0: * michael@0: * @param hash The binary data sequence michael@0: * @param hashSize The size of the binary data sequence michael@0: * @param hexString A buffer to store the hex string, must be of michael@0: * size 2 * @hashSize michael@0: */ michael@0: static void michael@0: BinaryDataToHexString(const BYTE *hash, DWORD &hashSize, michael@0: LPWSTR hexString) michael@0: { michael@0: WCHAR *p = hexString; michael@0: for (DWORD i = 0; i < hashSize; ++i) { michael@0: wsprintfW(p, L"%.2x", hash[i]); michael@0: p += 2; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Calculates an MD5 hash for the given input binary data michael@0: * michael@0: * @param data Any sequence of bytes michael@0: * @param dataSize The number of bytes inside @data michael@0: * @param hash Output buffer to store hash, must be freed by the caller michael@0: * @param hashSize The number of bytes in the output buffer michael@0: * @return TRUE on success michael@0: */ michael@0: static BOOL michael@0: CalculateMD5(const char *data, DWORD dataSize, michael@0: BYTE **hash, DWORD &hashSize) michael@0: { michael@0: HCRYPTPROV hProv = 0; michael@0: HCRYPTHASH hHash = 0; michael@0: michael@0: if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, michael@0: CRYPT_VERIFYCONTEXT)) { michael@0: if (NTE_BAD_KEYSET != GetLastError()) { michael@0: return FALSE; michael@0: } michael@0: michael@0: // Maybe it doesn't exist, try to create it. michael@0: if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, michael@0: CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)) { michael@0: return FALSE; michael@0: } michael@0: } michael@0: michael@0: if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { michael@0: return FALSE; michael@0: } michael@0: michael@0: if (!CryptHashData(hHash, reinterpret_cast(data), michael@0: dataSize, 0)) { michael@0: return FALSE; michael@0: } michael@0: michael@0: DWORD dwCount = sizeof(DWORD); michael@0: if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashSize, michael@0: &dwCount, 0)) { michael@0: return FALSE; michael@0: } michael@0: michael@0: *hash = new BYTE[hashSize]; michael@0: ZeroMemory(*hash, hashSize); michael@0: if (!CryptGetHashParam(hHash, HP_HASHVAL, *hash, &hashSize, 0)) { michael@0: return FALSE; michael@0: } michael@0: michael@0: if (hHash) { michael@0: CryptDestroyHash(hHash); michael@0: } michael@0: michael@0: if (hProv) { michael@0: CryptReleaseContext(hProv,0); michael@0: } michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: /** michael@0: * Converts a file path into a unique registry location for cert storage michael@0: * michael@0: * @param filePath The input file path to get a registry path from michael@0: * @param registryPath A buffer to write the registry path to, must michael@0: * be of size in WCHARs MAX_PATH + 1 michael@0: * @return TRUE if successful michael@0: */ michael@0: BOOL michael@0: CalculateRegistryPathFromFilePath(const LPCWSTR filePath, michael@0: LPWSTR registryPath) michael@0: { michael@0: size_t filePathLen = wcslen(filePath); michael@0: if (!filePathLen) { michael@0: return FALSE; michael@0: } michael@0: michael@0: // If the file path ends in a slash, ignore that character michael@0: if (filePath[filePathLen -1] == L'\\' || michael@0: filePath[filePathLen - 1] == L'/') { michael@0: filePathLen--; michael@0: } michael@0: michael@0: // Copy in the full path into our own buffer. michael@0: // Copying in the extra slash is OK because we calculate the hash michael@0: // based on the filePathLen which excludes the slash. michael@0: // +2 to account for the possibly trailing slash and the null terminator. michael@0: WCHAR *lowercasePath = new WCHAR[filePathLen + 2]; michael@0: memset(lowercasePath, 0, (filePathLen + 2) * sizeof(WCHAR)); michael@0: wcsncpy(lowercasePath, filePath, filePathLen + 1); michael@0: _wcslwr(lowercasePath); michael@0: michael@0: BYTE *hash; michael@0: DWORD hashSize = 0; michael@0: if (!CalculateMD5(reinterpret_cast(lowercasePath), michael@0: filePathLen * 2, michael@0: &hash, hashSize)) { michael@0: delete[] lowercasePath; michael@0: return FALSE; michael@0: } michael@0: delete[] lowercasePath; michael@0: michael@0: LPCWSTR baseRegPath = L"SOFTWARE\\Mozilla\\" michael@0: L"MaintenanceService\\"; michael@0: wcsncpy(registryPath, baseRegPath, MAX_PATH); michael@0: BinaryDataToHexString(hash, hashSize, michael@0: registryPath + wcslen(baseRegPath)); michael@0: delete[] hash; michael@0: return TRUE; michael@0: }