|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include <windows.h> |
|
6 #include <wincrypt.h> |
|
7 #include "pathhash.h" |
|
8 |
|
9 |
|
10 /** |
|
11 * Converts a binary sequence into a hex string |
|
12 * |
|
13 * @param hash The binary data sequence |
|
14 * @param hashSize The size of the binary data sequence |
|
15 * @param hexString A buffer to store the hex string, must be of |
|
16 * size 2 * @hashSize |
|
17 */ |
|
18 static void |
|
19 BinaryDataToHexString(const BYTE *hash, DWORD &hashSize, |
|
20 LPWSTR hexString) |
|
21 { |
|
22 WCHAR *p = hexString; |
|
23 for (DWORD i = 0; i < hashSize; ++i) { |
|
24 wsprintfW(p, L"%.2x", hash[i]); |
|
25 p += 2; |
|
26 } |
|
27 } |
|
28 |
|
29 /** |
|
30 * Calculates an MD5 hash for the given input binary data |
|
31 * |
|
32 * @param data Any sequence of bytes |
|
33 * @param dataSize The number of bytes inside @data |
|
34 * @param hash Output buffer to store hash, must be freed by the caller |
|
35 * @param hashSize The number of bytes in the output buffer |
|
36 * @return TRUE on success |
|
37 */ |
|
38 static BOOL |
|
39 CalculateMD5(const char *data, DWORD dataSize, |
|
40 BYTE **hash, DWORD &hashSize) |
|
41 { |
|
42 HCRYPTPROV hProv = 0; |
|
43 HCRYPTHASH hHash = 0; |
|
44 |
|
45 if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, |
|
46 CRYPT_VERIFYCONTEXT)) { |
|
47 if (NTE_BAD_KEYSET != GetLastError()) { |
|
48 return FALSE; |
|
49 } |
|
50 |
|
51 // Maybe it doesn't exist, try to create it. |
|
52 if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, |
|
53 CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)) { |
|
54 return FALSE; |
|
55 } |
|
56 } |
|
57 |
|
58 if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { |
|
59 return FALSE; |
|
60 } |
|
61 |
|
62 if (!CryptHashData(hHash, reinterpret_cast<const BYTE*>(data), |
|
63 dataSize, 0)) { |
|
64 return FALSE; |
|
65 } |
|
66 |
|
67 DWORD dwCount = sizeof(DWORD); |
|
68 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&hashSize, |
|
69 &dwCount, 0)) { |
|
70 return FALSE; |
|
71 } |
|
72 |
|
73 *hash = new BYTE[hashSize]; |
|
74 ZeroMemory(*hash, hashSize); |
|
75 if (!CryptGetHashParam(hHash, HP_HASHVAL, *hash, &hashSize, 0)) { |
|
76 return FALSE; |
|
77 } |
|
78 |
|
79 if (hHash) { |
|
80 CryptDestroyHash(hHash); |
|
81 } |
|
82 |
|
83 if (hProv) { |
|
84 CryptReleaseContext(hProv,0); |
|
85 } |
|
86 |
|
87 return TRUE; |
|
88 } |
|
89 |
|
90 /** |
|
91 * Converts a file path into a unique registry location for cert storage |
|
92 * |
|
93 * @param filePath The input file path to get a registry path from |
|
94 * @param registryPath A buffer to write the registry path to, must |
|
95 * be of size in WCHARs MAX_PATH + 1 |
|
96 * @return TRUE if successful |
|
97 */ |
|
98 BOOL |
|
99 CalculateRegistryPathFromFilePath(const LPCWSTR filePath, |
|
100 LPWSTR registryPath) |
|
101 { |
|
102 size_t filePathLen = wcslen(filePath); |
|
103 if (!filePathLen) { |
|
104 return FALSE; |
|
105 } |
|
106 |
|
107 // If the file path ends in a slash, ignore that character |
|
108 if (filePath[filePathLen -1] == L'\\' || |
|
109 filePath[filePathLen - 1] == L'/') { |
|
110 filePathLen--; |
|
111 } |
|
112 |
|
113 // Copy in the full path into our own buffer. |
|
114 // Copying in the extra slash is OK because we calculate the hash |
|
115 // based on the filePathLen which excludes the slash. |
|
116 // +2 to account for the possibly trailing slash and the null terminator. |
|
117 WCHAR *lowercasePath = new WCHAR[filePathLen + 2]; |
|
118 memset(lowercasePath, 0, (filePathLen + 2) * sizeof(WCHAR)); |
|
119 wcsncpy(lowercasePath, filePath, filePathLen + 1); |
|
120 _wcslwr(lowercasePath); |
|
121 |
|
122 BYTE *hash; |
|
123 DWORD hashSize = 0; |
|
124 if (!CalculateMD5(reinterpret_cast<const char*>(lowercasePath), |
|
125 filePathLen * 2, |
|
126 &hash, hashSize)) { |
|
127 delete[] lowercasePath; |
|
128 return FALSE; |
|
129 } |
|
130 delete[] lowercasePath; |
|
131 |
|
132 LPCWSTR baseRegPath = L"SOFTWARE\\Mozilla\\" |
|
133 L"MaintenanceService\\"; |
|
134 wcsncpy(registryPath, baseRegPath, MAX_PATH); |
|
135 BinaryDataToHexString(hash, hashSize, |
|
136 registryPath + wcslen(baseRegPath)); |
|
137 delete[] hash; |
|
138 return TRUE; |
|
139 } |