aes: add support for GCM Galois Counter Mode (#106)
* aes: add support for GCM Galois Counter Mode (AEAD) * add tag functions * variable length IV * set crypt direction * remove usage of old AES api * aes: set IV using EVP_CipherInit_ex
This commit is contained in:
parent
624187196d
commit
b42724a64b
4 changed files with 190 additions and 98 deletions
|
@ -11,14 +11,17 @@
|
|||
|
||||
/** AES mode */
|
||||
enum aes_mode {
|
||||
AES_MODE_CTR /**< AES Counter mode (CTR) */
|
||||
AES_MODE_CTR, /**< AES Counter mode (CTR) */
|
||||
AES_MODE_GCM, /**< AES Galois Counter Mode (GCM) */
|
||||
};
|
||||
|
||||
struct aes;
|
||||
|
||||
int aes_alloc(struct aes **stp, enum aes_mode mode,
|
||||
const uint8_t *key, size_t key_bits,
|
||||
const uint8_t iv[AES_BLOCK_SIZE]);
|
||||
void aes_set_iv(struct aes *aes, const uint8_t iv[AES_BLOCK_SIZE]);
|
||||
const uint8_t *iv);
|
||||
void aes_set_iv(struct aes *aes, const uint8_t *iv);
|
||||
int aes_encr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len);
|
||||
int aes_decr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len);
|
||||
int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen);
|
||||
int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen);
|
||||
|
|
|
@ -30,7 +30,7 @@ static void destructor(void *arg)
|
|||
|
||||
int aes_alloc(struct aes **stp, enum aes_mode mode,
|
||||
const uint8_t *key, size_t key_bits,
|
||||
const uint8_t iv[AES_BLOCK_SIZE])
|
||||
const uint8_t *iv)
|
||||
{
|
||||
struct aes *st;
|
||||
size_t key_bytes = key_bits / 8;
|
||||
|
@ -75,7 +75,7 @@ int aes_alloc(struct aes **stp, enum aes_mode mode,
|
|||
}
|
||||
|
||||
|
||||
void aes_set_iv(struct aes *st, const uint8_t iv[AES_BLOCK_SIZE])
|
||||
void aes_set_iv(struct aes *st, const uint8_t *iv)
|
||||
{
|
||||
CCCryptorStatus status;
|
||||
|
||||
|
@ -123,3 +123,23 @@ int aes_decr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
|
|||
{
|
||||
return aes_encr(st, out, in, len);
|
||||
}
|
||||
|
||||
|
||||
int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
|
||||
{
|
||||
(void)aes;
|
||||
(void)tag;
|
||||
(void)taglen;
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
|
||||
{
|
||||
(void)aes;
|
||||
(void)tag;
|
||||
(void)taglen;
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
|
|
@ -13,14 +13,60 @@
|
|||
#include <re_aes.h>
|
||||
|
||||
|
||||
#ifdef EVP_CIPH_CTR_MODE
|
||||
|
||||
|
||||
struct aes {
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
enum aes_mode mode;
|
||||
bool encr;
|
||||
};
|
||||
|
||||
|
||||
static const EVP_CIPHER *aes_cipher(enum aes_mode mode, size_t key_bits)
|
||||
{
|
||||
if (mode == AES_MODE_CTR) {
|
||||
|
||||
switch (key_bits) {
|
||||
|
||||
case 128: return EVP_aes_128_ctr();
|
||||
case 192: return EVP_aes_192_ctr();
|
||||
case 256: return EVP_aes_256_ctr();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (mode == AES_MODE_GCM) {
|
||||
|
||||
switch (key_bits) {
|
||||
|
||||
case 128: return EVP_aes_128_gcm();
|
||||
case 256: return EVP_aes_256_gcm();
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline bool set_crypt_dir(struct aes *aes, bool encr)
|
||||
{
|
||||
if (aes->encr != encr) {
|
||||
|
||||
/* update the encrypt/decrypt direction */
|
||||
if (!EVP_CipherInit_ex(aes->ctx, NULL, NULL,
|
||||
NULL, NULL, encr)) {
|
||||
ERR_clear_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
aes->encr = encr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void destructor(void *arg)
|
||||
{
|
||||
struct aes *st = arg;
|
||||
|
@ -38,7 +84,7 @@ static void destructor(void *arg)
|
|||
|
||||
int aes_alloc(struct aes **aesp, enum aes_mode mode,
|
||||
const uint8_t *key, size_t key_bits,
|
||||
const uint8_t iv[AES_BLOCK_SIZE])
|
||||
const uint8_t *iv)
|
||||
{
|
||||
const EVP_CIPHER *cipher;
|
||||
struct aes *st;
|
||||
|
@ -47,13 +93,17 @@ int aes_alloc(struct aes **aesp, enum aes_mode mode,
|
|||
if (!aesp || !key)
|
||||
return EINVAL;
|
||||
|
||||
if (mode != AES_MODE_CTR)
|
||||
cipher = aes_cipher(mode, key_bits);
|
||||
if (!cipher)
|
||||
return ENOTSUP;
|
||||
|
||||
st = mem_zalloc(sizeof(*st), destructor);
|
||||
if (!st)
|
||||
return ENOMEM;
|
||||
|
||||
st->mode = mode;
|
||||
st->encr = true;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
st->ctx = EVP_CIPHER_CTX_new();
|
||||
if (!st->ctx) {
|
||||
|
@ -72,17 +122,6 @@ int aes_alloc(struct aes **aesp, enum aes_mode mode,
|
|||
EVP_CIPHER_CTX_init(st->ctx);
|
||||
#endif
|
||||
|
||||
switch (key_bits) {
|
||||
|
||||
case 128: cipher = EVP_aes_128_ctr(); break;
|
||||
case 192: cipher = EVP_aes_192_ctr(); break;
|
||||
case 256: cipher = EVP_aes_256_ctr(); break;
|
||||
default:
|
||||
re_fprintf(stderr, "aes: unknown key: %zu bits\n", key_bits);
|
||||
err = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = EVP_EncryptInit_ex(st->ctx, cipher, NULL, key, iv);
|
||||
if (!r) {
|
||||
ERR_clear_error();
|
||||
|
@ -99,14 +138,14 @@ int aes_alloc(struct aes **aesp, enum aes_mode mode,
|
|||
}
|
||||
|
||||
|
||||
void aes_set_iv(struct aes *aes, const uint8_t iv[AES_BLOCK_SIZE])
|
||||
void aes_set_iv(struct aes *aes, const uint8_t *iv)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!aes || !iv)
|
||||
return;
|
||||
|
||||
r = EVP_EncryptInit_ex(aes->ctx, NULL, NULL, NULL, iv);
|
||||
r = EVP_CipherInit_ex(aes->ctx, NULL, NULL, NULL, iv, -1);
|
||||
if (!r)
|
||||
ERR_clear_error();
|
||||
}
|
||||
|
@ -116,9 +155,12 @@ int aes_encr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
|
|||
{
|
||||
int c_len = (int)len;
|
||||
|
||||
if (!aes || !out || !in)
|
||||
if (!aes || !in)
|
||||
return EINVAL;
|
||||
|
||||
if (!set_crypt_dir(aes, true))
|
||||
return EPROTO;
|
||||
|
||||
if (!EVP_EncryptUpdate(aes->ctx, out, &c_len, in, (int)len)) {
|
||||
ERR_clear_error();
|
||||
return EPROTO;
|
||||
|
@ -128,91 +170,98 @@ int aes_encr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
|
|||
}
|
||||
|
||||
|
||||
#else /* EVP_CIPH_CTR_MODE */
|
||||
|
||||
|
||||
struct aes {
|
||||
AES_KEY key;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
|
||||
static void destructor(void *arg)
|
||||
int aes_decr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
|
||||
{
|
||||
struct aes *st = arg;
|
||||
int c_len = (int)len;
|
||||
|
||||
memset(&st->key, 0, sizeof(st->key));
|
||||
}
|
||||
|
||||
|
||||
int aes_alloc(struct aes **aesp, enum aes_mode mode,
|
||||
const uint8_t *key, size_t key_bits,
|
||||
const uint8_t iv[AES_BLOCK_SIZE])
|
||||
{
|
||||
struct aes *st;
|
||||
int err = 0, r;
|
||||
|
||||
if (!aesp || !key)
|
||||
if (!aes || !in)
|
||||
return EINVAL;
|
||||
|
||||
if (mode != AES_MODE_CTR)
|
||||
return ENOTSUP;
|
||||
if (!set_crypt_dir(aes, false))
|
||||
return EPROTO;
|
||||
|
||||
st = mem_zalloc(sizeof(*st), destructor);
|
||||
if (!st)
|
||||
return ENOMEM;
|
||||
|
||||
r = AES_set_encrypt_key(key, (int)key_bits, &st->key);
|
||||
if (r != 0) {
|
||||
err = EPROTO;
|
||||
goto out;
|
||||
if (!EVP_DecryptUpdate(aes->ctx, out, &c_len, in, (int)len)) {
|
||||
ERR_clear_error();
|
||||
return EPROTO;
|
||||
}
|
||||
if (iv)
|
||||
memcpy(st->iv, iv, sizeof(st->iv));
|
||||
|
||||
out:
|
||||
if (err)
|
||||
mem_deref(st);
|
||||
else
|
||||
*aesp = st;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void aes_set_iv(struct aes *aes, const uint8_t iv[AES_BLOCK_SIZE])
|
||||
{
|
||||
if (!aes)
|
||||
return;
|
||||
|
||||
if (iv)
|
||||
memcpy(aes->iv, iv, sizeof(aes->iv));
|
||||
}
|
||||
|
||||
|
||||
int aes_encr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
|
||||
{
|
||||
unsigned char ec[AES_BLOCK_SIZE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
unsigned int num = 0;
|
||||
|
||||
if (!aes || !out || !in)
|
||||
return EINVAL;
|
||||
|
||||
AES_ctr128_encrypt(in, out, len, &aes->key, aes->iv, ec, &num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* EVP_CIPH_CTR_MODE */
|
||||
|
||||
|
||||
/*
|
||||
* Common code:
|
||||
/**
|
||||
* Get the authentication tag for an AEAD cipher (e.g. GCM)
|
||||
*
|
||||
* @param aes AES Context
|
||||
* @param tag Authentication tag
|
||||
* @param taglen Length of Authentication tag
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*/
|
||||
|
||||
|
||||
int aes_decr(struct aes *aes, uint8_t *out, const uint8_t *in, size_t len)
|
||||
int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
|
||||
{
|
||||
return aes_encr(aes, out, in, len);
|
||||
int tmplen;
|
||||
|
||||
if (!aes || !tag || !taglen)
|
||||
return EINVAL;
|
||||
|
||||
switch (aes->mode) {
|
||||
|
||||
case AES_MODE_GCM:
|
||||
if (!EVP_EncryptFinal_ex(aes->ctx, NULL, &tmplen)) {
|
||||
ERR_clear_error();
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
if (!EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_GET_TAG,
|
||||
(int)taglen, tag)) {
|
||||
ERR_clear_error();
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Authenticate a decryption tag for an AEAD cipher (e.g. GCM)
|
||||
*
|
||||
* @param aes AES Context
|
||||
* @param tag Authentication tag
|
||||
* @param taglen Length of Authentication tag
|
||||
*
|
||||
* @return 0 if success, otherwise errorcode
|
||||
*
|
||||
* @retval EAUTH if authentication failed
|
||||
*/
|
||||
int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
|
||||
{
|
||||
int tmplen;
|
||||
|
||||
if (!aes || !tag || !taglen)
|
||||
return EINVAL;
|
||||
|
||||
switch (aes->mode) {
|
||||
|
||||
case AES_MODE_GCM:
|
||||
if (!EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_SET_TAG,
|
||||
(int)taglen, (void *)tag)) {
|
||||
ERR_clear_error();
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
if (EVP_DecryptFinal_ex(aes->ctx, NULL, &tmplen) <= 0) {
|
||||
ERR_clear_error();
|
||||
return EAUTH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,3 +45,23 @@ int aes_decr(struct aes *st, uint8_t *out, const uint8_t *in, size_t len)
|
|||
(void)len;
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int aes_get_authtag(struct aes *aes, uint8_t *tag, size_t taglen)
|
||||
{
|
||||
(void)aes;
|
||||
(void)tag;
|
||||
(void)taglen;
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
||||
|
||||
int aes_authenticate(struct aes *aes, const uint8_t *tag, size_t taglen)
|
||||
{
|
||||
(void)aes;
|
||||
(void)tag;
|
||||
(void)taglen;
|
||||
|
||||
return ENOSYS;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue