Revision 0d9153dc34ee2dcf0821e3f21e825fc5bb8895b4 authored by Santiago Zanella-Beguelin on 11 December 2019, 17:46:08 UTC, committed by Santiago Zanella-Beguelin on 12 December 2019, 10:33:01 UTC
1 parent 7405f78
evercrypt_bcrypt.c
/* BCrypt is only available on Windows platforms */
#if defined(_MSC_VER) || defined(__MINGW32__)
#define IS_WINDOWS 1
#ifdef _KERNEL_MODE
#include <nt.h>
#include <ntrtl.h>
#else
#include <windows.h>
#endif
#include <bcrypt.h>
#ifndef BCRYPT_AES_GCM_ALG_HANDLE
#define BCRYPT_AES_GCM_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x000001e1)
#endif
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
#else
#define IS_WINDOWS 0
#include <unistd.h>
#endif
#include <fcntl.h>
#include <inttypes.h>
#include "kremlin/internal/target.h"
#include "EverCrypt_BCrypt.h"
/* KB, BB, JP: for now, we just ignore internal errors since the HACL* interface
* has enough preconditions to make sure that no errors ever happen; if the
* OpenSSL F* interface is strong enough, then any error here should be
* catastrophic and not something we can recover from.
* If we want to do something better, we can define:
* type error a = | Ok of a | Error of error_code
* Then at the boundary we could catch the error, print it, then exit abruptly.
* */
#define handleErrors(...) \
do { \
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
} while (0)
#if IS_WINDOWS
static BCRYPT_ALG_HANDLE g_hAlgRandom = NULL;
static uint32_t bcrypt_rng_init(void)
{
NTSTATUS st = BCryptOpenAlgorithmProvider(
&g_hAlgRandom,
BCRYPT_RNG_ALGORITHM,
NULL,
#ifdef _KERNEL_MODE
BCRYPT_PROV_DISPATCH
#else
0
#endif
);
if (!NT_SUCCESS(st)) {
return 0;
}
return 1;
}
static void bcrypt_rng_sample(uint32_t len, uint8_t *out)
{
NTSTATUS st;
/* Try to lazily initialize the RNG if it wasn't done
* by the user. If it fails, the app crashes. */
if(g_hAlgRandom == NULL)
{
if(!bcrypt_rng_init())
handleErrors();
}
st = BCryptGenRandom(g_hAlgRandom, out, len, 0);
if (!NT_SUCCESS(st)) {
handleErrors();
}
}
static void bcrypt_rng_cleanup(void)
{
BCryptCloseAlgorithmProvider(g_hAlgRandom, 0);
}
static BCRYPT_KEY_HANDLE bcrypt_create(BCRYPT_ALG_HANDLE alg, uint8_t *key, ULONG key_size)
{
NTSTATUS s;
BCRYPT_KEY_HANDLE hKey = NULL;
s = BCryptGenerateSymmetricKey(alg, &hKey, NULL, 0, key, key_size, 0);
if(!NT_SUCCESS(s)) handleErrors();
return hKey;
}
static uint32_t bcrypt_aead(BCRYPT_KEY_HANDLE hKey,
int enc, uint8_t *iv,
uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len,
uint8_t *ciphertext, uint8_t *tag)
{
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Info;
NTSTATUS s;
ULONG OutSize;
BCRYPT_INIT_AUTH_MODE_INFO(Info);
Info.pbAuthData = (PUCHAR) aad;
Info.cbAuthData = aad_len;
Info.pbTag = tag;
Info.cbTag = 16;
Info.pbNonce = iv;
Info.cbNonce = 12;
if(enc)
s = BCryptEncrypt(hKey, plaintext, plaintext_len, &Info, iv, 12, ciphertext, plaintext_len, &OutSize, 0);
else
s = BCryptDecrypt(hKey, ciphertext, plaintext_len, &Info, iv, 12, plaintext, plaintext_len, &OutSize, 0);
if (!NT_SUCCESS(s))
return 0;
return 1;
}
static void bcrypt_free(BCRYPT_KEY_HANDLE hKey)
{
BCryptDestroyKey(hKey);
}
#else /* IS_WINDOWS */
#define BCRYPT_KEY_HANDLE void*
#define BCRYPT_ALG_HANDLE uint8_t
#define BCRYPT_AES_GCM_ALG_HANDLE 0
static uint32_t bcrypt_rng_init(void)
{
return 0;
}
static void bcrypt_rng_sample(uint32_t len, uint8_t *out)
{
handleErrors();
}
static void bcrypt_rng_cleanup(void)
{
handleErrors();
}
static BCRYPT_KEY_HANDLE bcrypt_create(BCRYPT_ALG_HANDLE alg, uint8_t key, ULONG key_size)
{
return NULL;
}
static uint32_t bcrypt_aead(BCRYPT_KEY_HANDLE hKey,
int enc, uint8_t *iv,
uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len,
uint8_t *ciphertext, uint8_t *tag)
{
return 0;
}
static void bcrypt_free(BCRYPT_KEY_HANDLE hKey)
{
}
#endif /* IS_WINDOWS */
uint32_t EverCrypt_BCrypt_random_init(void)
{
return bcrypt_rng_init();
}
void EverCrypt_BCrypt_random_sample(uint32_t len, uint8_t *out)
{
bcrypt_rng_sample(len, out);
}
void EverCrypt_BCrypt_random_cleanup(void)
{
bcrypt_rng_cleanup();
}
void EverCrypt_BCrypt_aes128_gcm_encrypt(uint8_t *key, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
BCRYPT_KEY_HANDLE hKey = bcrypt_create(BCRYPT_AES_GCM_ALG_HANDLE, key, 16);
if(NULL == hKey || 1 != bcrypt_aead(hKey, 1, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag))
handleErrors();
bcrypt_free(hKey);
}
uint32_t EverCrypt_BCrypt_aes128_gcm_decrypt(uint8_t *key, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
BCRYPT_KEY_HANDLE hKey = bcrypt_create(BCRYPT_AES_GCM_ALG_HANDLE, key, 16);
if(hKey == NULL) return 0;
uint32_t ret = bcrypt_aead(hKey, 0, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag);
bcrypt_free(hKey);
return ret;
}
void EverCrypt_BCrypt_aes256_gcm_encrypt(uint8_t *key, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
BCRYPT_KEY_HANDLE hKey = bcrypt_create(BCRYPT_AES_GCM_ALG_HANDLE, key, 32);
if(NULL == hKey || 1 != bcrypt_aead(hKey, 1, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag))
handleErrors();
bcrypt_free(hKey);
}
uint32_t EverCrypt_BCrypt_aes256_gcm_decrypt(uint8_t *key, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
uint32_t ret;
BCRYPT_KEY_HANDLE hKey = bcrypt_create(BCRYPT_AES_GCM_ALG_HANDLE, key, 32);
if(hKey == NULL) return 0;
ret = bcrypt_aead(hKey, 0, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag);
bcrypt_free(hKey);
return ret;
}
void* EverCrypt_BCrypt_aead_create(uint8_t alg, uint8_t *key)
{
BCRYPT_KEY_HANDLE hKey = bcrypt_create(BCRYPT_AES_GCM_ALG_HANDLE, key, alg ? 32 : 16);
if(hKey == NULL) handleErrors();
return (void*)hKey;
}
void EverCrypt_BCrypt_aead_encrypt(void* hKey, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
bcrypt_aead((BCRYPT_KEY_HANDLE)hKey, 1, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag);
}
uint32_t EverCrypt_BCrypt_aead_decrypt(void* hKey, uint8_t *iv, uint8_t *aad, uint32_t aad_len,
uint8_t *plaintext, uint32_t plaintext_len, uint8_t *ciphertext, uint8_t *tag)
{
return bcrypt_aead((BCRYPT_KEY_HANDLE)hKey, 0, iv, aad, aad_len, plaintext, plaintext_len, ciphertext, tag);
}
void EverCrypt_BCrypt_aead_free(void* hKey)
{
bcrypt_free((BCRYPT_KEY_HANDLE)hKey);
}
Computing file changes ...