blob: 33ca35409185e3844de5de0b6d9b8371b5a13528 [file] [log] [blame]
/* mz_crypt_winrt.c -- Crypto/hash functions for UWP
part of the minizip-ng project
Copyright (C) 2010-2022 Nathan Moinvaziri
https://github.com/zlib-ng/minizip-ng
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_os.h"
#include "mz_crypt.h"
#include <windows.h>
#include <bcrypt.h>
/***************************************************************************/
#define NT_SUCCESS(status) ((status) >= 0)
/***************************************************************************/
int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
BCRYPT_ALG_HANDLE provider = NULL;
NTSTATUS status = 0;
status = BCryptOpenAlgorithmProvider(&provider, BCRYPT_RNG_ALGORITHM, NULL, 0);
if (NT_SUCCESS(status)) {
status = BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, buf, size, 0);
BCryptCloseAlgorithmProvider(provider, 0);
}
if (NT_SUCCESS(status))
return size;
return mz_os_rand(buf, size);
}
/***************************************************************************/
/* Adapted from RFC4634 and Igor Pavlov's 2010 public domain implementation */
typedef struct mz_crypt_sha224_s {
uint8_t buffer[64];
uint32_t state[8];
uint64_t count;
} mz_crypt_sha224;
/***************************************************************************/
#define rotl(x, n) (((x) << (n)) | ((x) >> ((8 * sizeof(x)) - (n))))
#define rotr(x, n) (((x) >> (n)) | ((x) << ((8 * sizeof(x)) - (n))))
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) ((x & y) | (z & (x | y)))
#define S0_256(x) (rotr(x, 2) ^ rotr(x,13) ^ rotr(x, 22))
#define S1_256(x) (rotr(x, 6) ^ rotr(x,11) ^ rotr(x, 25))
#define s0_256(x) (rotr(x, 7) ^ rotr(x,18) ^ (x >> 3))
#define s1_256(x) (rotr(x,17) ^ rotr(x,19) ^ (x >> 10))
#define blk0(i) (w[i] = buffer[i])
#define blk2(i) (w[i&15] += s1_256(w[(i-2)&15]) + w[(i-7)&15] + s0_256(w[(i-15)&15]))
#define R(a,b,c,d,e,f,g,h,i) \
h += S1_256(e) + Ch(e,f,g) + k256[i+j] + (j?blk2(i):blk0(i)); \
d += h; h += S0_256(a) + Maj(a, b, c)
#define RX_8(i) \
R(a,b,c,d,e,f,g,h, (i)); \
R(h,a,b,c,d,e,f,g, (i+1)); \
R(g,h,a,b,c,d,e,f, (i+2)); \
R(f,g,h,a,b,c,d,e, (i+3)); \
R(e,f,g,h,a,b,c,d, (i+4)); \
R(d,e,f,g,h,a,b,c, (i+5)); \
R(c,d,e,f,g,h,a,b, (i+6)); \
R(b,c,d,e,f,g,h,a, (i+7))
static const uint32_t k256[64] = {
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u,
0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u,
0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu,
0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u,
0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u,
0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u,
0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u,
0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u,
0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u
};
/***************************************************************************/
static void mz_crypt_sha224_init(mz_crypt_sha224 *sha) {
sha->state[0] = 0xc1059ed8u;
sha->state[1] = 0x367cd507u;
sha->state[2] = 0x3070dd17u;
sha->state[3] = 0xf70e5939u;
sha->state[4] = 0xffc00b31u;
sha->state[5] = 0x68581511u;
sha->state[6] = 0x64f98fa7u;
sha->state[7] = 0xbefa4fa4u;
sha->count = 0;
}
static void mz_crypt_sha224_transform(uint32_t *state, const uint32_t *buffer) {
uint32_t w[16];
int32_t j = 0;
uint32_t a = state[0], b = state[1], c = state[2], d = state[3];
uint32_t e = state[4], f = state[5], g = state[6], h = state[7];
for (j = 0; j < 64; j += 16) {
RX_8(0);
RX_8(8);
}
state[0] += a; state[1] += b; state[2] += c; state[3] += d;
state[4] += e; state[5] += f; state[6] += g; state[7] += h;
}
static void mz_crypt_sha224_write_byte_block(mz_crypt_sha224 *sha) {
uint32_t data32[16];
int32_t i = 0;
for (i = 0; i < 16; i++) {
data32[i] = ((uint32_t)(sha->buffer[i * 4 + 0]) << 24) +
((uint32_t)(sha->buffer[i * 4 + 1]) << 16) +
((uint32_t)(sha->buffer[i * 4 + 2]) << 8 ) +
((uint32_t)(sha->buffer[i * 4 + 3]));
}
mz_crypt_sha224_transform(sha->state, data32);
}
static void mz_crypt_sha224_update(mz_crypt_sha224 *sha, const uint8_t *data, size_t size) {
uint32_t pos = (uint32_t)sha->count & 0x3F;
while (size > 0) {
sha->buffer[pos++] = *data++;
sha->count++;
size--;
if (pos == 64) {
pos = 0;
mz_crypt_sha224_write_byte_block(sha);
}
}
}
static void mz_crypt_sha224_end(mz_crypt_sha224 *sha, uint8_t *digest) {
uint64_t bits = (sha->count << 3);
uint32_t pos = (uint32_t)sha->count & 0x3F;
int32_t i = 0;
sha->buffer[pos++] = 0x80;
while (pos != (64 - 8)) {
pos &= 0x3F;
if (pos == 0)
mz_crypt_sha224_write_byte_block(sha);
sha->buffer[pos++] = 0;
}
for (i = 0; i < 8; i++) {
sha->buffer[pos++] = (uint8_t)(bits >> 56);
bits <<= 8;
}
mz_crypt_sha224_write_byte_block(sha);
for (i = 0; i < 7; i++) {
*digest++ = (uint8_t)(sha->state[i] >> 24);
*digest++ = (uint8_t)(sha->state[i] >> 16);
*digest++ = (uint8_t)(sha->state[i] >> 8 );
*digest++ = (uint8_t)(sha->state[i]);
}
mz_crypt_sha224_init(sha);
}
/***************************************************************************/
typedef struct mz_crypt_sha_s {
union {
struct {
BCRYPT_ALG_HANDLE provider;
BCRYPT_HASH_HANDLE hash;
uint8_t *buffer;
};
mz_crypt_sha224 *sha224;
};
int32_t error;
uint16_t algorithm;
} mz_crypt_sha;
/***************************************************************************/
void mz_crypt_sha_reset(void *handle) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
if (sha->algorithm == MZ_HASH_SHA224) {
free(sha->sha224);
sha->sha224 = NULL;
} else {
if (sha->hash)
BCryptDestroyHash(sha->hash);
if (sha->provider)
BCryptCloseAlgorithmProvider(sha->provider, 0);
free(sha->buffer);
sha->hash = NULL;
sha->provider = NULL;
sha->buffer = NULL;
}
sha->error = 0;
}
int32_t mz_crypt_sha_begin(void *handle) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
NTSTATUS status = 0;
const wchar_t *alg_id = BCRYPT_SHA256_ALGORITHM;
ULONG buffer_size = 0;
ULONG result_size = sizeof(buffer_size);
int32_t err = MZ_OK;
if (!sha)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA224) {
sha->sha224 = malloc(sizeof(mz_crypt_sha224));
if (!sha->sha224)
return MZ_MEM_ERROR;
mz_crypt_sha224_init(sha->sha224);
return MZ_OK;
}
switch (sha->algorithm) {
case MZ_HASH_SHA1:
alg_id = BCRYPT_SHA1_ALGORITHM;
break;
case MZ_HASH_SHA384:
alg_id = BCRYPT_SHA384_ALGORITHM;
break;
case MZ_HASH_SHA512:
alg_id = BCRYPT_SHA512_ALGORITHM;
break;
}
status = BCryptOpenAlgorithmProvider(&sha->provider, alg_id, NULL, 0);
if (NT_SUCCESS(status)) {
status = BCryptGetProperty(sha->provider, BCRYPT_OBJECT_LENGTH, (PUCHAR)&buffer_size, result_size, &result_size,
0);
}
if (NT_SUCCESS(status)) {
sha->buffer = malloc(buffer_size);
if (!sha->buffer)
return MZ_MEM_ERROR;
status = BCryptCreateHash(sha->provider, &sha->hash, sha->buffer, buffer_size, NULL, 0, 0);
}
if (!NT_SUCCESS(status)) {
sha->error = status;
err = MZ_HASH_ERROR;
}
return err;
}
int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
NTSTATUS status = 0;
if (!sha || !buf || size < 0)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA224) {
if (!sha->sha224)
return MZ_PARAM_ERROR;
mz_crypt_sha224_update(sha->sha224, buf, size);
return size;
}
if (sha->hash == 0)
return MZ_PARAM_ERROR;
status = BCryptHashData(sha->hash, (uint8_t*)buf, size, 0);
if (!NT_SUCCESS(status)) {
sha->error = status;
return MZ_HASH_ERROR;
}
return size;
}
int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
NTSTATUS status = 0;
ULONG expected_size = 0;
ULONG result_size = sizeof(expected_size);
if (!sha || !digest)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA224) {
if (!sha->sha224 || digest_size < 28)
return MZ_PARAM_ERROR;
mz_crypt_sha224_end(sha->sha224, digest);
return MZ_OK;
}
if (sha->hash == 0)
return MZ_PARAM_ERROR;
status = BCryptGetProperty(sha->hash, BCRYPT_HASH_LENGTH, (PUCHAR)&expected_size, result_size, &result_size, 0);
if (!NT_SUCCESS(status))
return MZ_HASH_ERROR;
if ((int32_t)expected_size > digest_size)
return MZ_BUF_ERROR;
status = BCryptFinishHash(sha->hash, digest, expected_size, 0);
if (!NT_SUCCESS(status)) {
sha->error = status;
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
sha->algorithm = algorithm;
}
void *mz_crypt_sha_create(void **handle) {
mz_crypt_sha *sha = NULL;
sha = (mz_crypt_sha *)malloc(sizeof(mz_crypt_sha));
if (sha) {
memset(sha, 0, sizeof(mz_crypt_sha));
sha->algorithm = MZ_HASH_SHA256;
}
if (handle)
*handle = sha;
return sha;
}
void mz_crypt_sha_delete(void **handle) {
mz_crypt_sha *sha = NULL;
if (!handle)
return;
sha = (mz_crypt_sha *)*handle;
if (sha) {
mz_crypt_sha_reset(*handle);
free(sha);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_aes_s {
BCRYPT_ALG_HANDLE provider;
BCRYPT_KEY_HANDLE key;
uint8_t *key_buffer;
int32_t mode;
int32_t error;
} mz_crypt_aes;
/***************************************************************************/
static void mz_crypt_aes_free(void *handle) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes->key)
BCryptDestroyKey(aes->key);
if (aes->provider)
BCryptCloseAlgorithmProvider(aes->provider, 0);
free(aes->key_buffer);
aes->provider = NULL;
aes->key = NULL;
aes->key_buffer = NULL;
}
void mz_crypt_aes_reset(void *handle) {
mz_crypt_aes_free(handle);
}
int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
ULONG output_size = 0;
NTSTATUS status = 0;
if (!aes || !buf)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
status = BCryptEncrypt(aes->key, buf, size, NULL, NULL, 0, buf, size, &output_size, 0);
if (!NT_SUCCESS(status)) {
aes->error = status;
return MZ_CRYPT_ERROR;
}
return size;
}
int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
ULONG output_size = 0;
NTSTATUS status = 0;
if (!aes || !buf)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
status = BCryptDecrypt(aes->key, buf, size, NULL, NULL, 0, buf, size, &output_size, 0);
if (!NT_SUCCESS(status)) {
aes->error = status;
return MZ_CRYPT_ERROR;
}
return size;
}
static int32_t mz_crypt_aes_set_key(void *handle, const void *key, int32_t key_length) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
BCRYPT_KEY_DATA_BLOB_HEADER *key_blob = NULL;
int32_t key_blob_size = 0;
ULONG key_size;
ULONG result_size = sizeof(key_size);
NTSTATUS status = 0;
int32_t err = MZ_OK;
if (!aes || !key || !key_length)
return MZ_PARAM_ERROR;
mz_crypt_aes_reset(handle);
if (key_length != MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_128) &&
key_length != MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_192) &&
key_length != MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_256)) {
return MZ_PARAM_ERROR;
}
status = BCryptOpenAlgorithmProvider(&aes->provider, BCRYPT_AES_ALGORITHM, NULL, 0);
if (NT_SUCCESS(status)) {
status = BCryptGetProperty(aes->provider, BCRYPT_OBJECT_LENGTH, (PUCHAR)&key_size, result_size, &result_size,
0);
}
if (NT_SUCCESS(status)) {
status = BCryptSetProperty(aes->provider, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC), 0);
}
if (NT_SUCCESS(status)) {
aes->key_buffer = malloc(key_size);
if (!aes->key_buffer)
return MZ_MEM_ERROR;
key_blob_size = sizeof(*key_blob) + key_length;
key_blob = malloc(key_blob_size);
if (key_blob) {
key_blob->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC;
key_blob->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1;
key_blob->cbKeyData = key_length;
memcpy((uint8_t*)key_blob + sizeof(*key_blob), key, key_length);
status = BCryptImportKey(aes->provider, NULL, BCRYPT_KEY_DATA_BLOB, &aes->key, aes->key_buffer, key_size,
(PUCHAR)key_blob, key_blob_size, 0);
SecureZeroMemory(key_blob, key_blob_size);
free(key_blob);
}
}
if (!NT_SUCCESS(status)) {
aes->error = status;
err = MZ_CRYPT_ERROR;
}
return err;
}
int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {
return mz_crypt_aes_set_key(handle, key, key_length);
}
int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {
return mz_crypt_aes_set_key(handle, key, key_length);
}
void mz_crypt_aes_set_mode(void *handle, int32_t mode) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
aes->mode = mode;
}
void *mz_crypt_aes_create(void **handle) {
mz_crypt_aes *aes = NULL;
aes = (mz_crypt_aes *)calloc(1, sizeof(mz_crypt_aes));
if (handle)
*handle = aes;
return aes;
}
void mz_crypt_aes_delete(void **handle) {
mz_crypt_aes *aes = NULL;
if (!handle)
return;
aes = (mz_crypt_aes *)*handle;
if (aes) {
mz_crypt_aes_free(*handle);
free(aes);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_hmac_s {
BCRYPT_ALG_HANDLE provider;
BCRYPT_KEY_HANDLE key;
BCRYPT_HASH_HANDLE hash;
uint8_t *buffer;
int32_t error;
uint16_t algorithm;
} mz_crypt_hmac;
/***************************************************************************/
static void mz_crypt_hmac_free(void *handle) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
if (hmac->hash)
BCryptDestroyHash(hmac->hash);
if (hmac->key)
BCryptDestroyKey(hmac->key);
if (hmac->provider)
BCryptCloseAlgorithmProvider(hmac->provider, 0);
free(hmac->buffer);
hmac->hash = NULL;
hmac->key = NULL;
hmac->provider = NULL;
hmac->buffer = NULL;
}
void mz_crypt_hmac_reset(void *handle) {
mz_crypt_hmac_free(handle);
}
int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
wchar_t *alg_id = BCRYPT_SHA256_ALGORITHM;
ULONG buffer_size = 0;
ULONG result_size = sizeof(buffer_size);
NTSTATUS status = 0;
int32_t err = MZ_OK;
if (!hmac || !key)
return MZ_PARAM_ERROR;
mz_crypt_hmac_reset(handle);
if (hmac->algorithm == MZ_HASH_SHA1)
alg_id = BCRYPT_SHA1_ALGORITHM;
status = BCryptOpenAlgorithmProvider(&hmac->provider, alg_id, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
if (NT_SUCCESS(status)) {
status = BCryptGetProperty(hmac->provider, BCRYPT_OBJECT_LENGTH, (PUCHAR)&buffer_size, result_size,
&result_size, 0);
}
if (NT_SUCCESS(status)) {
hmac->buffer = malloc(buffer_size);
if (!hmac->buffer)
return MZ_MEM_ERROR;
}
if (NT_SUCCESS(status))
status = BCryptCreateHash(hmac->provider, &hmac->hash, hmac->buffer, buffer_size, (PUCHAR)key, key_length, 0);
if (!NT_SUCCESS(status)) {
hmac->error = status;
err = MZ_CRYPT_ERROR;
}
if (err != MZ_OK)
mz_crypt_hmac_free(handle);
return err;
}
int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
NTSTATUS status = 0;
if (!hmac || !buf || !hmac->hash)
return MZ_PARAM_ERROR;
status = BCryptHashData(hmac->hash, (uint8_t*)buf, size, 0);
if (!NT_SUCCESS(status)) {
hmac->error = status;
return MZ_HASH_ERROR;
}
return MZ_OK;
}
int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
NTSTATUS status = 0;
ULONG expected_size = 0;
ULONG result_size = sizeof(expected_size);
if (!hmac || !digest || !hmac->hash)
return MZ_PARAM_ERROR;
status = BCryptGetProperty(hmac->hash, BCRYPT_HASH_LENGTH, (PUCHAR)&expected_size, result_size, &result_size, 0);
if (!NT_SUCCESS(status))
return MZ_HASH_ERROR;
if ((int32_t)expected_size > digest_size)
return MZ_BUF_ERROR;
status = BCryptFinishHash(hmac->hash, digest, expected_size, 0);
if (!NT_SUCCESS(status)) {
hmac->error = status;
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
hmac->algorithm = algorithm;
}
int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {
mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
NTSTATUS status = 0;
int32_t err = MZ_OK;
if (target->hash) {
BCryptDestroyHash(target->hash);
target->hash = NULL;
}
status = BCryptDuplicateHash(source->hash, &target->hash, NULL, 0, 0);
if (!NT_SUCCESS(status)) {
target->error = status;
err = MZ_HASH_ERROR;
}
return err;
}
void *mz_crypt_hmac_create(void **handle) {
mz_crypt_hmac *hmac = NULL;
hmac = (mz_crypt_hmac *)malloc(sizeof(mz_crypt_hmac));
if (hmac) {
memset(hmac, 0, sizeof(mz_crypt_hmac));
hmac->algorithm = MZ_HASH_SHA256;
}
if (handle)
*handle = hmac;
return hmac;
}
void mz_crypt_hmac_delete(void **handle) {
mz_crypt_hmac *hmac = NULL;
if (!handle)
return;
hmac = (mz_crypt_hmac *)*handle;
if (hmac) {
mz_crypt_hmac_free(*handle);
free(hmac);
}
*handle = NULL;
}
/***************************************************************************/
#if defined(MZ_ZIP_SIGNING)
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {
return MZ_SIGN_ERROR;
#if 0
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE private_key = 0;
uint32_t private_key_spec = 0;
BOOL release_private_key = FALSE;
CRYPT_DATA_BLOB cert_data_blob;
PCCERT_CONTEXT cert_context = NULL;
HCERTSTORE cert_store = 0;
BCRYPT_PKCS1_PADDING_INFO pad_info;
wchar_t *password_wide = NULL;
int32_t result = 0;
int32_t err = MZ_OK;
if (!message || !cert_data || !signature || !signature_size)
return MZ_PARAM_ERROR;
*signature = NULL;
*signature_size = 0;
pad_info.pszAlgId = BCRYPT_SHA256_ALGORITHM;
cert_data_blob.pbData = cert_data;
cert_data_blob.cbData = cert_data_size;
password_wide = mz_os_unicode_string_create(cert_pwd, MZ_ENCODING_UTF8);
if (password_wide) {
cert_store = PFXImportCertStore(&cert_data_blob, password_wide, 0);
mz_os_unicode_string_delete(&password_wide);
}
if (!cert_store)
cert_store = PFXImportCertStore(&cert_data_blob, L"", 0);
if (!cert_store)
cert_store = PFXImportCertStore(&cert_data_blob, NULL, 0);
if (!cert_store)
return MZ_PARAM_ERROR;
if (err == MZ_OK) {
cert_context = CertFindCertificateInStore(cert_store,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_HAS_PRIVATE_KEY, NULL, NULL);
if (!cert_context)
err = MZ_PARAM_ERROR;
}
if (err == MZ_OK) {
if (!CryptAcquireCertificatePrivateKey(cert_context, CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, NULL, &private_key,
&private_key_spec, &release_private_key)) {
err = MZ_PARAM_ERROR;
}
}
if (err == MZ_OK) {
#if 0 /* Timestamp support */
CRYPT_ATTR_BLOB crypt_blob;
CRYPT_TIMESTAMP_CONTEXT *ts_context = NULL;
CRYPT_ATTRIBUTE unauth_attribs[1];
wchar_t *timestamp_url_wide = NULL;
const char *timestamp_url = NULL;
if (timestamp_url)
timestamp_url_wide = mz_os_unicode_string_create(timestamp_url);
if (timestamp_url_wide) {
result = CryptRetrieveTimeStamp(timestamp_url_wide,
TIMESTAMP_NO_AUTH_RETRIEVAL | TIMESTAMP_VERIFY_CONTEXT_SIGNATURE, 0, szOID_NIST_sha256,
NULL, message, message_size, &ts_context, NULL, NULL);
mz_os_unicode_string_delete(&timestamp_url_wide);
if (result && ts_context) {
crypt_blob.cbData = ts_context->cbEncoded;
crypt_blob.pbData = ts_context->pbEncoded;
unauth_attribs[0].pszObjId = "1.2.840.113549.1.9.16.2.14"; //id-smime-aa-timeStampToken
unauth_attribs[0].cValue = 1;
unauth_attribs[0].rgValue = &crypt_blob;
sign_params.rgUnauthAttr = &unauth_attribs[0];
sign_params.cUnauthAttr = 1;
}
}
if (ts_context)
CryptMemFree(ts_context);
if (result)
#endif
result = !NCryptSignHash(private_key, &pad_info, message, message_size, NULL, 0, signature_size,
BCRYPT_PAD_PKCS1 | NCRYPT_SILENT_FLAG);
if (result && *signature_size > 0)
*signature = (uint8_t *)malloc(*signature_size);
if (result && *signature) {
result = !NCryptSignHash(private_key, &pad_info, message, message_size, *signature, *signature_size,
signature_size, BCRYPT_PAD_PKCS1 | NCRYPT_SILENT_FLAG);
}
if (release_private_key) {
if (private_key_spec == CERT_NCRYPT_KEY_SPEC)
NCryptFreeObject(private_key);
else
CryptReleaseContext(private_key, 0);
}
if (!result)
err = MZ_SIGN_ERROR;
}
if (cert_context)
CertFreeCertificateContext(cert_context);
if (cert_store)
CertCloseStore(cert_store, 0);
return err;
#endif
}
int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {
return MZ_SIGN_ERROR;
#if 0
CRYPT_VERIFY_MESSAGE_PARA verify_params;
CERT_CONTEXT *signer_cert = NULL;
CERT_CHAIN_PARA chain_para;
CERT_CHAIN_CONTEXT *chain_context = NULL;
CERT_CHAIN_POLICY_PARA chain_policy;
CERT_CHAIN_POLICY_STATUS chain_policy_status;
HCRYPTMSG crypt_msg = 0;
int32_t result = 0;
int32_t err = MZ_SIGN_ERROR;
uint8_t *decoded = NULL;
int32_t decoded_size = 0;
memset(&verify_params, 0, sizeof(verify_params));
verify_params.cbSize = sizeof(verify_params);
verify_params.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
result = CryptVerifyMessageSignature(&verify_params, 0, signature, signature_size,
NULL, (DWORD *)&decoded_size, NULL);
if (result && decoded_size > 0)
decoded = (uint8_t *)malloc(decoded_size);
if (result && decoded)
result = CryptVerifyMessageSignature(&verify_params, 0, signature, signature_size,
decoded, (DWORD *)&decoded_size, (const CERT_CONTEXT **)&signer_cert);
/* Get and validate certificate chain */
memset(&chain_para, 0, sizeof(chain_para));
if (result && signer_cert)
result = CertGetCertificateChain(NULL, signer_cert, NULL, NULL, &chain_para,
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, (const CERT_CHAIN_CONTEXT **)&chain_context);
memset(&chain_policy, 0, sizeof(chain_policy));
chain_policy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
memset(&chain_policy_status, 0, sizeof(chain_policy_status));
chain_policy_status.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);
if (result && chain_context)
result = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain_context,
&chain_policy, &chain_policy_status);
if (chain_policy_status.dwError != S_OK)
result = 0;
#if 0
crypt_msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0, 0, NULL, NULL);
if (crypt_msg) {
/* Timestamp support */
PCRYPT_ATTRIBUTES unauth_attribs = NULL;
HCRYPTMSG ts_msg = 0;
uint8_t *ts_content = NULL;
int32_t ts_content_size = 0;
uint8_t *ts_signature = NULL;
int32_t ts_signature_size = 0;
result = CryptMsgUpdate(crypt_msg, signature, signature_size, 1);
if (result)
CryptMsgGetParam(crypt_msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, NULL, &ts_signature_size);
if (result && ts_signature_size > 0)
ts_signature = (uint8_t *)malloc(ts_signature_size);
if (result && ts_signature) {
result = CryptMsgGetParam(crypt_msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, ts_signature,
&ts_signature_size);
if (result)
{
unauth_attribs = (PCRYPT_ATTRIBUTES)ts_signature;
if ((unauth_attribs->cAttr > 0) && (unauth_attribs->rgAttr[0].cValue > 0))
{
ts_content = unauth_attribs->rgAttr[0].rgValue->pbData;
ts_content_size = unauth_attribs->rgAttr[0].rgValue->cbData;
}
}
if (result && ts_content)
result = CryptVerifyTimeStampSignature(ts_content, ts_content_size, decoded,
decoded_size, 0, &crypt_context, NULL, NULL);
if (result)
err = MZ_OK;
}
if (ts_signature)
free(ts_signature);
if (crypt_context)
CryptMemFree(crypt_context);
} else {
result = 0;
}
#endif
if (result && decoded && decoded_size == message_size) {
/* Verify cms message with our stored message */
if (memcmp(decoded, message, message_size) == 0)
err = MZ_OK;
}
if (chain_context)
CertFreeCertificateChain(chain_context);
if (signer_cert)
CertFreeCertificateContext(signer_cert);
if (crypt_msg)
CryptMsgClose(crypt_msg);
if (decoded)
free(decoded);
return err;
#endif
}
#endif