Develop a cryptographic provider library for picotls based on the Windows specifc bcrypt library.
diff --git a/include/picotls/ptlsbcrypt.h b/include/picotls/ptlsbcrypt.h
index 4685b76..890953a 100644
--- a/include/picotls/ptlsbcrypt.h
+++ b/include/picotls/ptlsbcrypt.h
@@ -19,8 +19,8 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
-#ifndef picotls_openssl_h
-#define picotls_openssl_h
+#ifndef picotls_bcrypt_h
+#define picotls_bcrypt_h
#ifdef __cplusplus
extern "C" {
@@ -28,6 +28,9 @@
#include "../picotls.h"
+#ifdef _WINDOWS
+#include <bcrypt.h>
+
extern ptls_cipher_algorithm_t ptls_bcrypt_aes128ecb;
extern ptls_cipher_algorithm_t ptls_bcrypt_aes256ecb;
extern ptls_cipher_algorithm_t ptls_bcrypt_aes128ctr;
@@ -41,6 +44,7 @@
extern ptls_cipher_suite_t ptls_bcrypt_aes128gcmsha256;
extern ptls_cipher_suite_t ptls_bcrypt_aes256gcmsha384;
+#endif
#if 0
@@ -84,4 +88,4 @@
}
#endif
-#endif
+#endif /* picotls_bcrypt_h */
diff --git a/lib/ptlsbcrypt.c b/lib/ptlsbcrypt.c
index 57cfd41..8b32da7 100644
--- a/lib/ptlsbcrypt.c
+++ b/lib/ptlsbcrypt.c
@@ -45,7 +45,7 @@
* required common variables, etc. */
int ptls_bcrypt_init()
{
- return -1;
+ return 0;
}
/**
@@ -63,30 +63,8 @@
/* TODO: Crypto gen random */
}
-/**
- * a symmetric cipher
- *
-typedef const struct st_ptls_cipher_algorithm_t {
- const char *name;
- size_t key_size;
- size_t block_size;
- size_t iv_size;
- size_t context_size;
- int (*setup_crypto)(ptls_cipher_context_t *ctx, int is_enc, const void *key);
-} ptls_cipher_algorithm_t;
-*/
-
-/**
- * context of a symmetric cipher
- * the "algo" field must not be altered by crypto bindings.
-
-typedef struct st_ptls_cipher_context_t {
- const struct st_ptls_cipher_algorithm_t *algo;
- void (*do_dispose)(struct st_ptls_cipher_context_t *ctx);
- void (*do_init)(struct st_ptls_cipher_context_t *ctx, const void *iv);
- void (*do_transform)(struct st_ptls_cipher_context_t *ctx, void *output, const void *input, size_t len);
-} ptls_cipher_context_t;
-
+/*
+ * Support for symmetric ciphers
*/
struct ptls_bcrypt_symmetric_param_t {
@@ -103,11 +81,15 @@
struct ptls_bcrypt_symmetric_param_t bctx;
};
-static void ptls_bcrypt_cipher_init(ptls_cipher_context_t *_ctx, const void *iv)
+static void ptls_bcrypt_cipher_init_ctr(ptls_cipher_context_t *_ctx, const void *iv)
{
struct ptls_bcrypt_symmetric_context_t *ctx = (struct ptls_bcrypt_symmetric_context_t *)_ctx;
/* Copy the IV to inside structure */
- memcpy(ctx->bctx.iv, iv, ctx->super.algo->iv_size);
+ if (iv != NULL) {
+ memcpy(ctx->bctx.iv, iv, ctx->super.algo->block_size);
+ } else {
+ memset(ctx->bctx.iv, 0, ctx->super.algo->block_size);
+ }
}
static void ptls_bcrypt_cipher_dispose(ptls_cipher_context_t *_ctx)
@@ -141,6 +123,10 @@
}
assert(BCRYPT_SUCCESS(ret));
+
+ if (!BCRYPT_SUCCESS(ret)) {
+ memset(output, 0, cbResult);
+ }
}
static void ptls_bcrypt_cipher_transform_ctr(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
@@ -148,35 +134,36 @@
struct ptls_bcrypt_symmetric_context_t *ctx = (struct ptls_bcrypt_symmetric_context_t *)_ctx;
ULONG cbResult;
NTSTATUS ret;
- uint8_t iv[PTLS_MAX_IV_SIZE];
uint8_t eiv[PTLS_MAX_IV_SIZE];
- size_t iv_size = _ctx->algo->iv_size;
- size_t i;
+ int i;
uint64_t seq = 0;
size_t processed = 0;
uint8_t const *v_in = input;
uint8_t *v_out = output;
+ assert(ctx->super.algo->block_size > 0);
assert(ctx->super.algo->block_size <= PTLS_MAX_IV_SIZE);
while (processed < len) {
- /* Build the next iv block */
- const uint8_t *s = ctx->bctx.iv;
- uint8_t *d = iv;
- for (i = iv_size - 8; i != 0; --i)
- *d++ = *s++;
- i = 64;
- do {
- i -= 8;
- *d++ = *s++ ^ (uint8_t)(seq >> i);
- } while (i != 0);
- ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)iv, (ULONG)ctx->super.algo->block_size, NULL, NULL, 0, eiv,
+ ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.iv, (ULONG)ctx->super.algo->block_size, NULL, NULL, 0, eiv,
(ULONG)(ULONG)ctx->super.algo->block_size, &cbResult, 0);
assert(BCRYPT_SUCCESS(ret));
- for (i = 0; processed < len && i < ctx->super.algo->block_size; i++, processed++) {
- v_out[processed] = v_in[processed] ^ eiv[i];
+ if (BCRYPT_SUCCESS(ret)) {
+ for (i = 0; processed < len && i < ctx->super.algo->block_size; i++, processed++) {
+ v_out[processed] = v_in[processed] ^ eiv[i];
+ }
+
+ /* Increment the iv block */
+ i = (int)ctx->super.algo->block_size - 1;
+ while (i >= 0) {
+ ctx->bctx.iv[i] += 1;
+ if (ctx->bctx.iv[i] > 0) {
+ break;
+ }
+ i--;
+ }
}
}
}
@@ -224,10 +211,11 @@
if (BCRYPT_SUCCESS(ret)) {
ctx->super.do_dispose = ptls_bcrypt_cipher_dispose;
- ctx->super.do_init = ptls_bcrypt_cipher_init;
if (is_ctr) {
+ ctx->super.do_init = ptls_bcrypt_cipher_init_ctr;
ctx->super.do_transform = ptls_bcrypt_cipher_transform_ctr;
} else {
+ ctx->super.do_init = NULL;
ctx->super.do_transform = ptls_bcrypt_cipher_transform_ecb;
}
ctx->bctx.is_enc = is_enc;
@@ -248,13 +236,68 @@
return ptls_bcrypt_cipher_setup_crypto(_ctx, is_enc, key, BCRYPT_AES_ALGORITHM, 1);
}
+
+/* Picotls assumes that AEAD encryption works as:
+ * - an "init" call that prepares the encryption context.
+ * - a series of "update" calls that encrypt segments of the message
+ * - a "final" call that completes the encryption.
+ *
+ * In Bcrypt, the update calls will be implemented as a series of calls
+ * to BCryptEncrypt. The state necessary to pass these calls is provided
+ * to the Bcrypt function in two parameters:
+ * - the "padding info" points to a BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
+ * structure
+ * - the "IV" parameter points to a buffer holding intermediate updates
+ * of the IV. That buffer shall be initialize to zero before the
+ * first call.
+ * The documentation of the AEAD mode on MSDN is slightly obscure, and
+ * also slightly wrong. After trial and errors and web searches, we find
+ * that:
+ * - the Nonce parameter (pbNonce, cbNonce) points to the initial
+ * vector for the encryption, as passed by Picotls. Picotls combines
+ * per session IV and sequence number in that nonce prior to the call.
+ * - The Authdata parameter (pbAuthData, cbAuthData) points to the
+ * authenticated data passed to the API as aad, aadlen.
+ * - The cbAAd parameter contains the length of auth data that needs
+ * to be processed. It is initialized before the first call.
+ * - The tag parameter (pbTag, cbTag) points to a buffer that
+ * holds intermediate tag values during chaining. The size must be
+ * the size of the tag for the algorithm. It must be
+ * initialized to zero before first call.
+ * - The Mac Context parameter (pbMacContext, cbMacContext) contains
+ * a working buffer for the computation of the tag. The size
+ * must be the maxLength parameter returned retrieved in the
+ * BCRYPT_AUTH_TAG_LENGTH property of the algorithm. It must be
+ * initialized to zero before first call.
+ * - The dwflag parameters must be set to
+ * BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG on first call. (The
+ * MSDN documentation says BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG,
+ * but that's an error.)
+ *
+ * The members of the BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO struct
+ * should not be modified between calls, except for:
+ * - the BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG should be cleared
+ * before the final call.
+ *
+ * The Picotls API does not constrain the length of the segments
+ * passed in the "update" calls, but BCryptEncrypt will fail with
+ * error STATUS_INVALID_BUFFER_SIZE if the length passed in the
+ * chained calls is not an integer multiple of block size. This forces
+ * us to maintain an intermediate buffer of "extra bytes".
+ *
+ */
+
struct ptls_bcrypt_aead_param_t {
HANDLE hKey;
ULONG cbKeyObject;
+ ULONG maxTagLength;
+ ULONG nbExtraBytes;
uint8_t *key_object;
+ uint8_t extraBytes[PTLS_MAX_DIGEST_SIZE];
uint8_t iv[PTLS_MAX_IV_SIZE];
+ uint8_t ivbuf[PTLS_MAX_IV_SIZE];
uint8_t tag[PTLS_MAX_DIGEST_SIZE];
- uint64_t nonce;
+ uint8_t auth_tag[PTLS_MAX_DIGEST_SIZE];
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO aead_params;
};
@@ -286,46 +329,101 @@
memcpy(ctx->bctx.iv, iv, ctx->super.algo->iv_size);
/* Auth tag to NULL */
memset(ctx->bctx.tag, 0, sizeof(ctx->super.algo->tag_size));
-
- /* pPaddingInfo must point to BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure. */
BCRYPT_INIT_AUTH_MODE_INFO(ctx->bctx.aead_params);
- /* TODO: find clarity on handling of nonce */
- ctx->bctx.nonce = 0;
- ctx->bctx.aead_params.pbNonce = (PUCHAR)&ctx->bctx.nonce;
- ctx->bctx.aead_params.cbNonce = (ULONG)sizeof(ctx->bctx.nonce);
+
+ assert(ctx->super.algo->iv_size <= sizeof(ctx->bctx.ivbuf));
+ assert(ctx->super.algo->tag_size <= sizeof(ctx->bctx.tag));
+ assert(ctx->bctx.maxTagLength <= sizeof(ctx->bctx.auth_tag));
+
+ memset(ctx->bctx.ivbuf, 0, ctx->super.algo->iv_size);
+ memset(ctx->bctx.tag, 0, ctx->super.algo->tag_size);
+ memset(ctx->bctx.auth_tag, 0, sizeof(ctx->bctx.auth_tag));
+
+ ctx->bctx.nbExtraBytes = 0;
+
+ ctx->bctx.aead_params.pbNonce = (PUCHAR)&ctx->bctx.iv;
+ ctx->bctx.aead_params.cbNonce = (ULONG)ctx->super.algo->iv_size;
ctx->bctx.aead_params.pbAuthData = (PUCHAR)aad;
ctx->bctx.aead_params.cbAuthData = (ULONG)aadlen;
ctx->bctx.aead_params.pbTag = (PUCHAR)ctx->bctx.tag;
- ctx->bctx.aead_params.cbTag = (ULONG)ctx->super.algo->tag_size;
+ ctx->bctx.aead_params.cbTag = (ULONG) ctx->super.algo->tag_size;
+ // ctx->bctx.aead_params.cbAAD = (ULONG)aadlen;
+ ctx->bctx.aead_params.pbMacContext = (PUCHAR) ctx->bctx.auth_tag;
+ ctx->bctx.aead_params.cbMacContext = (ULONG)ctx->bctx.maxTagLength;
+ ctx->bctx.aead_params.dwFlags = BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
}
static size_t ptls_bcrypt_aead_do_encrypt_update(struct st_ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
{
struct ptls_bcrypt_aead_context_t *ctx = (struct ptls_bcrypt_aead_context_t *)_ctx;
- size_t outlenMax = inlen;
- ULONG cbResult = 0;
+ size_t outlenMax = inlen + ctx->super.algo->tag_size + ctx->bctx.nbExtraBytes;
+ ULONG cbResult1 = 0;
+ ULONG cbResult2 = 0;
NTSTATUS ret;
- /* Call the decryption */
- ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)inlen, (void *)&ctx->bctx.aead_params, ctx->bctx.iv,
- (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult,
- BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG | BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG);
- assert(BCRYPT_SUCCESS(ret));
- return inlen;
+ /* If there are extra bytes, complement and encrypt */
+ if (ctx->bctx.nbExtraBytes > 0) {
+ ULONG requiredBytes = (ULONG)(ctx->super.algo->ecb_cipher->block_size - ctx->bctx.nbExtraBytes);
+
+ if (inlen < requiredBytes) {
+ memcpy(&ctx->bctx.extraBytes[ctx->bctx.nbExtraBytes], input, inlen);
+ ctx->bctx.nbExtraBytes += (ULONG) inlen;
+ inlen = 0;
+ } else {
+ memcpy(&ctx->bctx.extraBytes[ctx->bctx.nbExtraBytes], input, requiredBytes);
+ inlen -= requiredBytes;
+ input = (void*)(((uint8_t *)input) + requiredBytes);
+ ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.extraBytes, (ULONG)ctx->super.algo->ecb_cipher->block_size,
+ (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf, (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult1, 0);
+
+ assert(BCRYPT_SUCCESS(ret));
+ if (!BCRYPT_SUCCESS(ret)) {
+ memset(output, 0, cbResult1);
+ }
+ outlenMax -= cbResult1;
+ output = (void *)(((uint8_t *)output) + cbResult1);
+ }
+ }
+
+ /* If there are trailing bytes, store them in the extra bytes */
+ ctx->bctx.nbExtraBytes = (ULONG)(inlen % ctx->super.algo->ecb_cipher->block_size);
+ if (ctx->bctx.nbExtraBytes > 0) {
+ inlen -= ctx->bctx.nbExtraBytes;
+ memcpy(&ctx->bctx.extraBytes, (void *)(((uint8_t *)input) + inlen), ctx->bctx.nbExtraBytes);
+ }
+
+ if (inlen > 0) {
+ ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)inlen, (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf,
+ (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult2, 0);
+ assert(BCRYPT_SUCCESS(ret));
+
+ if (!BCRYPT_SUCCESS(ret)) {
+ memset(output, 0, cbResult2);
+ }
+ }
+ return (size_t)cbResult1 + cbResult2;
}
static size_t ptls_bcrypt_aead_do_encrypt_final(struct st_ptls_aead_context_t *_ctx, void *output)
{
struct ptls_bcrypt_aead_context_t *ctx = (struct ptls_bcrypt_aead_context_t *)_ctx;
- size_t oulenMax = ctx->super.algo->tag_size;
+ size_t outlenMax = ctx->super.algo->tag_size + ctx->bctx.nbExtraBytes;
ULONG cbResult = 0;
NTSTATUS ret;
- /* Call the decryption */
- ret = BCryptDecrypt(ctx->bctx.hKey, (PUCHAR)NULL, (ULONG)0, (void *)&ctx->bctx.aead_params, ctx->bctx.iv,
- (ULONG)ctx->super.algo->iv_size, output, (ULONG)oulenMax, &cbResult, BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG);
+ ctx->bctx.aead_params.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
+
+ ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.extraBytes, (ULONG)ctx->bctx.nbExtraBytes, (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf,
+ (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult, 0);
assert(BCRYPT_SUCCESS(ret));
- return ctx->super.algo->tag_size;
+
+ if (BCRYPT_SUCCESS(ret)) {
+ /* Find the tag in the aead parameters and append it to the output */
+ assert(cbResult + ctx->bctx.aead_params.cbTag <= outlenMax);
+ memcpy(((uint8_t *)output) + cbResult, ctx->bctx.aead_params.pbTag, ctx->bctx.aead_params.cbTag);
+ cbResult += ctx->bctx.aead_params.cbTag;
+ }
+ return cbResult;
}
static size_t ptls_bcrypt_aead_do_decrypt(struct st_ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen,
@@ -333,7 +431,7 @@
{
struct ptls_bcrypt_aead_context_t *ctx = (struct ptls_bcrypt_aead_context_t *)_ctx;
ULONG cbResult;
- size_t out_len_max = inlen - ctx->super.algo->tag_size;
+ size_t textLen = inlen - ctx->super.algo->tag_size;
NTSTATUS ret;
/* Save a copy of the IV*/
@@ -341,20 +439,18 @@
/* TODO: pPaddingInfo must point to BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO structure. */
BCRYPT_INIT_AUTH_MODE_INFO(ctx->bctx.aead_params);
- /* TODO: find clarity on handling of nonce */
- ctx->bctx.nonce = 0;
- ctx->bctx.aead_params.pbNonce = (PUCHAR)&ctx->bctx.nonce;
- ctx->bctx.aead_params.cbNonce = (ULONG)sizeof(ctx->bctx.nonce);
+ /* TODO: find clarity on handling of ivbuf */
+ memset(ctx->bctx.tag, 0, sizeof(ctx->super.algo->tag_size));
+ ctx->bctx.aead_params.pbNonce = (PUCHAR)&ctx->bctx.iv;
+ ctx->bctx.aead_params.cbNonce = (ULONG)ctx->super.algo->iv_size;
ctx->bctx.aead_params.pbAuthData = (PUCHAR)aad;
ctx->bctx.aead_params.cbAuthData = (ULONG)aadlen;
- memset(ctx->bctx.tag, 0, sizeof(ctx->bctx.tag));
- /* TODO: check whether there is a need to set the precise tag size */
- ctx->bctx.aead_params.pbTag = (PUCHAR)ctx->bctx.tag;
- ctx->bctx.aead_params.cbTag = (ULONG)sizeof(ctx->bctx.tag);
+ ctx->bctx.aead_params.pbTag = (PUCHAR)(((uint8_t *)input) + textLen);
+ ctx->bctx.aead_params.cbTag = (ULONG)(ULONG)ctx->super.algo->tag_size;
/* Call the decryption */
- ret = BCryptDecrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)inlen, (void *)&ctx->bctx.aead_params, ctx->bctx.iv,
- (ULONG)ctx->super.algo->iv_size, (PUCHAR)output, (ULONG)out_len_max, &cbResult, 0);
+ ret = BCryptDecrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)textLen, (void *)&ctx->bctx.aead_params,
+ NULL, 0, (PUCHAR)output, (ULONG)textLen, &cbResult, 0);
if (BCRYPT_SUCCESS(ret)) {
return (size_t)cbResult;
@@ -375,6 +471,10 @@
ret = BCryptOpenAlgorithmProvider(&hAlgorithm, bcrypt_name, NULL, 0);
if (BCRYPT_SUCCESS(ret)) {
+ ret = BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)bcrypt_mode, (ULONG)bcrypt_mode_size, 0);
+ }
+
+ if (BCRYPT_SUCCESS(ret)) {
DWORD ko_size = 0;
ULONG cbResult = 0;
@@ -391,7 +491,13 @@
}
if (BCRYPT_SUCCESS(ret)) {
- ret = BCryptSetProperty(hAlgorithm, BCRYPT_CHAINING_MODE, (PBYTE)bcrypt_mode, bcrypt_mode_size, 0);
+ BCRYPT_KEY_LENGTHS_STRUCT atl_st;
+ ULONG cbResult = 0;
+
+ ret = BCryptGetProperty(hAlgorithm, BCRYPT_AUTH_TAG_LENGTH, (PUCHAR)&atl_st, (ULONG)sizeof(atl_st), &cbResult, 0);
+ if (BCRYPT_SUCCESS(ret)) {
+ ctx->bctx.maxTagLength = atl_st.dwMaxLength;
+ }
}
if (BCRYPT_SUCCESS(ret)) {
@@ -399,11 +505,6 @@
(ULONG)ctx->super.algo->key_size, 0);
}
- if (BCRYPT_SUCCESS(ret)) {
- ret = BCryptSetProperty(ctx->bctx.hKey, BCRYPT_CHAINING_MODE, (PUCHAR)bcrypt_mode,
- (ULONG)(sizeof(wchar_t) * wcslen(bcrypt_mode)), 0);
- }
-
if (hAlgorithm != NULL) {
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
@@ -411,16 +512,16 @@
if (BCRYPT_SUCCESS(ret)) {
if (is_enc) {
ctx->super.dispose_crypto = ptls_bcrypt_aead_dispose_crypto;
- ctx->super.do_decrypt = ptls_bcrypt_aead_do_decrypt;
- ctx->super.do_encrypt_init = NULL;
- ctx->super.do_encrypt_update = NULL;
- ctx->super.do_encrypt_final = NULL;
- } else {
- ctx->super.dispose_crypto = ptls_bcrypt_aead_dispose_crypto;
ctx->super.do_decrypt = NULL;
ctx->super.do_encrypt_init = ptls_bcrypt_aead_do_encrypt_init;
ctx->super.do_encrypt_update = ptls_bcrypt_aead_do_encrypt_update;
ctx->super.do_encrypt_final = ptls_bcrypt_aead_do_encrypt_final;
+ } else {
+ ctx->super.dispose_crypto = ptls_bcrypt_aead_dispose_crypto;
+ ctx->super.do_decrypt = ptls_bcrypt_aead_do_decrypt;
+ ctx->super.do_encrypt_init = NULL;
+ ctx->super.do_encrypt_update = NULL;
+ ctx->super.do_encrypt_final = NULL;
}
return 0;
} else {
@@ -436,54 +537,14 @@
}
/* Hash algorithms */
-#if 0
-/**
- * A hash context.
- */
-typedef struct st_ptls_hash_context_t {
- /**
- * feeds additional data into the hash context
- */
- void (*update)(struct st_ptls_hash_context_t *ctx, const void *src, size_t len);
- /**
- * returns the digest and performs necessary operation specified by mode
- */
- void (*final)(struct st_ptls_hash_context_t *ctx, void *md, ptls_hash_final_mode_t mode);
- /**
- * creates a copy of the hash context
- */
- struct st_ptls_hash_context_t *(*clone_)(struct st_ptls_hash_context_t *src);
-} ptls_hash_context_t;
-/**
- * A hash algorithm and its properties.
- */
-typedef const struct st_ptls_hash_algorithm_t {
- /**
- * block size
- */
- size_t block_size;
- /**
- * digest size
- */
- size_t digest_size;
- /**
- * constructor that creates the hash context
- */
- ptls_hash_context_t *(*create)(void);
- /**
- * digest of zero-length octets
- */
- uint8_t empty_digest[PTLS_MAX_DIGEST_SIZE];
-} ptls_hash_algorithm_t;
-#endif
-
-typedef struct st_ptls_bcrypt_hash_param_t {
+struct st_ptls_bcrypt_hash_param_t {
wchar_t const *bcrypt_name;
BCRYPT_HASH_HANDLE hHash;
PUCHAR pbHashObject;
ULONG cbHashObject;
ULONG hash_size;
+ int has_error;
};
struct st_ptls_bcrypt_hash_context_t {
@@ -496,6 +557,10 @@
struct st_ptls_bcrypt_hash_context_t *ctx = (struct st_ptls_bcrypt_hash_context_t *)_ctx;
NTSTATUS ret = BCryptHashData(ctx->ctx.hHash, (PUCHAR)src, (ULONG)len, 0);
assert(BCRYPT_SUCCESS(ret));
+
+ if (!BCRYPT_SUCCESS(ret)) {
+ ctx->ctx.has_error = 1;
+ }
}
static struct st_ptls_bcrypt_hash_context_t *ptls_bcrypt_hash_context_free(struct st_ptls_bcrypt_hash_context_t *ctx)
@@ -529,6 +594,9 @@
if (md != NULL) {
ret = BCryptFinishHash(ctx->ctx.hHash, md, ctx->ctx.hash_size, 0);
assert(BCRYPT_SUCCESS(ret));
+ if (!BCRYPT_SUCCESS(ret) || ctx->ctx.has_error) {
+ memset(md, 0, ctx->ctx.hash_size);
+ }
}
ret = BCryptDestroyHash(ctx->ctx.hHash);
@@ -547,6 +615,9 @@
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
assert(BCRYPT_SUCCESS(ret));
+ if (!BCRYPT_SUCCESS(ret)) {
+ ctx->ctx.hHash = NULL;
+ }
break;
}
default:
@@ -570,11 +641,12 @@
clone_ctx->ctx.cbHashObject = ctx->ctx.cbHashObject;
clone_ctx->ctx.bcrypt_name = ctx->ctx.bcrypt_name;
clone_ctx->ctx.hash_size = ctx->ctx.hash_size;
+ clone_ctx->ctx.has_error = ctx->ctx.has_error;
if (clone_ctx->ctx.pbHashObject == NULL) {
ret = STATUS_NO_MEMORY;
} else {
- ctx->ctx.hHash = NULL;
+ clone_ctx->ctx.hHash = NULL;
ptls_clear_memory(&clone_ctx->ctx.pbHashObject, clone_ctx->ctx.cbHashObject);
ret = BCryptDuplicateHash(ctx->ctx.hHash, &clone_ctx->ctx.hHash, clone_ctx->ctx.pbHashObject,
clone_ctx->ctx.cbHashObject, 0);
@@ -606,8 +678,7 @@
DWORD hb_length = 0;
ULONG cbResult = 0;
- ret =
- BCryptGetProperty(hAlgorithm, BCRYPT_HASH_BLOCK_LENGTH, (PUCHAR)&hb_length, (ULONG)sizeof(hb_length), &cbResult, 0);
+ ret = BCryptGetProperty(hAlgorithm, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hb_length, (ULONG)sizeof(hb_length), &cbResult, 0);
if (BCRYPT_SUCCESS(ret)) {
ctx->ctx.pbHashObject = (uint8_t *)malloc(hb_length);
@@ -635,12 +706,12 @@
return (ptls_hash_context_t *)ctx;
}
-static ptls_hash_context_t *ptls_bcrypt_sha256_create()
+static ptls_hash_context_t *ptls_bcrypt_sha256_create(void)
{
return ptls_bcrypt_hash_create(BCRYPT_SHA256_ALGORITHM, PTLS_SHA256_DIGEST_SIZE);
}
-static ptls_hash_context_t *ptls_bcrypt_sha384_create()
+static ptls_hash_context_t *ptls_bcrypt_sha384_create(void)
{
return ptls_bcrypt_hash_create(BCRYPT_SHA384_ALGORITHM, PTLS_SHA384_DIGEST_SIZE);
}
@@ -703,189 +774,8 @@
ptls_cipher_suite_t ptls_bcrypt_aes256gcmsha384 = {PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, &ptls_bcrypt_aes256gcm,
&ptls_bcrypt_sha384};
-#ifdef PTLS_BCRYPT_TODO
-int ptls_bcrypt_init_verify_certificate(ptls_bcrypt_verify_certificate_t *self, X509_STORE *store)
-{
- /* TODO: Replace with bcrypt library */
- *self = (ptls_bcrypt_verify_certificate_t){{verify_cert}};
-
- if (store != NULL) {
- X509_STORE_up_ref(store);
- self->cert_store = store;
- } else {
- /* use default store */
- if ((self->cert_store = ptls_bcrypt_create_default_certificate_store()) == NULL)
- return -1;
- }
-
- return 0;
-}
-
-void ptls_bcrypt_dispose_verify_certificate(ptls_bcrypt_verify_certificate_t *self)
-{
- X509_STORE_free(self->cert_store);
- free(self);
-}
-
-X509_STORE *ptls_bcrypt_create_default_certificate_store(void)
-{
- X509_STORE *store;
- X509_LOOKUP *lookup;
-
- if ((store = X509_STORE_new()) == NULL)
- goto Error;
- if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL)
- goto Error;
- X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
- if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) == NULL)
- goto Error;
- X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
-
- return store;
-Error:
- if (store != NULL)
- X509_STORE_free(store);
- return NULL;
-}
-
-#define TICKET_LABEL_SIZE 16
-#define TICKET_IV_SIZE EVP_MAX_IV_LENGTH
-
-int ptls_bcrypt_encrypt_ticket(ptls_buffer_t *buf, ptls_iovec_t src,
- int (*cb)(unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc))
-{
- /* TODO: rewrite with bcrypt functions */
- EVP_CIPHER_CTX *cctx = NULL;
- HMAC_CTX *hctx = NULL;
- uint8_t *dst;
- int clen, ret;
-
- if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((hctx = HMAC_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- if ((ret = ptls_buffer_reserve(buf, TICKET_LABEL_SIZE + TICKET_IV_SIZE + src.len + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE)) !=
- 0)
- goto Exit;
- dst = buf->base + buf->off;
-
- /* fill label and iv, as well as obtaining the keys */
- if (!(*cb)(dst, dst + TICKET_LABEL_SIZE, cctx, hctx, 1)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += TICKET_LABEL_SIZE + TICKET_IV_SIZE;
-
- /* encrypt */
- if (!EVP_EncryptUpdate(cctx, dst, &clen, src.base, (int)src.len)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += clen;
- if (!EVP_EncryptFinal_ex(cctx, dst, &clen)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += clen;
-
- /* append hmac */
- if (!HMAC_Update(hctx, buf->base + buf->off, dst - (buf->base + buf->off)) || !HMAC_Final(hctx, dst, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- dst += HMAC_size(hctx);
-
- assert(dst <= buf->base + buf->capacity);
- buf->off += dst - (buf->base + buf->off);
- ret = 0;
-
-Exit:
- if (cctx != NULL)
- cleanup_cipher_ctx(cctx);
- if (hctx != NULL)
- HMAC_CTX_free(hctx);
- return ret;
-}
-
-int ptls_bcrypt_decrypt_ticket(ptls_buffer_t *buf, ptls_iovec_t src,
- int (*cb)(unsigned char *key_name, unsigned char *iv, EVP_CIPHER_CTX *ctx, HMAC_CTX *hctx, int enc))
-{
- /* TODO: replace with bcrypt functions */
- EVP_CIPHER_CTX *cctx = NULL;
- HMAC_CTX *hctx = NULL;
- int clen, ret;
-
- if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
- if ((hctx = HMAC_CTX_new()) == NULL) {
- ret = PTLS_ERROR_NO_MEMORY;
- goto Exit;
- }
-
- /* obtain cipher and hash context.
- * Note: no need to handle renew, since in picotls we always send a new ticket to minimize the chance of ticket reuse */
- if (src.len < TICKET_LABEL_SIZE + TICKET_IV_SIZE) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- if (!(*cb)(src.base, src.base + TICKET_LABEL_SIZE, cctx, hctx, 0)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
-
- /* check hmac, and exclude label, iv, hmac */
- size_t hmac_size = HMAC_size(hctx);
- if (src.len < TICKET_LABEL_SIZE + TICKET_IV_SIZE + hmac_size) {
- ret = PTLS_ALERT_DECODE_ERROR;
- goto Exit;
- }
- src.len -= hmac_size;
- uint8_t hmac[EVP_MAX_MD_SIZE];
- if (!HMAC_Update(hctx, src.base, src.len) || !HMAC_Final(hctx, hmac, NULL)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- if (!ptls_mem_equal(src.base + src.len, hmac, hmac_size)) {
- ret = PTLS_ALERT_HANDSHAKE_FAILURE;
- goto Exit;
- }
- src.base += TICKET_LABEL_SIZE + TICKET_IV_SIZE;
- src.len -= TICKET_LABEL_SIZE + TICKET_IV_SIZE;
-
- /* decrypt */
- if ((ret = ptls_buffer_reserve(buf, src.len)) != 0)
- goto Exit;
- if (!EVP_DecryptUpdate(cctx, buf->base + buf->off, &clen, src.base, (int)src.len)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- buf->off += clen;
- if (!EVP_DecryptFinal_ex(cctx, buf->base + buf->off, &clen)) {
- ret = PTLS_ERROR_LIBRARY;
- goto Exit;
- }
- buf->off += clen;
-
- ret = 0;
-
-Exit:
- if (cctx != NULL)
- cleanup_cipher_ctx(cctx);
- if (hctx != NULL)
- HMAC_CTX_free(hctx);
- return ret;
-}
-#endif
-
#ifdef PRLS_BCRYPT_TODO
-/* TODO: replace with bcrypt functions */
+/* TODO: develp these bcrypt functions */
ptls_key_exchange_algorithm_t ptls_bcrypt_secp256r1 = {PTLS_GROUP_SECP256R1, x9_62_create_key_exchange, secp_key_exchange,
NID_X9_62_prime256v1};
#if ptls_bcrypt_HAVE_SECP384R1
diff --git a/picotlsvs/bcrypt-test/bcrypt-test.c b/picotlsvs/bcrypt-test/bcrypt-test.c
new file mode 100644
index 0000000..324d425
--- /dev/null
+++ b/picotlsvs/bcrypt-test/bcrypt-test.c
@@ -0,0 +1,614 @@
+// 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(wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz, BYTE *key, ULONG key_length, BYTE *data,
+ ULONG dataLength, BYTE *nonceValue, ULONG nonceLength, 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 *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);
+ bacmi.pbNonce = nonceValue;
+ bacmi.cbNonce = nonceLength;
+ 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(wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz, BYTE *key, ULONG key_length, BYTE *encrypted,
+ ULONG encryptedLength, BYTE *nonceValue, ULONG nonceLength, BYTE *authData, ULONG authDataLength,
+ ULONG authTagLength, BYTE *decrypted, ULONG decryptedLengthMax, ULONG *decryptedLength)
+{
+
+ BCRYPT_KEY_HANDLE hKey = NULL;
+ BYTE *authTag = encrypted + (encryptedLength - authTagLength);
+ 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);
+ bacmi.pbNonce = nonceValue;
+ bacmi.cbNonce = nonceLength;
+ 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 nonce[12];
+ 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(nonce) >= 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(nonce, 'n', sizeof(nonce));
+ memset(authData, 'a', sizeof(authData));
+
+ ret = EncodeOneShot(name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, data, 123, nonce, (ULONG)aead->iv_size,
+ authData, 9, authTagLength, encrypted, 256, &encryptedLength);
+
+ printf("Encrypt one shot returns %d, l=%d\n", ret, encryptedLength);
+
+ if (ret == 0) {
+ ret = DecodeOneShot(name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, encrypted, encryptedLength, nonce,
+ (ULONG)aead->iv_size, 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)
+{
+ 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) != 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 data[123];
+ BYTE nonce[12];
+ 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(nonce) >= 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(nonce, 'n', sizeof(nonce));
+ memset(authData, 'a', sizeof(authData));
+
+ /* Create a decryption context */
+ ctx = new_test_aead_context(aead, 0, key);
+ if (ctx == NULL) {
+ ret = -1;
+ }
+
+ /* Do a simple encrypt using one shot bcrypt */
+ if (ret == 0) {
+ ret = EncodeOneShot(name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, data, 123, nonce, (ULONG)aead->iv_size,
+ 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 data[123];
+ BYTE nonce[12];
+ 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(nonce) >= aead->iv_size);
+ assert(sizeof(data) + authTagLength <= sizeof(encrypted));
+ assert(sizeof(data) + authTagLength <= sizeof(encryptedRef));
+
+ memset(key, 'k', sizeof(key));
+ memset(data, 'd', sizeof(data));
+ memset(nonce, 'n', sizeof(nonce));
+ memset(authData, 'a', sizeof(authData));
+
+ /* Create an encryption context */
+ ctx = new_test_aead_context(aead, 1, key);
+ if (ctx == NULL) {
+ ret = -1;
+ }
+
+ /* Do a simple encrypt using one shot bcrypt */
+ if (ret == 0) {
+ ret = EncodeOneShot(name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, data, 123, nonce, (ULONG)aead->iv_size,
+ 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_for_size(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz)
+{
+ BYTE key[32];
+ BYTE nonce[12];
+ 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(nonce) >= aead->iv_size);
+
+ memset(key, 'k', sizeof(key));
+ memset(nonce, 'n', sizeof(nonce));
+ memset(authData, 'a', sizeof(authData));
+
+ /* Create the encryption contexts */
+ ctx_e = new_test_aead_context(aead, 1, key);
+ ctx_d = new_test_aead_context(aead, 0, key);
+
+ 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_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);
+}
diff --git a/picotlsvs/bcrypt-test/bcrypt-test.vcxproj b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj
new file mode 100644
index 0000000..4c71134
--- /dev/null
+++ b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <ProjectGuid>{7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>bcrypttest</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\picotls;$(ProjectDir);$(ProjectDir)..\..\picotls;$(ProjectDir)..\..\include;$(ProjectDir)..\..\include\picotls;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>picotls-core.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\picotls;$(ProjectDir);$(ProjectDir)..\..\picotls;$(ProjectDir)..\..\include;$(ProjectDir)..\..\include\picotls;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>picotls-core.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\picotls;$(ProjectDir);$(ProjectDir)..\..\picotls;$(ProjectDir)..\..\include;$(ProjectDir)..\..\include\picotls;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>picotls-core.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>$(ProjectDir)..\picotls;$(ProjectDir);$(ProjectDir)..\..\picotls;$(ProjectDir)..\..\include;$(ProjectDir)..\..\include\picotls;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>picotls-core.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="bcrypt-test.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.filters b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.filters
new file mode 100644
index 0000000..6d21ff8
--- /dev/null
+++ b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="bcrypt-test.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.user b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/picotlsvs/bcrypt-test/bcrypt-test.vcxproj.user
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup />
+</Project>
\ No newline at end of file
diff --git a/picotlsvs/picotls-bcrypt/picotls-bcrypt.vcxproj b/picotlsvs/picotls-bcrypt/picotls-bcrypt.vcxproj
index 9867c37..973957a 100644
--- a/picotlsvs/picotls-bcrypt/picotls-bcrypt.vcxproj
+++ b/picotlsvs/picotls-bcrypt/picotls-bcrypt.vcxproj
@@ -26,13 +26,13 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
@@ -45,9 +45,9 @@
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
+ <PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
diff --git a/picotlsvs/picotlsvs.sln b/picotlsvs/picotlsvs.sln
index 8cfb619..ba57589 100644
--- a/picotlsvs/picotlsvs.sln
+++ b/picotlsvs/picotlsvs.sln
@@ -24,6 +24,7 @@
{559AC085-1BEF-450A-A62D-0D370561D596} = {559AC085-1BEF-450A-A62D-0D370561D596}
{499B82B3-F5A5-4C2E-91EF-A2F77CBC33F5} = {499B82B3-F5A5-4C2E-91EF-A2F77CBC33F5}
{56C264BF-822B-4F29-B512-5B26157CA2EC} = {56C264BF-822B-4F29-B512-5B26157CA2EC}
+ {0A0E7AF2-05C8-488B-867C-D83B776B8BF4} = {0A0E7AF2-05C8-488B-867C-D83B776B8BF4}
{497433FE-B252-4985-A504-54EB791F57F4} = {497433FE-B252-4985-A504-54EB791F57F4}
EndProjectSection
EndProject
@@ -45,6 +46,14 @@
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picotls-bcrypt", "picotls-bcrypt\picotls-bcrypt.vcxproj", "{0A0E7AF2-05C8-488B-867C-D83B776B8BF4}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bcrypt-test", "bcrypt-test\bcrypt-test.vcxproj", "{7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {559AC085-1BEF-450A-A62D-0D370561D596} = {559AC085-1BEF-450A-A62D-0D370561D596}
+ {499B82B3-F5A5-4C2E-91EF-A2F77CBC33F5} = {499B82B3-F5A5-4C2E-91EF-A2F77CBC33F5}
+ {0A0E7AF2-05C8-488B-867C-D83B776B8BF4} = {0A0E7AF2-05C8-488B-867C-D83B776B8BF4}
+ {497433FE-B252-4985-A504-54EB791F57F4} = {497433FE-B252-4985-A504-54EB791F57F4}
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -125,6 +134,14 @@
{0A0E7AF2-05C8-488B-867C-D83B776B8BF4}.Release|x64.Build.0 = Release|x64
{0A0E7AF2-05C8-488B-867C-D83B776B8BF4}.Release|x86.ActiveCfg = Release|Win32
{0A0E7AF2-05C8-488B-867C-D83B776B8BF4}.Release|x86.Build.0 = Release|Win32
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Debug|x64.ActiveCfg = Debug|x64
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Debug|x64.Build.0 = Debug|x64
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Debug|x86.ActiveCfg = Debug|Win32
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Debug|x86.Build.0 = Debug|Win32
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Release|x64.ActiveCfg = Release|x64
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Release|x64.Build.0 = Release|x64
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Release|x86.ActiveCfg = Release|Win32
+ {7A04A2BF-03BF-4C3A-9E44-A53B0E90036B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/picotlsvs/picotlsvs/picotlsvs.vcxproj b/picotlsvs/picotlsvs/picotlsvs.vcxproj
index f1190d1..35810aa 100644
--- a/picotlsvs/picotlsvs/picotlsvs.vcxproj
+++ b/picotlsvs/picotlsvs/picotlsvs.vcxproj
@@ -23,7 +23,7 @@
<ProjectGuid>{D0265367-FCCF-47A4-95FD-C33BECAB3486}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>picotlsvs</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/picotlsvs/ptlsbench/ptlsbench.vcxproj b/picotlsvs/ptlsbench/ptlsbench.vcxproj
index 7c4525b..4e06766 100644
--- a/picotlsvs/ptlsbench/ptlsbench.vcxproj
+++ b/picotlsvs/ptlsbench/ptlsbench.vcxproj
@@ -100,7 +100,7 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OPENSSL64DIR);$(OPENSSL64DIR)\lib;$(OutDir)</AdditionalLibraryDirectories>
- <AdditionalDependencies>picotls-core.lib;picotls-openssl.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;libcrypto.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>bcrypt.lib;picotls-core.lib;picotls-openssl.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;libcrypto.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -118,7 +118,7 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OPENSSLDIR);$(OutDir)</AdditionalLibraryDirectories>
- <AdditionalDependencies>picotls-core.lib;picotls-openssl.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;libcrypto.lib;bcrypt.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>bcrypt.lib;picotls-core.lib;picotls-openssl.lib;picotls-bcrypt.lib;picotls-minicrypto.lib;picotls-minicrypto-deps.lib;libcrypto.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
diff --git a/picotlsvs/testopenssl/testopenssl.vcxproj b/picotlsvs/testopenssl/testopenssl.vcxproj
index f1bb883..6c7b156 100644
--- a/picotlsvs/testopenssl/testopenssl.vcxproj
+++ b/picotlsvs/testopenssl/testopenssl.vcxproj
@@ -23,7 +23,7 @@
<ProjectGuid>{8750EE3B-9440-48BF-8D83-7274E94B06A7}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>testopenssl</RootNamespace>
- <WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
diff --git a/t/ptlsbench.c b/t/ptlsbench.c
index fd8cfd0..09292e1 100644
--- a/t/ptlsbench.c
+++ b/t/ptlsbench.c
@@ -38,11 +38,14 @@
#include <openssl/opensslv.h>
#ifdef _WINDOWS
+#include <bcrypt.h>
+#include "picotls/ptlsbcrypt.h"
#ifdef _DEBUG
#define BENCH_MODE "check"
#else
#define BENCH_MODE "release"
#endif
+#include "../lib/ptlsbcrypt.c"
#else
#ifdef PTLS_DEBUG
#define BENCH_MODE "debug"
@@ -242,17 +245,23 @@
const char *algo_name;
ptls_aead_algorithm_t *aead;
ptls_hash_algorithm_t *hash;
+ int enabled_by_defaut;
} ptls_bench_entry_t;
static ptls_bench_entry_t aead_list[] = {
- {"minicrypto", "aes128gcm", &ptls_minicrypto_aes128gcm, &ptls_minicrypto_sha256},
- {"minicrypto", "aes256gcm", &ptls_minicrypto_aes256gcm, &ptls_minicrypto_sha384},
- {"minicrypto", "chacha20poly1305", &ptls_minicrypto_chacha20poly1305, &ptls_minicrypto_sha256},
-#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
- {"openssl", "chacha20poly1305", &ptls_openssl_chacha20poly1305, &ptls_minicrypto_sha256},
+ /* Minicrypto AES disabled by defaut because of atrocious perf */
+ {"minicrypto", "aes128gcm", &ptls_minicrypto_aes128gcm, &ptls_minicrypto_sha256, 0},
+ {"minicrypto", "aes256gcm", &ptls_minicrypto_aes256gcm, &ptls_minicrypto_sha384, 0},
+ {"minicrypto", "chacha20poly1305", &ptls_minicrypto_chacha20poly1305, &ptls_minicrypto_sha256, 1},
+#ifdef _WINDOWS
+ {"ptlsbcrypt", "aes128gcm", &ptls_bcrypt_aes128gcm, &ptls_bcrypt_sha256, 1},
+ {"ptlsbcrypt", "aes256gcm", &ptls_bcrypt_aes256gcm, &ptls_bcrypt_sha384, 1},
#endif
- {"openssl", "aes128gcm", &ptls_openssl_aes128gcm, &ptls_minicrypto_sha256},
- {"openssl", "aes256gcm", &ptls_openssl_aes256gcm, &ptls_minicrypto_sha384}};
+#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
+ {"openssl", "chacha20poly1305", &ptls_openssl_chacha20poly1305, &ptls_minicrypto_sha256, 1},
+#endif
+ {"openssl", "aes128gcm", &ptls_openssl_aes128gcm, &ptls_minicrypto_sha256, 1},
+ {"openssl", "aes256gcm", &ptls_openssl_aes256gcm, &ptls_minicrypto_sha384, 1}};
static size_t nb_aead_list = sizeof(aead_list) / sizeof(ptls_bench_entry_t);
@@ -280,6 +289,7 @@
int main(int argc, char **argv)
{
int ret = 0;
+ int force_all_tests = 0;
uint64_t x = 0xdeadbeef;
uint64_t s = 0;
int basic_ref = bench_basic(&x);
@@ -305,17 +315,24 @@
}
#endif
-
- printf("OS, HW, bits, mode, 10M ops, provider, version, algorithm, N, L, encrypt us, decrypt us, encrypt mbps, decrypt mbps,\n");
-
+ if (argc == 2 && strcmp(argv[1], "-f") == 0) {
+ force_all_tests = 1;
+ } else if (argc > 1) {
+ fprintf(stderr, "Usage: %s [-f]\n Use option \"-f\" to force execution of the slower tests.\n", argv[0]);
+ exit (-1);
+ }
+ printf("OS, HW, bits, mode, 10M ops, provider, version, algorithm, N, L, encrypt us, decrypt us, encrypt mbps, decrypt mbps,\n");
+
for (size_t i = 0; ret == 0 && i < nb_aead_list; i++) {
- ret = bench_run_aead(OS, HW, basic_ref, x, aead_list[i].provider, aead_list[i].algo_name, aead_list[i].aead, aead_list[i].hash, 1000,
- 1500, &s);
+ if (aead_list[i].enabled_by_defaut || force_all_tests) {
+ ret = bench_run_aead(OS, HW, basic_ref, x, aead_list[i].provider, aead_list[i].algo_name, aead_list[i].aead,
+ aead_list[i].hash, 1000, 1500, &s);
+ }
}
/* Gratuitous test, designed to ensure that the initial computation
- * of the basic reference benchmark is not optimised away. */
+ * of the basic reference benchmark is not optimized away. */
if (s == 0){
printf("Unexpected value of test sum s = %llx\n", (unsigned long long)s);
}