Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 76 additions & 31 deletions src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,48 @@
#include <stdbool.h>
#include "crypto.h"

#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX *HMAC_CTX_new(void)
{
HMAC_CTX *ctx;

ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
if (!ctx) return NULL;

HMAC_CTX_init(ctx);

return ctx;
}

void HMAC_CTX_free(HMAC_CTX *ctx)
{
if (ctx == NULL) return;

HMAC_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}

EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
{
EVP_CIPHER_CTX *ctx;

ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX));
if (!ctx) return NULL;

EVP_CIPHER_CTX_init(ctx);

return ctx;
}

void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
{
if (ctx == NULL) return;

EVP_CIPHER_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
#endif

struct seal_key {
const EVP_CIPHER *cipher;
const EVP_MD *md;
Expand All @@ -29,7 +71,7 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
goto done;
}

keylen = n->cipher->key_len;
keylen = EVP_CIPHER_key_length(n->cipher);

n->md = EVP_sha256();
if (!n->md) {
Expand Down Expand Up @@ -81,24 +123,25 @@ apr_status_t SEAL_KEY_CREATE(apr_pool_t *p, struct seal_key **skey,
apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer,
struct databuf *result)
{
HMAC_CTX hmac_ctx = { 0 };
HMAC_CTX *hmac_ctx;
unsigned int len;
int ret;
int ret = 0;

/* now MAC the buffer */
HMAC_CTX_init(&hmac_ctx);
hmac_ctx = HMAC_CTX_new();
if (!hmac_ctx) goto done;

ret = HMAC_Init_ex(&hmac_ctx, skey->hkey,
skey->cipher->key_len, skey->md, NULL);
ret = HMAC_Init_ex(hmac_ctx, skey->hkey,
EVP_CIPHER_key_length(skey->cipher), skey->md, NULL);
if (ret == 0) goto done;

ret = HMAC_Update(&hmac_ctx, buffer->value, buffer->length);
ret = HMAC_Update(hmac_ctx, buffer->value, buffer->length);
if (ret == 0) goto done;

ret = HMAC_Final(&hmac_ctx, result->value, &len);
ret = HMAC_Final(hmac_ctx, result->value, &len);

done:
HMAC_CTX_cleanup(&hmac_ctx);
HMAC_CTX_free(hmac_ctx);
if (ret == 0) return EFAULT;

result->length = len;
Expand All @@ -108,15 +151,15 @@ apr_status_t HMAC_BUFFER(struct seal_key *skey, struct databuf *buffer,
apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
struct databuf *plain, struct databuf *cipher)
{
int blksz = skey->cipher->block_size;
int blksz = EVP_CIPHER_block_size(skey->cipher);
apr_status_t err = EFAULT;
EVP_CIPHER_CTX ctx = { 0 };
EVP_CIPHER_CTX *ctx;
uint8_t rbuf[blksz];
struct databuf hmacbuf;
int outlen, totlen;
int ret;

EVP_CIPHER_CTX_init(&ctx);
ctx = EVP_CIPHER_CTX_new();

/* confounder to avoid exposing random numbers directly to clients
* as IVs */
Expand All @@ -126,30 +169,30 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
if (cipher->length == 0) {
/* add space for confounder and padding and MAC */
cipher->length = (plain->length / blksz + 2) * blksz;
cipher->value = apr_palloc(p, cipher->length + skey->md->md_size);
cipher->value = apr_palloc(p, cipher->length + EVP_MD_size(skey->md));
if (!cipher->value) {
err = ENOMEM;
goto done;
}
}

ret = EVP_EncryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
ret = EVP_EncryptInit_ex(ctx, skey->cipher, NULL, skey->ekey, NULL);
if (ret == 0) goto done;
totlen = 0;

outlen = cipher->length;
ret = EVP_EncryptUpdate(&ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
ret = EVP_EncryptUpdate(ctx, cipher->value, &outlen, rbuf, sizeof(rbuf));
if (ret == 0) goto done;
totlen += outlen;

outlen = cipher->length - totlen;
ret = EVP_EncryptUpdate(&ctx, &cipher->value[totlen], &outlen,
ret = EVP_EncryptUpdate(ctx, &cipher->value[totlen], &outlen,
plain->value, plain->length);
if (ret == 0) goto done;
totlen += outlen;

outlen = cipher->length - totlen;
ret = EVP_EncryptFinal_ex(&ctx, &cipher->value[totlen], &outlen);
ret = EVP_EncryptFinal_ex(ctx, &cipher->value[totlen], &outlen);
if (ret == 0) goto done;
totlen += outlen;

Expand All @@ -163,36 +206,38 @@ apr_status_t SEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
err = 0;

done:
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_CIPHER_CTX_free(ctx);
return err;
}

apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
struct databuf *cipher, struct databuf *plain)
{
apr_status_t err = EFAULT;
EVP_CIPHER_CTX ctx = { 0 };
unsigned char mac[skey->md->md_size];
EVP_CIPHER_CTX *ctx = NULL;
int blksz = EVP_CIPHER_block_size(skey->cipher);
int md_size = EVP_MD_size(skey->md);
unsigned char mac[md_size];
struct databuf hmacbuf;
int outlen, totlen;
volatile bool equal = true;
int ret, i;

/* check MAC first */
cipher->length -= skey->md->md_size;
cipher->length -= md_size;
hmacbuf.value = mac;
ret = HMAC_BUFFER(skey, cipher, &hmacbuf);
if (ret != 0) goto done;

if (hmacbuf.length != skey->md->md_size) goto done;
for (i = 0; i < skey->md->md_size; i++) {
if (hmacbuf.length != md_size) goto done;
for (i = 0; i < md_size; i++) {
if (cipher->value[cipher->length + i] != mac[i]) equal = false;
/* not breaking intentionally,
* or we would allow an oracle attack */
}
if (!equal) goto done;

EVP_CIPHER_CTX_init(&ctx);
ctx = EVP_CIPHER_CTX_new();

if (plain->length == 0) {
plain->length = cipher->length;
Expand All @@ -203,37 +248,37 @@ apr_status_t UNSEAL_BUFFER(apr_pool_t *p, struct seal_key *skey,
}
}

ret = EVP_DecryptInit_ex(&ctx, skey->cipher, NULL, skey->ekey, NULL);
ret = EVP_DecryptInit_ex(ctx, skey->cipher, NULL, skey->ekey, NULL);
if (ret == 0) goto done;

totlen = 0;
outlen = plain->length;
ret = EVP_DecryptUpdate(&ctx, plain->value, &outlen,
ret = EVP_DecryptUpdate(ctx, plain->value, &outlen,
cipher->value, cipher->length);
if (ret == 0) goto done;

totlen += outlen;
outlen = plain->length - totlen;
ret = EVP_DecryptFinal_ex(&ctx, plain->value, &outlen);
ret = EVP_DecryptFinal_ex(ctx, plain->value, &outlen);
if (ret == 0) goto done;

totlen += outlen;
/* now remove the confounder */
totlen -= skey->cipher->block_size;
memmove(plain->value, plain->value + skey->cipher->block_size, totlen);
totlen -= blksz;
memmove(plain->value, plain->value + blksz, totlen);

plain->length = totlen;
err = 0;

done:
EVP_CIPHER_CTX_cleanup(&ctx);
EVP_CIPHER_CTX_free(ctx);
return err;
}

int get_mac_size(struct seal_key *skey)
{
if (skey) {
return skey->md->md_size;
return EVP_MD_size(skey->md);
} else {
return 0;
}
Expand Down