| // bcrypt-test.cpp : This file contains the 'main' function. Program execution begins and ends there. | |
| // | |
| #include <wincompat.h> | |
| #include <bcrypt.h> | |
| #include <stdio.h> | |
| #include "picotls/ptlsbcrypt.h" | |
| #include "picotls/minicrypto.h" | |
| int KeyInit(BCRYPT_KEY_HANDLE *hKey, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz, const BYTE *proposedKey, | |
| DWORD proposedKeyLength, BYTE **ko, ULONG *ko_length) | |
| { | |
| DWORD cbData = 0; | |
| HANDLE hAlgo = NULL; | |
| // Open an algorithm handle. | |
| NTSTATUS ret = BCryptOpenAlgorithmProvider(&hAlgo, name, NULL, 0); | |
| if (BCRYPT_SUCCESS(ret)) { | |
| // Set the properties to define the chaining mode | |
| ret = BCryptSetProperty(hAlgo, BCRYPT_CHAINING_MODE, (PBYTE)chain_mode, (ULONG)chain_mode_sz, 0); | |
| } | |
| *ko = NULL; | |
| *ko_length = 0; | |
| if (BCRYPT_SUCCESS(ret)) { | |
| DWORD ko_size = 0; | |
| ULONG cbResult = 0; | |
| ret = BCryptGetProperty(hAlgo, BCRYPT_OBJECT_LENGTH, (PUCHAR)&ko_size, (ULONG)sizeof(ko_size), &cbResult, 0); | |
| if (BCRYPT_SUCCESS(ret)) { | |
| *ko = (uint8_t *)malloc(ko_size); | |
| if (*ko == NULL) { | |
| ret = STATUS_NO_MEMORY; | |
| } else { | |
| *ko_length = ko_size; | |
| memset(*ko, 0, *ko_length); | |
| } | |
| } | |
| } | |
| if (BCRYPT_SUCCESS(ret)) { | |
| // Generate the key from supplied input key bytes. | |
| ret = BCryptGenerateSymmetricKey(hAlgo, hKey, *ko, *ko_length, (PBYTE)proposedKey, proposedKeyLength, 0); | |
| } else { | |
| if (*ko != NULL) { | |
| free(*ko); | |
| *ko = NULL; | |
| *ko_length = 0; | |
| } | |
| } | |
| if (hAlgo != NULL) { | |
| BCryptCloseAlgorithmProvider(hAlgo, 0); | |
| } | |
| return BCRYPT_SUCCESS(ret) ? 0 : -1; | |
| } | |
| void KeyRelease(BCRYPT_KEY_HANDLE *hKey, BYTE **ko, ULONG *ko_length) | |
| { | |
| BCryptDestroyKey(*hKey); | |
| *hKey = NULL; | |
| if (*ko) { | |
| free(*ko); | |
| } | |
| *ko = NULL; | |
| *ko_length = 0; | |
| } | |
| int EncodeOneShot(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz, BYTE *key, | |
| ULONG key_length, | |
| BYTE* iv, ULONG iv_length, | |
| BYTE *data, ULONG dataLength, uint64_t seq, BYTE *authData, ULONG authDataLength, ULONG authTagLength, | |
| BYTE *encrypted, ULONG encryptedLengthMax, ULONG *encryptedLength) | |
| { | |
| BCRYPT_KEY_HANDLE hKey = NULL; | |
| BYTE *authTag = encrypted + dataLength; | |
| BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO bacmi; | |
| BYTE iv_nonce[PTLS_MAX_IV_SIZE]; | |
| BYTE *ko = NULL; | |
| ULONG ko_length = 0; | |
| int ret = 0; | |
| *encryptedLength = 0; | |
| if (KeyInit(&hKey, name, chain_mode, chain_mode_sz, key, key_length, &ko, &ko_length) != 0) { | |
| return -1; | |
| } | |
| memset(authTag, 0, authTagLength); | |
| // Set the auth mode info for AEAD | |
| BCRYPT_INIT_AUTH_MODE_INFO(bacmi); | |
| ptls_aead__build_iv(aead, iv_nonce, iv, seq); | |
| bacmi.pbNonce = iv_nonce; | |
| bacmi.cbNonce = iv_length; | |
| bacmi.pbAuthData = authData; | |
| bacmi.cbAuthData = authDataLength; | |
| bacmi.pbTag = authTag; | |
| bacmi.cbTag = authTagLength; | |
| /* All other fields are set to NULL by the INIT macro. */ | |
| /* If called with a NULL pointer for the data block, we will merely compute the block size. */ | |
| DWORD cbCipherText = 0; | |
| NTSTATUS status = BCryptEncrypt(hKey, data, dataLength, &bacmi, NULL, 0, encrypted, encryptedLengthMax, &cbCipherText, 0); | |
| KeyRelease(&hKey, &ko, &ko_length); | |
| if (BCRYPT_SUCCESS(status)) { | |
| *encryptedLength = cbCipherText + authTagLength; | |
| } else { | |
| ret = -1; | |
| } | |
| return ret; | |
| } | |
| int DecodeOneShot(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz, | |
| BYTE *key, ULONG key_length, BYTE * iv, ULONG iv_length, BYTE *encrypted, | |
| ULONG encryptedLength, uint64_t seq, BYTE *authData, ULONG authDataLength, | |
| ULONG authTagLength, BYTE *decrypted, ULONG decryptedLengthMax, ULONG *decryptedLength) | |
| { | |
| BCRYPT_KEY_HANDLE hKey = NULL; | |
| BYTE *authTag = encrypted + (encryptedLength - authTagLength); | |
| BYTE iv_nonce[PTLS_MAX_IV_SIZE]; | |
| BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO bacmi; | |
| BYTE *ko = NULL; | |
| ULONG ko_length = 0; | |
| int ret = 0; | |
| *decryptedLength = 0; | |
| if (KeyInit(&hKey, name, chain_mode, chain_mode_sz, key, key_length, &ko, &ko_length) != 0) { | |
| return -1; | |
| } | |
| // Set the auth mode info for AEAD | |
| BCRYPT_INIT_AUTH_MODE_INFO(bacmi); | |
| ptls_aead__build_iv(aead, iv_nonce, iv, seq); | |
| bacmi.pbNonce = iv_nonce; | |
| bacmi.cbNonce = iv_length; | |
| bacmi.pbAuthData = authData; | |
| bacmi.cbAuthData = authDataLength; | |
| bacmi.pbTag = authTag; | |
| bacmi.cbTag = authTagLength; | |
| /* All other fields are set to NULL by the INIT macro. */ | |
| /* If called with a NULL pointer for the data block, we will merely compute the block size. */ | |
| DWORD cbCipherText = 0; | |
| NTSTATUS status = BCryptDecrypt(hKey, encrypted, encryptedLength - authTagLength, &bacmi, NULL, 0, decrypted, | |
| decryptedLengthMax, &cbCipherText, 0); | |
| KeyRelease(&hKey, &ko, &ko_length); | |
| if (BCRYPT_SUCCESS(status)) { | |
| *decryptedLength = cbCipherText; | |
| } else { | |
| ret = -1; | |
| } | |
| return ret; | |
| } | |
| int test_oneshot(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| BYTE key[32]; | |
| BYTE data[123]; | |
| BYTE iv[PTLS_MAX_IV_SIZE]; | |
| uint64_t nonce; | |
| BYTE authData[9]; | |
| BYTE encrypted[256]; | |
| ULONG encryptedLength; | |
| BYTE decrypted[256]; | |
| ULONG decryptedLength; | |
| ULONG authTagLength = (ULONG)aead->tag_size; | |
| int ret = 0; | |
| assert(sizeof(key) >= aead->key_size); | |
| assert(sizeof(iv) >= aead->iv_size); | |
| assert(sizeof(data) + authTagLength <= sizeof(encrypted)); | |
| assert(sizeof(decrypted) >= sizeof(encrypted)); | |
| memset(key, 'k', sizeof(key)); | |
| memset(data, 'd', sizeof(data)); | |
| memset(iv, 'n', sizeof(iv)); | |
| nonce = 0; | |
| memset(authData, 'a', sizeof(authData)); | |
| ret = EncodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, iv, (ULONG)aead->iv_size, data, | |
| 123, nonce, authData, 9, authTagLength, encrypted, 256, &encryptedLength); | |
| printf("Encrypt one shot returns %d, l=%d\n", ret, encryptedLength); | |
| if (ret == 0) { | |
| ret = DecodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, | |
| iv, (ULONG)aead->iv_size, encrypted, encryptedLength, nonce, authData, 9, | |
| authTagLength, decrypted, 256, &decryptedLength); | |
| printf("Decrypt one shot returns %d, l=%d\n", ret, decryptedLength); | |
| if (ret == 0) { | |
| if (decryptedLength != 123) { | |
| printf("Wrong length, not %d\n", 123); | |
| ret = -1; | |
| } else if (memcmp(data, decrypted, 123) != 0) { | |
| printf("Data and decrypted don't match\n"); | |
| ret = -1; | |
| } else { | |
| printf("One shot matches.\n"); | |
| } | |
| } | |
| } | |
| return ret; | |
| } | |
| void delete_test_aead_context(ptls_aead_context_t *ctx) | |
| { | |
| if (ctx != NULL) { | |
| ctx->dispose_crypto(ctx); | |
| free(ctx); | |
| } | |
| } | |
| ptls_aead_context_t *new_test_aead_context(ptls_aead_algorithm_t *aead, int is_enc, BYTE *key, BYTE *iv) | |
| { | |
| int ret = 0; | |
| ptls_aead_context_t *ctx = (ptls_aead_context_t *)malloc(aead->context_size); | |
| if (ctx != NULL) { | |
| memset(ctx, 0, aead->context_size); | |
| *ctx = (ptls_aead_context_t){aead}; | |
| if (aead->setup_crypto(ctx, is_enc, key, iv) != 0) { | |
| printf("For %s, setup returns %d\n", aead->name, ret); | |
| delete_test_aead_context(ctx); | |
| ctx = NULL; | |
| } | |
| } else { | |
| printf("For %s, memory error during setup\n", aead->name); | |
| } | |
| return (ctx); | |
| } | |
| int test_decrypt(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| BYTE key[32]; | |
| BYTE iv[PTLS_MAX_IV_SIZE]; | |
| BYTE data[123]; | |
| uint64_t nonce; | |
| BYTE authData[9]; | |
| BYTE encrypted[256]; | |
| ULONG encryptedLength; | |
| BYTE decrypted[256]; | |
| size_t decryptedLength; | |
| ULONG authTagLength = (ULONG)aead->tag_size; | |
| ptls_aead_context_t *ctx = NULL; | |
| int ret = 0; | |
| assert(sizeof(key) >= aead->key_size); | |
| assert(sizeof(iv) >= aead->iv_size); | |
| assert(sizeof(data) + authTagLength <= sizeof(encrypted)); | |
| assert(sizeof(decrypted) >= sizeof(encrypted)); | |
| memset(key, 'k', sizeof(key)); | |
| memset(iv, 'n', sizeof(iv)); | |
| memset(data, 'd', sizeof(data)); | |
| nonce = 0; | |
| memset(authData, 'a', sizeof(authData)); | |
| /* Create a decryption context */ | |
| ctx = new_test_aead_context(aead, 0, key, iv); | |
| if (ctx == NULL) { | |
| ret = -1; | |
| } | |
| /* Do a simple encrypt using one shot bcrypt */ | |
| if (ret == 0) { | |
| ret = EncodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, | |
| iv, (ULONG)aead->iv_size, data, 123, nonce, | |
| authData, 9, authTagLength, encrypted, 256, &encryptedLength); | |
| } | |
| /* Try decrypt with library procedure */ | |
| if (ret == 0) { | |
| decryptedLength = ctx->do_decrypt(ctx, decrypted, encrypted, encryptedLength, nonce, authData, 9); | |
| if (decryptedLength >= encryptedLength) { | |
| printf("For %s, decrypt returns %d\n", aead->name, (int)decryptedLength); | |
| ret = -1; | |
| } else if (decryptedLength != 123) { | |
| printf("For %s, decrypt returns %d instead of %d\n", aead->name, (int)decryptedLength, 123); | |
| ret = -1; | |
| } else if (memcmp(data, decrypted, decryptedLength) != 0) { | |
| printf("For %s, decrypted does not match clear text\n", aead->name); | |
| ret = -1; | |
| } else { | |
| printf("For %s, decrypting test passes.\n", aead->name); | |
| } | |
| } | |
| delete_test_aead_context(ctx); | |
| return ret; | |
| } | |
| int test_encrypt(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| BYTE key[32]; | |
| BYTE iv[PTLS_MAX_IV_SIZE]; | |
| BYTE data[123]; | |
| uint64_t nonce; | |
| BYTE authData[9]; | |
| BYTE encryptedRef[256]; | |
| ULONG encryptedRefLength; | |
| BYTE encrypted[256]; | |
| size_t encryptedLength; | |
| ULONG authTagLength = (ULONG)aead->tag_size; | |
| ptls_aead_context_t *ctx = NULL; | |
| int ret = 0; | |
| assert(sizeof(key) >= aead->key_size); | |
| assert(sizeof(iv) >= aead->iv_size); | |
| assert(sizeof(data) + authTagLength <= sizeof(encrypted)); | |
| assert(sizeof(data) + authTagLength <= sizeof(encryptedRef)); | |
| memset(key, 'k', sizeof(key)); | |
| memset(iv, 'n', sizeof(iv)); | |
| memset(data, 'd', sizeof(data)); | |
| nonce = 0; | |
| memset(authData, 'a', sizeof(authData)); | |
| /* Create an encryption context */ | |
| ctx = new_test_aead_context(aead, 1, key, iv); | |
| if (ctx == NULL) { | |
| ret = -1; | |
| } | |
| /* Do a simple encrypt using one shot bcrypt */ | |
| if (ret == 0) { | |
| ret = EncodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, | |
| iv, (ULONG)aead->iv_size, data, 123, nonce, | |
| authData, 9, authTagLength, encryptedRef, 256, &encryptedRefLength); | |
| } | |
| /* Try encrypt with library procedure */ | |
| if (ret == 0) { | |
| ctx->do_encrypt_init(ctx, nonce, authData, 9); | |
| encryptedLength = ctx->do_encrypt_update(ctx, encrypted, data, 123); | |
| encryptedLength += ctx->do_encrypt_final(ctx, &encrypted[encryptedLength]); | |
| if (encryptedLength != encryptedRefLength) { | |
| printf("For %s, encrypt returns %d instead of %d\n", aead->name, (int)encryptedLength, encryptedRefLength); | |
| ret = -1; | |
| } else if (memcmp(encryptedRef, encrypted, encryptedRefLength) != 0) { | |
| printf("For %s, encrypted does not match ref\n", aead->name); | |
| for (ULONG i = 0; i < encryptedRefLength; i++) { | |
| if (encryptedRef[i] != encrypted[i]) { | |
| printf("For %s, encrypted[%d] = 0x%02x vs encryptedRef[%d] = 0x%02x\n", aead->name, i, encrypted[i], i, | |
| encryptedRef[i]); | |
| break; | |
| } | |
| } | |
| ret = -1; | |
| } else { | |
| printf("For %s, encrypting test passes.\n", aead->name); | |
| } | |
| } | |
| delete_test_aead_context(ctx); | |
| return ret; | |
| } | |
| int test_encrypt_vector(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| BYTE key[32]; | |
| BYTE iv[PTLS_MAX_IV_SIZE]; | |
| BYTE data[123]; | |
| uint64_t nonce; | |
| BYTE authData[9]; | |
| BYTE encryptedRef[256]; | |
| ULONG encryptedRefLength; | |
| BYTE encrypted[256]; | |
| size_t encryptedLength; | |
| ULONG authTagLength = (ULONG)aead->tag_size; | |
| ptls_aead_context_t *ctx = NULL; | |
| int ret = 0; | |
| assert(sizeof(key) >= aead->key_size); | |
| assert(sizeof(iv) >= aead->iv_size); | |
| assert(sizeof(data) + authTagLength <= sizeof(encrypted)); | |
| assert(sizeof(data) + authTagLength <= sizeof(encryptedRef)); | |
| memset(key, 'k', sizeof(key)); | |
| memset(iv, 'n', sizeof(iv)); | |
| memset(data, 'd', sizeof(data)); | |
| nonce = 0; | |
| memset(authData, 'a', sizeof(authData)); | |
| /* Create an encryption context */ | |
| ctx = new_test_aead_context(aead, 1, key, iv); | |
| if (ctx == NULL) { | |
| ret = -1; | |
| } | |
| if (ret == 0) { | |
| ret = EncodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, iv, (ULONG)aead->iv_size, data, 123, | |
| nonce, authData, 9, authTagLength, encryptedRef, 256, &encryptedRefLength); | |
| } | |
| /* Try encrypt with vector procedure */ | |
| if (ret == 0) { | |
| ptls_iovec_t input_vec[2]; | |
| input_vec[0].base = data; | |
| input_vec[0].len = 23; | |
| input_vec[1].base = data + 23; | |
| input_vec[1].len = 100; | |
| ptls_aead_encrypt_v(ctx, encrypted, input_vec, 2, nonce, authData, 9); | |
| encryptedLength = 123 + authTagLength; | |
| if (encryptedLength != encryptedRefLength) { | |
| printf("For %s, encrypt_v returns %d instead of %d\n", aead->name, (int)encryptedLength, encryptedRefLength); | |
| ret = -1; | |
| } else if (memcmp(encryptedRef, encrypted, encryptedRefLength) != 0) { | |
| printf("For %s, vector encrypted does not match ref\n", aead->name); | |
| for (ULONG i = 0; i < encryptedRefLength; i++) { | |
| if (encryptedRef[i] != encrypted[i]) { | |
| printf("For %s, vector encrypted[%d] = 0x%02x vs encryptedRef[%d] = 0x%02x\n", aead->name, i, encrypted[i], i, | |
| encryptedRef[i]); | |
| break; | |
| } | |
| } | |
| ret = -1; | |
| } else { | |
| printf("For %s, vector encrypting test passes.\n", aead->name); | |
| } | |
| } | |
| delete_test_aead_context(ctx); | |
| return ret; | |
| } | |
| int test_for_size(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| BYTE key[32]; | |
| BYTE iv[PTLS_MAX_IV_SIZE]; | |
| uint64_t nonce; | |
| BYTE authData[9]; | |
| BYTE *data = NULL; | |
| BYTE *encrypted = NULL; | |
| BYTE *decrypted = NULL; | |
| size_t encryptedLength; | |
| size_t decryptedLength; | |
| ULONG authTagLength = (ULONG)aead->tag_size; | |
| ptls_aead_context_t *ctx_e = NULL; | |
| ptls_aead_context_t *ctx_d = NULL; | |
| ULONG packet_size[] = {1500, 128, 3, 0}; | |
| ULONG nb_packet_size = (ULONG)(sizeof(packet_size) / sizeof(ULONG)); | |
| int ret = 0; | |
| assert(sizeof(key) >= aead->key_size); | |
| assert(sizeof(iv) >= aead->iv_size); | |
| memset(key, 'k', sizeof(key)); | |
| memset(key, 'n', sizeof(iv)); | |
| nonce = 0; | |
| memset(authData, 'a', sizeof(authData)); | |
| /* Create the encryption contexts */ | |
| ctx_e = new_test_aead_context(aead, 1, key, iv); | |
| ctx_d = new_test_aead_context(aead, 0, key, iv); | |
| if (ctx_e == NULL || ctx_d == NULL) { | |
| ret = -1; | |
| } | |
| /* Test a variety of packet sizes */ | |
| for (ULONG i = 0; ret == 0 && i < nb_packet_size; i++) { | |
| ULONG data_size = (packet_size[i] > 0) ? packet_size[i] : 128; | |
| ULONG encrypted_size = packet_size[i] + authTagLength; | |
| data = (BYTE *)malloc(data_size); | |
| encrypted = (BYTE *)malloc(encrypted_size); | |
| decrypted = (BYTE *)malloc(data_size); | |
| if (data == NULL || encrypted == NULL || decrypted == NULL) { | |
| printf("For %s: cannot allocate memory for packet size[%d] = %d\n", aead->name, i, packet_size[i]); | |
| } else { | |
| memset(data, 'd', data_size); | |
| ctx_e->do_encrypt_init(ctx_e, nonce, authData, 9); | |
| encryptedLength = ctx_e->do_encrypt_update(ctx_e, encrypted, data, packet_size[i]); | |
| encryptedLength += ctx_e->do_encrypt_final(ctx_e, &encrypted[encryptedLength]); | |
| decryptedLength = ctx_d->do_decrypt(ctx_d, decrypted, encrypted, encryptedLength, nonce, authData, 9); | |
| if (decryptedLength >= encryptedLength) { | |
| printf("For %s, decrypt returns %d\n", aead->name, (int)decryptedLength); | |
| ret = -1; | |
| } else if (decryptedLength != packet_size[i]) { | |
| printf("For %s, decrypt returns %d instead of %d\n", aead->name, (int)decryptedLength, packet_size[i]); | |
| ret = -1; | |
| } else if (memcmp(data, decrypted, decryptedLength) != 0) { | |
| printf("For %s, decrypted does not match clear text\n", aead->name); | |
| ret = -1; | |
| } else { | |
| printf("For %s, test packet size[%d] = %d passes.\n", aead->name, i, packet_size[i]); | |
| } | |
| } | |
| if (data != NULL) { | |
| free(data); | |
| data = NULL; | |
| } | |
| if (encrypted != NULL) { | |
| free(encrypted); | |
| encrypted = NULL; | |
| } | |
| if (decrypted != NULL) { | |
| free(decrypted); | |
| decrypted = NULL; | |
| } | |
| } | |
| delete_test_aead_context(ctx_e); | |
| delete_test_aead_context(ctx_d); | |
| return ret; | |
| } | |
| int test_one_aead(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz) | |
| { | |
| int ret = test_oneshot(aead, name, chain_mode, chain_mode_sz); | |
| printf("For %s, test one shot returns %d\n", aead->name, ret); | |
| if (ret == 0) { | |
| ret = test_decrypt(aead, name, chain_mode, chain_mode_sz); | |
| printf("For %s, test decrypt returns %d\n", aead->name, ret); | |
| } | |
| if (ret == 0) { | |
| ret = test_encrypt(aead, name, chain_mode, chain_mode_sz); | |
| printf("For %s, test encrypt returns %d\n", aead->name, ret); | |
| } | |
| if (ret == 0) { | |
| ret = test_encrypt_vector(aead, name, chain_mode, chain_mode_sz); | |
| printf("For %s, test encrypt returns %d\n", aead->name, ret); | |
| } | |
| if (ret == 0) { | |
| ret = test_for_size(aead, name, chain_mode, chain_mode_sz); | |
| printf("For %s, test packet sizes returns %d\n", aead->name, ret); | |
| } | |
| return ret; | |
| } | |
| /* Test of cipher functions. | |
| * The test verifies that a message encode with a bcrypt function can be | |
| * decoded with a minicrypto function, and vice versa. | |
| */ | |
| int test_cipher_one_way(char const *name1, char const *name2, ptls_cipher_algorithm_t *b1, ptls_cipher_algorithm_t *b2, | |
| unsigned int nb_blocks) | |
| { | |
| BYTE key[32]; | |
| BYTE nonce[16]; | |
| BYTE data[128]; | |
| BYTE encrypted[128]; | |
| BYTE decrypted[128]; | |
| size_t data_size = b1->block_size * nb_blocks; | |
| ptls_cipher_context_t *ctx1 = NULL; | |
| ptls_cipher_context_t *ctx2 = NULL; | |
| int ret = 0; | |
| assert(sizeof(key) >= b1->key_size); | |
| assert(sizeof(data) >= data_size); | |
| assert(sizeof(nonce) >= b1->iv_size); | |
| memset(key, 'k', sizeof(key)); | |
| memset(data, 'd', data_size); | |
| ctx1 = ptls_cipher_new(b1, 1, key); | |
| ctx2 = ptls_cipher_new(b2, 0, key); | |
| if (ctx1 == NULL || ctx2 == NULL) { | |
| ret = -1; | |
| } else { | |
| memset(nonce, 0, sizeof(nonce)); | |
| if (ctx1->do_init != NULL) { | |
| ctx1->do_init(ctx1, nonce); | |
| } | |
| if (ctx2->do_init != NULL) { | |
| ctx2->do_init(ctx2, nonce); | |
| } | |
| ctx1->do_transform(ctx1, encrypted, data, data_size); | |
| ctx2->do_transform(ctx2, decrypted, encrypted, data_size); | |
| if (memcmp(data, decrypted, data_size) != 0) { | |
| printf("For %s -> %s, decrypted does not match clear text\n", name1, name2); | |
| ret = -1; | |
| } else { | |
| printf("For %s -> %s, test passes.\n", name1, name2); | |
| } | |
| } | |
| if (ctx1 != NULL) { | |
| ptls_cipher_free(ctx1); | |
| } | |
| if (ctx2 != NULL) { | |
| ptls_cipher_free(ctx2); | |
| } | |
| return ret; | |
| } | |
| int test_cipher_pair(char const *name1, char const *name2, ptls_cipher_algorithm_t *b1, ptls_cipher_algorithm_t *b2, | |
| unsigned int nb_blocks) | |
| { | |
| int ret = test_cipher_one_way(name1, name2, b1, b2, nb_blocks); | |
| if (ret == 0) { | |
| ret = test_cipher_one_way(name2, name1, b2, b1, nb_blocks); | |
| } | |
| return ret; | |
| } | |
| /* Test of the hash functions | |
| */ | |
| int test_hash_calc(char const *name1, char const *name2, ptls_hash_algorithm_t *h1, ptls_hash_algorithm_t *h2) | |
| { | |
| BYTE data[123]; | |
| BYTE tag1[128]; | |
| BYTE tag2[128]; | |
| ptls_hash_context_t *ctx1 = NULL; | |
| ptls_hash_context_t *ctx2 = NULL; | |
| int ret = 0; | |
| assert(sizeof(tag1) >= h1->digest_size); | |
| assert(sizeof(tag2) >= h2->digest_size); | |
| assert(h1->digest_size == h2->digest_size); | |
| memset(data, 'd', sizeof(data)); | |
| memset(tag1, '1', sizeof(tag1)); | |
| memset(tag2, '2', sizeof(tag2)); | |
| if (h1->digest_size != h2->digest_size) { | |
| ret = -1; | |
| } | |
| if (ret == 0) { | |
| ret = ptls_calc_hash(h1, tag1, data, sizeof(data)); | |
| } | |
| if (ret == 0) { | |
| ret = ptls_calc_hash(h2, tag2, data, sizeof(data)); | |
| } | |
| if (ret == 0){ | |
| if (memcmp(tag1, tag2, h1->digest_size) != 0) { | |
| printf("For %s -> %s, hash1 does not match hash2\n", name1, name2); | |
| ret = -1; | |
| } else { | |
| printf("For %s -> %s, hash test passes.\n", name1, name2); | |
| } | |
| } | |
| return ret; | |
| } | |
| /* Minimal test program for the bcrypt functions. | |
| * Need to add tests for the SHA256 and SHA384 implementations. | |
| */ | |
| int main() | |
| { | |
| int ret = 0; | |
| ret |= test_cipher_pair("bcrypt aes128ecb", "minicrypto aes128ecb", &ptls_bcrypt_aes128ecb, &ptls_minicrypto_aes128ecb, 1); | |
| ret |= test_cipher_pair("bcrypt aes256ecb", "minicrypto aes256ecb", &ptls_bcrypt_aes256ecb, &ptls_minicrypto_aes256ecb, 1); | |
| ret |= test_cipher_pair("bcrypt aes128ctr", "minicrypto aes128ctr", &ptls_bcrypt_aes128ctr, &ptls_minicrypto_aes128ctr, 4); | |
| ret |= test_cipher_pair("bcrypt aes256ctr", "minicrypto aes256ctr", &ptls_bcrypt_aes256ctr, &ptls_minicrypto_aes256ctr, 4); | |
| ret |= test_one_aead(&ptls_bcrypt_aes128gcm, BCRYPT_AES_ALGORITHM, BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM)); | |
| ret |= test_one_aead(&ptls_bcrypt_aes256gcm, BCRYPT_AES_ALGORITHM, BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM)); | |
| ret |= test_hash_calc("bcrypt sha256", "minicrypto sha256", &ptls_bcrypt_sha256, &ptls_minicrypto_sha256); | |
| ret |= test_hash_calc("bcrypt sha384", "minicrypto sha384", &ptls_bcrypt_sha384, &ptls_minicrypto_sha384); | |
| exit(ret); | |
| } |