#include <assert.h>
#include <openssl/aes.h>
#include "evp_locl.h"
-#include <openssl/modes.h>
+#include "modes_lcl.h"
#include <openssl/rand.h>
static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
static const EVP_CIPHER aes_128_ctr_cipher=
{
NID_aes_128_ctr,1,16,16,
- EVP_CIPH_CTR_MODE,
+ EVP_CIPH_CTR_MODE|EVP_CIPH_FLAG_FIPS,
aes_init_key,
aes_counter,
NULL,
static const EVP_CIPHER aes_192_ctr_cipher=
{
NID_aes_192_ctr,1,24,16,
- EVP_CIPH_CTR_MODE,
+ EVP_CIPH_CTR_MODE|EVP_CIPH_FLAG_FIPS,
aes_init_key,
aes_counter,
NULL,
static const EVP_CIPHER aes_256_ctr_cipher=
{
NID_aes_256_ctr,1,32,16,
- EVP_CIPH_CTR_MODE,
+ EVP_CIPH_CTR_MODE|EVP_CIPH_FLAG_FIPS,
aes_init_key,
aes_counter,
NULL,
int key_set;
/* Set if an iv is set */
int iv_set;
- /* Pointer to GCM128_CTX: FIXME actual structure later */
- GCM128_CONTEXT *gcm;
+ GCM128_CONTEXT gcm;
/* Temporary IV store */
unsigned char *iv;
/* IV length */
int ivlen;
- /* Tag to verify */
- unsigned char tag[16];
int taglen;
/* It is OK to generate IVs */
int iv_gen;
static int aes_gcm_cleanup(EVP_CIPHER_CTX *c)
{
EVP_AES_GCM_CTX *gctx = c->cipher_data;
- if (gctx->gcm)
- CRYPTO_gcm128_release(gctx->gcm);
+ OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm));
if (gctx->iv != c->iv)
OPENSSL_free(gctx->iv);
return 1;
switch (type)
{
case EVP_CTRL_INIT:
- gctx->gcm = NULL;
gctx->key_set = 0;
gctx->iv_set = 0;
gctx->ivlen = c->cipher->iv_len;
case EVP_CTRL_GCM_SET_TAG:
if (arg <= 0 || arg > 16 || c->encrypt)
return 0;
- memcpy(gctx->tag, ptr, arg);
+ memcpy(c->buf, ptr, arg);
gctx->taglen = arg;
return 1;
case EVP_CTRL_GCM_GET_TAG:
if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0)
return 0;
- memcpy(ptr, gctx->tag, arg);
+ memcpy(ptr, c->buf, arg);
return 1;
case EVP_CTRL_GCM_SET_IV_FIXED:
case EVP_CTRL_GCM_IV_GEN:
if (gctx->iv_gen == 0 || gctx->key_set == 0)
return 0;
- CRYPTO_gcm128_setiv(gctx->gcm, gctx->iv, gctx->ivlen);
+ CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen);
memcpy(ptr, gctx->iv, gctx->ivlen);
/* Invocation field will be at least 8 bytes in size and
* so no need to check wrap around or increment more than
if (key)
{
AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks);
- if (!gctx->gcm)
- {
- gctx->gcm =
- CRYPTO_gcm128_new(&gctx->ks, (block128_f)AES_encrypt);
- if (!gctx->gcm)
- return 0;
- }
- else
- CRYPTO_gcm128_init(gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
+ CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
/* If we have an iv can set it directly, otherwise use
* saved IV.
*/
iv = gctx->iv;
if (iv)
{
- CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen);
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
gctx->iv_set = 1;
}
gctx->key_set = 1;
{
/* If key set use IV, otherwise copy */
if (gctx->key_set)
- CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen);
+ CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen);
else
memcpy(gctx->iv, iv, gctx->ivlen);
gctx->iv_set = 1;
{
if (out == NULL)
{
- if (CRYPTO_gcm128_aad(gctx->gcm, in, len))
+ if (CRYPTO_gcm128_aad(&gctx->gcm, in, len))
return -1;
}
else if (ctx->encrypt)
{
- if (CRYPTO_gcm128_encrypt(gctx->gcm, in, out, len))
+ if (CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, len))
return -1;
}
else
{
- if (CRYPTO_gcm128_decrypt(gctx->gcm, in, out, len))
+ if (CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, len))
return -1;
}
return len;
{
if (!ctx->encrypt)
{
- if (CRYPTO_gcm128_finish(gctx->gcm,
- gctx->tag, gctx->taglen) != 0)
+ if (CRYPTO_gcm128_finish(&gctx->gcm,
+ ctx->buf, gctx->taglen) != 0)
return -1;
gctx->iv_set = 0;
return 0;
}
- CRYPTO_gcm128_tag(gctx->gcm, gctx->tag, 16);
+ CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, 16);
gctx->taglen = 16;
/* Don't reuse the IV */
gctx->iv_set = 0;
const EVP_CIPHER *EVP_aes_256_gcm (void)
{ return &aes_256_gcm_cipher; }
-
+
+typedef struct
+ {
+ /* AES key schedules to use */
+ AES_KEY ks1, ks2;
+ XTS128_CONTEXT xts;
+ } EVP_AES_XTS_CTX;
+
+static int aes_xts_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
+ {
+ EVP_AES_XTS_CTX *xctx = c->cipher_data;
+ if (type != EVP_CTRL_INIT)
+ return -1;
+ /* key1 and key2 are used as an indicator both key and IV are set */
+ xctx->xts.key1 = NULL;
+ xctx->xts.key2 = NULL;
+ return 1;
+ }
+
+static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+ {
+ EVP_AES_XTS_CTX *xctx = ctx->cipher_data;
+ if (!iv && !key)
+ return 1;
+
+ if (key)
+ {
+ /* key_len is two AES keys */
+ if (ctx->encrypt)
+ {
+ AES_set_encrypt_key(key, ctx->key_len * 4, &xctx->ks1);
+ xctx->xts.block1 = (block128_f)AES_encrypt;
+ }
+ else
+ {
+ AES_set_decrypt_key(key, ctx->key_len * 4, &xctx->ks1);
+ xctx->xts.block1 = (block128_f)AES_decrypt;
+ }
+
+ AES_set_encrypt_key(key + ctx->key_len/2,
+ ctx->key_len * 4, &xctx->ks2);
+ xctx->xts.block2 = (block128_f)AES_encrypt;
+
+ xctx->xts.key1 = &xctx->ks1;
+ }
+
+ if (iv)
+ {
+ xctx->xts.key2 = &xctx->ks2;
+ memcpy(ctx->iv, iv, 16);
+ }
+
+ return 1;
+ }
+
+static int aes_xts(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+ {
+ EVP_AES_XTS_CTX *xctx = ctx->cipher_data;
+ if (!xctx->xts.key1 || !xctx->xts.key2)
+ return -1;
+ if (!out || !in)
+ return -1;
+#ifdef OPENSSL_FIPS
+ /* Requirement of SP800-38E */
+ if (FIPS_mode() && !(ctx->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW) &&
+ (len > (1L<<20)*16))
+ {
+ EVPerr(EVP_F_AES_XTS, EVP_R_TOO_LARGE);
+ return -1;
+ }
+#endif
+ if (CRYPTO_xts128_encrypt(&xctx->xts, ctx->iv, in, out, len,
+ ctx->encrypt))
+ return -1;
+ return len;
+ }
+
+static const EVP_CIPHER aes_128_xts_cipher=
+ {
+ NID_aes_128_xts,16,32,16,
+ EVP_CIPH_XTS_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_xts_init_key,
+ aes_xts,
+ 0,
+ sizeof(EVP_AES_XTS_CTX),
+ NULL,
+ NULL,
+ aes_xts_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_128_xts (void)
+{ return &aes_128_xts_cipher; }
+
+static const EVP_CIPHER aes_256_xts_cipher=
+ {
+ NID_aes_256_xts,16,64,16,
+ EVP_CIPH_XTS_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_xts_init_key,
+ aes_xts,
+ 0,
+ sizeof(EVP_AES_XTS_CTX),
+ NULL,
+ NULL,
+ aes_xts_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_256_xts (void)
+{ return &aes_256_xts_cipher; }
+
+typedef struct
+ {
+ /* AES key schedule to use */
+ AES_KEY ks;
+ /* Set if key initialised */
+ int key_set;
+ /* Set if an iv is set */
+ int iv_set;
+ /* Set if tag is valid */
+ int tag_set;
+ /* Set if message length set */
+ int len_set;
+ /* L and M parameters from RFC3610 */
+ int L, M;
+ CCM128_CONTEXT ccm;
+ } EVP_AES_CCM_CTX;
+
+static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
+ {
+ EVP_AES_CCM_CTX *cctx = c->cipher_data;
+ switch (type)
+ {
+ case EVP_CTRL_INIT:
+ cctx->key_set = 0;
+ cctx->iv_set = 0;
+ cctx->L = 8;
+ cctx->M = 12;
+ cctx->tag_set = 0;
+ cctx->len_set = 0;
+ return 1;
+
+ case EVP_CTRL_CCM_SET_IVLEN:
+ arg = 15 - arg;
+ case EVP_CTRL_CCM_SET_L:
+ if (arg < 2 || arg > 8)
+ return 0;
+ cctx->L = arg;
+ return 1;
+
+ case EVP_CTRL_CCM_SET_TAG:
+ if ((arg & 1) || arg < 4 || arg > 16)
+ return 0;
+ if ((c->encrypt && ptr) || (!c->encrypt && !ptr))
+ return 0;
+ if (ptr)
+ {
+ cctx->tag_set = 1;
+ memcpy(c->buf, ptr, arg);
+ }
+ cctx->M = arg;
+ return 1;
+
+ case EVP_CTRL_CCM_GET_TAG:
+ if (!c->encrypt || !cctx->tag_set)
+ return 0;
+ if(CRYPTO_ccm128_tag(&cctx->ccm, ptr, (size_t)arg))
+ return 0;
+ cctx->tag_set = 0;
+ cctx->iv_set = 0;
+ cctx->len_set = 0;
+ return 1;
+
+ default:
+ return -1;
+
+ }
+ }
+
+static int aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc)
+ {
+ EVP_AES_CCM_CTX *cctx = ctx->cipher_data;
+ if (!iv && !key)
+ return 1;
+ if (key)
+ {
+ AES_set_encrypt_key(key, ctx->key_len * 8, &cctx->ks);
+ CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L,
+ &cctx->ks, (block128_f)AES_encrypt);
+ cctx->key_set = 1;
+ }
+ if (iv)
+ {
+ memcpy(ctx->iv, iv, 15 - cctx->L);
+ cctx->iv_set = 1;
+ }
+ return 1;
+ }
+
+static int aes_ccm(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t len)
+ {
+ EVP_AES_CCM_CTX *cctx = ctx->cipher_data;
+ CCM128_CONTEXT *ccm = &cctx->ccm;
+ /* If not set up, return error */
+ if (!cctx->iv_set && !cctx->key_set)
+ return -1;
+ if (!ctx->encrypt && !cctx->tag_set)
+ return -1;
+ if (!out)
+ {
+ if (!in)
+ {
+ if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L,len))
+ return -1;
+ cctx->len_set = 1;
+ return len;
+ }
+ /* If have AAD need message length */
+ if (!cctx->len_set && len)
+ return -1;
+ CRYPTO_ccm128_aad(ccm, in, len);
+ return len;
+ }
+ /* EVP_*Final() doesn't return any data */
+ if (!in)
+ return 0;
+ /* If not set length yet do it */
+ if (!cctx->len_set)
+ {
+ if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L, len))
+ return -1;
+ cctx->len_set = 1;
+ }
+ if (ctx->encrypt)
+ {
+ if (CRYPTO_ccm128_encrypt(ccm, in, out, len))
+ return -1;
+ cctx->tag_set = 1;
+ return len;
+ }
+ else
+ {
+ int rv = -1;
+ if (!CRYPTO_ccm128_decrypt(ccm, in, out, len))
+ {
+ unsigned char tag[16];
+ if (!CRYPTO_ccm128_tag(ccm, tag, cctx->M))
+ {
+ if (!memcmp(tag, ctx->buf, cctx->M))
+ rv = len;
+ }
+ }
+ if (rv == -1)
+ OPENSSL_cleanse(out, len);
+ cctx->iv_set = 0;
+ cctx->tag_set = 0;
+ cctx->len_set = 0;
+ return rv;
+ }
+
+ }
+
+static const EVP_CIPHER aes_128_ccm_cipher=
+ {
+ NID_aes_128_ccm,1,16,12,
+ EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_ccm_init_key,
+ aes_ccm,
+ 0,
+ sizeof(EVP_AES_CCM_CTX),
+ NULL,
+ NULL,
+ aes_ccm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_128_ccm (void)
+{ return &aes_128_ccm_cipher; }
+
+static const EVP_CIPHER aes_192_ccm_cipher=
+ {
+ NID_aes_128_ccm,1,24,12,
+ EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_ccm_init_key,
+ aes_ccm,
+ 0,
+ sizeof(EVP_AES_CCM_CTX),
+ NULL,
+ NULL,
+ aes_ccm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_192_ccm (void)
+{ return &aes_192_ccm_cipher; }
+
+static const EVP_CIPHER aes_256_ccm_cipher=
+ {
+ NID_aes_128_ccm,1,32,12,
+ EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1
+ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER
+ | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT,
+ aes_ccm_init_key,
+ aes_ccm,
+ 0,
+ sizeof(EVP_AES_CCM_CTX),
+ NULL,
+ NULL,
+ aes_ccm_ctrl,
+ NULL
+ };
+
+const EVP_CIPHER *EVP_aes_256_ccm (void)
+{ return &aes_256_ccm_cipher; }
+
#endif