|
16 | 16 | #include "mongoc-config.h"
|
17 | 17 |
|
18 | 18 | #ifdef MONGOC_ENABLE_CRYPTO_CNG
|
| 19 | +#include "mongoc-scram-private.h" |
19 | 20 | #include "mongoc-crypto-private.h"
|
20 | 21 | #include "mongoc-crypto-cng-private.h"
|
21 | 22 | #include "mongoc-log.h"
|
|
24 | 25 | #include <windows.h>
|
25 | 26 | #include <stdio.h>
|
26 | 27 | #include <bcrypt.h>
|
| 28 | +#include <string.h> |
27 | 29 |
|
28 | 30 | #define NT_SUCCESS(Status) (((NTSTATUS) (Status)) >= 0)
|
29 | 31 | #define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
|
@@ -75,8 +77,8 @@ mongoc_crypto_cng_cleanup (void)
|
75 | 77 | if (_sha256_hash_algo) {
|
76 | 78 | BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0);
|
77 | 79 | }
|
78 |
| - if (_sha256_hash_algo) { |
79 |
| - BCryptCloseAlgorithmProvider (&_sha256_hash_algo, 0); |
| 80 | + if (_sha256_hmac_algo) { |
| 81 | + BCryptCloseAlgorithmProvider (&_sha256_hmac_algo, 0); |
80 | 82 | }
|
81 | 83 | }
|
82 | 84 |
|
@@ -141,6 +143,112 @@ _mongoc_crypto_cng_hmac_or_hash (
|
141 | 143 | return retval;
|
142 | 144 | }
|
143 | 145 |
|
| 146 | +static int |
| 147 | +_crypto_hash_size (mongoc_crypto_t *crypto) |
| 148 | +{ |
| 149 | + if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_1) { |
| 150 | + return MONGOC_SCRAM_SHA_1_HASH_SIZE; |
| 151 | + } else if (crypto->algorithm == MONGOC_CRYPTO_ALGORITHM_SHA_256) { |
| 152 | + return MONGOC_SCRAM_SHA_256_HASH_SIZE; |
| 153 | + } else { |
| 154 | + BSON_UNREACHABLE ("Unexpected crypto algorithm"); |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +#if defined(MONGOC_HAVE_BCRYPT_PBKDF2) |
| 159 | +/* Wrapper for BCryptDeriveKeyPBKDF2 */ |
| 160 | +static bool |
| 161 | +_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE prf, |
| 162 | + const char *password, |
| 163 | + size_t password_len, |
| 164 | + const uint8_t *salt, |
| 165 | + size_t salt_len, |
| 166 | + uint32_t iterations, |
| 167 | + size_t output_len, |
| 168 | + unsigned char *output) |
| 169 | +{ |
| 170 | + // Make non-const versions of password and salt. |
| 171 | + char *password_copy = bson_strndup (password, password_len); |
| 172 | + char *salt_copy = bson_strndup (salt, salt_len); |
| 173 | + |
| 174 | + NTSTATUS status = BCryptDeriveKeyPBKDF2 (prf, |
| 175 | + (unsigned char *) password_copy, |
| 176 | + password_len, |
| 177 | + (unsigned char *) salt_copy, |
| 178 | + salt_len, |
| 179 | + iterations, |
| 180 | + output, |
| 181 | + output_len, |
| 182 | + 0); |
| 183 | + bson_free (password_copy); |
| 184 | + bson_free (salt_copy); |
| 185 | + |
| 186 | + if (!NT_SUCCESS (status)) { |
| 187 | + MONGOC_ERROR ("_bcrypt_derive_key_pbkdf2(): %ld", status); |
| 188 | + return false; |
| 189 | + } |
| 190 | + return true; |
| 191 | +} |
| 192 | + |
| 193 | +#else |
| 194 | +/* Manually salts password if BCryptDeriveKeyPBKDF2 is unavailable */ |
| 195 | +static bool |
| 196 | +_bcrypt_derive_key_pbkdf2 (BCRYPT_ALG_HANDLE algorithm, |
| 197 | + const char *password, |
| 198 | + size_t password_len, |
| 199 | + const uint8_t *salt, |
| 200 | + size_t salt_len, |
| 201 | + uint32_t iterations, |
| 202 | + size_t hash_size, |
| 203 | + unsigned char *output) |
| 204 | +{ |
| 205 | + uint8_t intermediate_digest[MONGOC_SCRAM_HASH_MAX_SIZE]; |
| 206 | + uint8_t start_key[MONGOC_SCRAM_HASH_MAX_SIZE]; |
| 207 | + |
| 208 | + memcpy (start_key, salt, salt_len); |
| 209 | + start_key[salt_len] = 0; |
| 210 | + start_key[salt_len + 1] = 0; |
| 211 | + start_key[salt_len + 2] = 0; |
| 212 | + start_key[salt_len + 3] = 1; |
| 213 | + |
| 214 | + if (!_mongoc_crypto_cng_hmac_or_hash (algorithm, password, password_len, start_key, hash_size, output)) { |
| 215 | + return false; |
| 216 | + } |
| 217 | + memcpy (intermediate_digest, output, hash_size); |
| 218 | + |
| 219 | + for (uint32_t i = 2u; i <= iterations; i++) { |
| 220 | + if (!_mongoc_crypto_cng_hmac_or_hash ( |
| 221 | + algorithm, password, password_len, intermediate_digest, hash_size, output)) { |
| 222 | + return false; |
| 223 | + } |
| 224 | + |
| 225 | + for (int k = 0; k < hash_size; k++) { |
| 226 | + output[k] ^= intermediate_digest[k]; |
| 227 | + } |
| 228 | + } |
| 229 | + return true; |
| 230 | +} |
| 231 | +#endif |
| 232 | + |
| 233 | +bool |
| 234 | +mongoc_crypto_cng_pbkdf2_hmac_sha1 (mongoc_crypto_t *crypto, |
| 235 | + const char *password, |
| 236 | + size_t password_len, |
| 237 | + const uint8_t *salt, |
| 238 | + size_t salt_len, |
| 239 | + uint32_t iterations, |
| 240 | + size_t output_len, |
| 241 | + unsigned char *output) |
| 242 | +{ |
| 243 | +#if defined(MONGOC_HAVE_BCRYPT_PBKDF2) |
| 244 | + return _bcrypt_derive_key_pbkdf2 ( |
| 245 | + _sha1_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output); |
| 246 | +#else |
| 247 | + return _bcrypt_derive_key_pbkdf2 ( |
| 248 | + _sha1_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output); |
| 249 | +#endif |
| 250 | +} |
| 251 | + |
144 | 252 | void
|
145 | 253 | mongoc_crypto_cng_hmac_sha1 (mongoc_crypto_t *crypto,
|
146 | 254 | const void *key,
|
@@ -172,6 +280,25 @@ mongoc_crypto_cng_sha1 (mongoc_crypto_t *crypto,
|
172 | 280 | return res;
|
173 | 281 | }
|
174 | 282 |
|
| 283 | +bool |
| 284 | +mongoc_crypto_cng_pbkdf2_hmac_sha256 (mongoc_crypto_t *crypto, |
| 285 | + const char *password, |
| 286 | + size_t password_len, |
| 287 | + const uint8_t *salt, |
| 288 | + size_t salt_len, |
| 289 | + uint32_t iterations, |
| 290 | + size_t output_len, |
| 291 | + unsigned char *output) |
| 292 | +{ |
| 293 | +#if defined(MONGOC_HAVE_BCRYPT_PBKDF2) |
| 294 | + return _bcrypt_derive_key_pbkdf2 ( |
| 295 | + _sha256_hmac_algo, password, password_len, salt, salt_len, iterations, output_len, output); |
| 296 | +#else |
| 297 | + return _bcrypt_derive_key_pbkdf2 ( |
| 298 | + _sha256_hmac_algo, password, password_len, salt, salt_len, iterations, _crypto_hash_size (crypto), output); |
| 299 | +#endif |
| 300 | +} |
| 301 | + |
175 | 302 | void
|
176 | 303 | mongoc_crypto_cng_hmac_sha256 (mongoc_crypto_t *crypto,
|
177 | 304 | const void *key,
|
|
0 commit comments