Add AES-CCM encryption, and plumb into OCF.
This commit essentially has three parts: * Add the AES-CCM encryption hooks. This is in and of itself fairly small, as there is only a small difference between CCM and the other ICM-based algorithms. * Hook the code into the OpenCrypto framework. This is the bulk of the changes, as the algorithm type has to be checked for, and the differences between it and GCM dealt with. * Update the cryptocheck tool to be aware of it. This is invaluable for confirming that the code works. This is a software-only implementation, meaning that the performance is very low. Sponsored by: iXsystems Inc. Differential Revision: https://reviews.freebsd.org/D19090
This commit is contained in:
parent
a99bc4c3eb
commit
507281e55e
@ -444,6 +444,9 @@ cryptof_ioctl(
|
||||
case CRYPTO_CHACHA20:
|
||||
txform = &enc_xform_chacha20;
|
||||
break;
|
||||
case CRYPTO_AES_CCM_16:
|
||||
txform = &enc_xform_ccm;
|
||||
break;
|
||||
|
||||
default:
|
||||
CRYPTDEB("invalid cipher");
|
||||
@ -488,6 +491,25 @@ cryptof_ioctl(
|
||||
thash = &auth_hash_nist_gmac_aes_256;
|
||||
break;
|
||||
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
switch (sop->keylen) {
|
||||
case 16:
|
||||
thash = &auth_hash_ccm_cbc_mac_128;
|
||||
break;
|
||||
case 24:
|
||||
thash = &auth_hash_ccm_cbc_mac_192;
|
||||
break;
|
||||
case 32:
|
||||
thash = &auth_hash_ccm_cbc_mac_256;
|
||||
break;
|
||||
default:
|
||||
CRYPTDEB("Invalid CBC MAC key size %d",
|
||||
sop->keylen);
|
||||
SDT_PROBE1(opencrypto, dev, ioctl,
|
||||
error, __LINE__);
|
||||
return (EINVAL);
|
||||
}
|
||||
break;
|
||||
#ifdef notdef
|
||||
case CRYPTO_MD5:
|
||||
thash = &auth_hash_md5;
|
||||
@ -1003,12 +1025,13 @@ cryptodev_aead(
|
||||
}
|
||||
|
||||
/*
|
||||
* For GCM, crd_len covers only the AAD. For other ciphers
|
||||
* For GCM/CCM, crd_len covers only the AAD. For other ciphers
|
||||
* chained with an HMAC, crd_len covers both the AAD and the
|
||||
* cipher text.
|
||||
*/
|
||||
crda->crd_skip = 0;
|
||||
if (cse->cipher == CRYPTO_AES_NIST_GCM_16)
|
||||
if (cse->cipher == CRYPTO_AES_NIST_GCM_16 ||
|
||||
cse->cipher == CRYPTO_AES_CCM_16)
|
||||
crda->crd_len = caead->aadlen;
|
||||
else
|
||||
crda->crd_len = caead->aadlen + caead->len;
|
||||
|
@ -133,6 +133,7 @@
|
||||
|
||||
#define ARC4_IV_LEN 1
|
||||
#define AES_GCM_IV_LEN 12
|
||||
#define AES_CCM_IV_LEN 12
|
||||
#define AES_XTS_IV_LEN 8
|
||||
#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
|
||||
|
||||
@ -204,7 +205,8 @@
|
||||
#define CRYPTO_SHA2_512 37
|
||||
#define CRYPTO_POLY1305 38
|
||||
#define CRYPTO_AES_CCM_CBC_MAC 39 /* auth side */
|
||||
#define CRYPTO_ALGORITHM_MAX 39 /* Keep updated - see below */
|
||||
#define CRYPTO_AES_CCM_16 40 /* cipher side */
|
||||
#define CRYPTO_ALGORITHM_MAX 40 /* Keep updated - see below */
|
||||
|
||||
#define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \
|
||||
(x) <= CRYPTO_ALGORITHM_MAX)
|
||||
|
@ -62,6 +62,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/bus.h>
|
||||
#include "cryptodev_if.h"
|
||||
|
||||
_Static_assert(AES_CCM_IV_LEN == AES_GCM_IV_LEN,
|
||||
"AES_GCM_IV_LEN must currently be the same as AES_CCM_IV_LEN");
|
||||
|
||||
static int32_t swcr_id;
|
||||
|
||||
u_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
|
||||
@ -506,6 +509,7 @@ swcr_authenc(struct cryptop *crp)
|
||||
caddr_t buf = (caddr_t)crp->crp_buf;
|
||||
uint32_t *blkp;
|
||||
int aadlen, blksz, i, ivlen, len, iskip, oskip, r;
|
||||
int isccm = 0;
|
||||
|
||||
ivlen = blksz = iskip = oskip = 0;
|
||||
|
||||
@ -520,13 +524,18 @@ swcr_authenc(struct cryptop *crp)
|
||||
|
||||
sw = &ses->swcr_algorithms[i];
|
||||
switch (sw->sw_alg) {
|
||||
case CRYPTO_AES_CCM_16:
|
||||
case CRYPTO_AES_NIST_GCM_16:
|
||||
case CRYPTO_AES_NIST_GMAC:
|
||||
swe = sw;
|
||||
crde = crd;
|
||||
exf = swe->sw_exf;
|
||||
ivlen = 12;
|
||||
/* AES_CCM_IV_LEN and AES_GCM_IV_LEN are both 12 */
|
||||
ivlen = AES_CCM_IV_LEN;
|
||||
break;
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
isccm = 1;
|
||||
/* FALLTHROUGH */
|
||||
case CRYPTO_AES_128_NIST_GMAC:
|
||||
case CRYPTO_AES_192_NIST_GMAC:
|
||||
case CRYPTO_AES_256_NIST_GMAC:
|
||||
@ -544,8 +553,26 @@ swcr_authenc(struct cryptop *crp)
|
||||
}
|
||||
if (crde == NULL || crda == NULL)
|
||||
return (EINVAL);
|
||||
/*
|
||||
* We need to make sure that the auth algorithm matches the
|
||||
* encr algorithm. Specifically, for AES-GCM must go with
|
||||
* AES NIST GMAC, and AES-CCM must go with CBC-MAC.
|
||||
*/
|
||||
if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16) {
|
||||
switch (crda->crd_alg) {
|
||||
case CRYPTO_AES_128_NIST_GMAC:
|
||||
case CRYPTO_AES_192_NIST_GMAC:
|
||||
case CRYPTO_AES_256_NIST_GMAC:
|
||||
break; /* Good! */
|
||||
default:
|
||||
return (EINVAL); /* Not good! */
|
||||
}
|
||||
} else if (crde->crd_alg == CRYPTO_AES_CCM_16 &&
|
||||
crda->crd_alg != CRYPTO_AES_CCM_CBC_MAC)
|
||||
return (EINVAL);
|
||||
|
||||
if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 &&
|
||||
if ((crde->crd_alg == CRYPTO_AES_NIST_GCM_16 ||
|
||||
crde->crd_alg == CRYPTO_AES_CCM_16) &&
|
||||
(crde->crd_flags & CRD_F_IV_EXPLICIT) == 0)
|
||||
return (EINVAL);
|
||||
|
||||
@ -576,6 +603,15 @@ swcr_authenc(struct cryptop *crp)
|
||||
}
|
||||
}
|
||||
|
||||
if (swa->sw_alg == CRYPTO_AES_CCM_CBC_MAC) {
|
||||
/*
|
||||
* AES CCM-CBC needs to know the length of
|
||||
* both the auth data, and payload data, before
|
||||
* doing the auth computation.
|
||||
*/
|
||||
ctx.aes_cbc_mac_ctx.authDataLength = crda->crd_len;
|
||||
ctx.aes_cbc_mac_ctx.cryptDataLength = crde->crd_len;
|
||||
}
|
||||
/* Supply MAC with IV */
|
||||
if (axf->Reinit)
|
||||
axf->Reinit(&ctx, iv, ivlen);
|
||||
@ -610,16 +646,30 @@ swcr_authenc(struct cryptop *crp)
|
||||
bzero(blk, blksz);
|
||||
crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len,
|
||||
blk);
|
||||
/*
|
||||
* One of the problems with CCM+CBC is that the authentication
|
||||
* is done on the unecncrypted data. As a result, we have
|
||||
* to do the authentication update at different times,
|
||||
* depending on whether it's CCM or not.
|
||||
*/
|
||||
if (crde->crd_flags & CRD_F_ENCRYPT) {
|
||||
if (isccm)
|
||||
axf->Update(&ctx, blk, len);
|
||||
if (exf->encrypt_multi != NULL)
|
||||
exf->encrypt_multi(swe->sw_kschedule, blk,
|
||||
len);
|
||||
else
|
||||
exf->encrypt(swe->sw_kschedule, blk);
|
||||
axf->Update(&ctx, blk, len);
|
||||
if (!isccm)
|
||||
axf->Update(&ctx, blk, len);
|
||||
crypto_copyback(crp->crp_flags, buf,
|
||||
crde->crd_skip + i, len, blk);
|
||||
} else {
|
||||
if (isccm) {
|
||||
KASSERT(exf->encrypt_multi == NULL,
|
||||
("assume CCM is single-block only"));
|
||||
exf->decrypt(swe->sw_kschedule, blk);
|
||||
}
|
||||
axf->Update(&ctx, blk, len);
|
||||
}
|
||||
}
|
||||
@ -650,6 +700,11 @@ swcr_authenc(struct cryptop *crp)
|
||||
r = timingsafe_bcmp(aalg, uaalg, axf->hashsize);
|
||||
if (r == 0) {
|
||||
/* tag matches, decrypt data */
|
||||
if (isccm) {
|
||||
KASSERT(exf->reinit != NULL,
|
||||
("AES-CCM reinit function must be set"));
|
||||
exf->reinit(swe->sw_kschedule, iv);
|
||||
}
|
||||
for (i = 0; i < crde->crd_len; i += blksz) {
|
||||
len = MIN(crde->crd_len - i, blksz);
|
||||
if (len < blksz)
|
||||
@ -799,6 +854,9 @@ swcr_newsession(device_t dev, crypto_session_t cses, struct cryptoini *cri)
|
||||
case CRYPTO_AES_NIST_GCM_16:
|
||||
txf = &enc_xform_aes_nist_gcm;
|
||||
goto enccommon;
|
||||
case CRYPTO_AES_CCM_16:
|
||||
txf = &enc_xform_ccm;
|
||||
goto enccommon;
|
||||
case CRYPTO_AES_NIST_GMAC:
|
||||
txf = &enc_xform_aes_nist_gmac;
|
||||
swd->sw_exf = txf;
|
||||
@ -943,6 +1001,22 @@ swcr_newsession(device_t dev, crypto_session_t cses, struct cryptoini *cri)
|
||||
swd->sw_axf = axf;
|
||||
break;
|
||||
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
switch (cri->cri_klen) {
|
||||
case 128:
|
||||
axf = &auth_hash_ccm_cbc_mac_128;
|
||||
break;
|
||||
case 192:
|
||||
axf = &auth_hash_ccm_cbc_mac_192;
|
||||
break;
|
||||
case 256:
|
||||
axf = &auth_hash_ccm_cbc_mac_256;
|
||||
break;
|
||||
default:
|
||||
swcr_freesession(dev, cses);
|
||||
return EINVAL;
|
||||
}
|
||||
goto auth4common;
|
||||
case CRYPTO_AES_128_NIST_GMAC:
|
||||
axf = &auth_hash_nist_gmac_aes_128;
|
||||
goto auth4common;
|
||||
@ -1042,6 +1116,7 @@ swcr_freesession(device_t dev, crypto_session_t cses)
|
||||
case CRYPTO_CAMELLIA_CBC:
|
||||
case CRYPTO_NULL_CBC:
|
||||
case CRYPTO_CHACHA20:
|
||||
case CRYPTO_AES_CCM_16:
|
||||
txf = swd->sw_exf;
|
||||
|
||||
if (swd->sw_kschedule)
|
||||
@ -1056,6 +1131,7 @@ swcr_freesession(device_t dev, crypto_session_t cses)
|
||||
case CRYPTO_SHA2_512_HMAC:
|
||||
case CRYPTO_RIPEMD160_HMAC:
|
||||
case CRYPTO_NULL_HMAC:
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
axf = swd->sw_axf;
|
||||
|
||||
if (swd->sw_ictx) {
|
||||
@ -1201,6 +1277,8 @@ swcr_process(device_t dev, struct cryptop *crp, int hint)
|
||||
case CRYPTO_AES_128_NIST_GMAC:
|
||||
case CRYPTO_AES_192_NIST_GMAC:
|
||||
case CRYPTO_AES_256_NIST_GMAC:
|
||||
case CRYPTO_AES_CCM_16:
|
||||
case CRYPTO_AES_CCM_CBC_MAC:
|
||||
crp->crp_etype = swcr_authenc(crp);
|
||||
goto done;
|
||||
|
||||
@ -1291,6 +1369,8 @@ swcr_attach(device_t dev)
|
||||
REGISTER(CRYPTO_BLAKE2B);
|
||||
REGISTER(CRYPTO_BLAKE2S);
|
||||
REGISTER(CRYPTO_CHACHA20);
|
||||
REGISTER(CRYPTO_AES_CCM_16);
|
||||
REGISTER(CRYPTO_AES_CCM_CBC_MAC);
|
||||
REGISTER(CRYPTO_POLY1305);
|
||||
#undef REGISTER
|
||||
|
||||
|
@ -57,6 +57,7 @@ static void aes_icm_crypt(caddr_t, u_int8_t *);
|
||||
static void aes_icm_zerokey(u_int8_t **);
|
||||
static void aes_icm_reinit(caddr_t, u_int8_t *);
|
||||
static void aes_gcm_reinit(caddr_t, u_int8_t *);
|
||||
static void aes_ccm_reinit(caddr_t, u_int8_t *);
|
||||
|
||||
/* Encryption instances */
|
||||
struct enc_xform enc_xform_aes_icm = {
|
||||
@ -79,6 +80,18 @@ struct enc_xform enc_xform_aes_nist_gcm = {
|
||||
aes_gcm_reinit,
|
||||
};
|
||||
|
||||
struct enc_xform enc_xform_ccm = {
|
||||
.type = CRYPTO_AES_CCM_16,
|
||||
.name = "AES-CCM",
|
||||
.blocksize = AES_ICM_BLOCK_LEN, .ivsize = AES_CCM_IV_LEN,
|
||||
.minkey = AES_MIN_KEY, .maxkey = AES_MAX_KEY,
|
||||
.encrypt = aes_icm_crypt,
|
||||
.decrypt = aes_icm_crypt,
|
||||
.setkey = aes_icm_setkey,
|
||||
.zerokey = aes_icm_zerokey,
|
||||
.reinit = aes_ccm_reinit,
|
||||
};
|
||||
|
||||
/*
|
||||
* Encryption wrapper routines.
|
||||
*/
|
||||
@ -104,6 +117,21 @@ aes_gcm_reinit(caddr_t key, u_int8_t *iv)
|
||||
ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2;
|
||||
}
|
||||
|
||||
static void
|
||||
aes_ccm_reinit(caddr_t key, u_int8_t *iv)
|
||||
{
|
||||
struct aes_icm_ctx *ctx;
|
||||
|
||||
ctx = (struct aes_icm_ctx*)key;
|
||||
|
||||
/* CCM has flags, then the IV, then the counter, which starts at 1 */
|
||||
bzero(ctx->ac_block, sizeof(ctx->ac_block));
|
||||
/* 3 bytes for length field; this gives a nonce of 12 bytes */
|
||||
ctx->ac_block[0] = (15 - AES_CCM_IV_LEN) - 1;
|
||||
bcopy(iv, ctx->ac_block+1, AES_CCM_IV_LEN);
|
||||
ctx->ac_block[AESICM_BLOCKSIZE - 1] = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
aes_icm_crypt(caddr_t key, u_int8_t *data)
|
||||
{
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <crypto/sha2/sha512.h>
|
||||
#include <opencrypto/rmd160.h>
|
||||
#include <opencrypto/gmac.h>
|
||||
#include <opencrypto/cbc_mac.h>
|
||||
|
||||
#include <opencrypto/cryptodev.h>
|
||||
#include <opencrypto/xform_userland.h>
|
||||
@ -85,6 +86,9 @@ extern struct auth_hash auth_hash_nist_gmac_aes_256;
|
||||
extern struct auth_hash auth_hash_blake2b;
|
||||
extern struct auth_hash auth_hash_blake2s;
|
||||
extern struct auth_hash auth_hash_poly1305;
|
||||
extern struct auth_hash auth_hash_ccm_cbc_mac_128;
|
||||
extern struct auth_hash auth_hash_ccm_cbc_mac_192;
|
||||
extern struct auth_hash auth_hash_ccm_cbc_mac_256;
|
||||
|
||||
union authctx {
|
||||
MD5_CTX md5ctx;
|
||||
@ -95,6 +99,7 @@ union authctx {
|
||||
SHA384_CTX sha384ctx;
|
||||
SHA512_CTX sha512ctx;
|
||||
struct aes_gmac_ctx aes_gmac_ctx;
|
||||
struct aes_cbc_mac_ctx aes_cbc_mac_ctx;
|
||||
};
|
||||
|
||||
#endif /* _CRYPTO_XFORM_AUTH_H_ */
|
||||
|
@ -84,6 +84,7 @@ extern struct enc_xform enc_xform_aes_xts;
|
||||
extern struct enc_xform enc_xform_arc4;
|
||||
extern struct enc_xform enc_xform_camellia;
|
||||
extern struct enc_xform enc_xform_chacha20;
|
||||
extern struct enc_xform enc_xform_ccm;
|
||||
|
||||
struct aes_icm_ctx {
|
||||
u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)];
|
||||
|
@ -105,6 +105,9 @@
|
||||
* aes-gcm 128-bit aes gcm
|
||||
* aes-gcm192 192-bit aes gcm
|
||||
* aes-gcm256 256-bit aes gcm
|
||||
* aes-ccm 128-bit aes ccm
|
||||
* aes-ccm192 192-bit aes ccm
|
||||
* aes-ccm256 256-bit aes ccm
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -131,7 +134,7 @@ struct alg {
|
||||
const char *name;
|
||||
int cipher;
|
||||
int mac;
|
||||
enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
|
||||
enum { T_HASH, T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM, T_CCM } type;
|
||||
const EVP_CIPHER *(*evp_cipher)(void);
|
||||
const EVP_MD *(*evp_md)(void);
|
||||
} algs[] = {
|
||||
@ -186,6 +189,15 @@ struct alg {
|
||||
{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
|
||||
.mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
|
||||
.evp_cipher = EVP_aes_256_gcm },
|
||||
{ .name = "aes-ccm", .cipher = CRYPTO_AES_CCM_16,
|
||||
.mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
|
||||
.evp_cipher = EVP_aes_128_ccm },
|
||||
{ .name = "aes-ccm192", .cipher = CRYPTO_AES_CCM_16,
|
||||
.mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
|
||||
.evp_cipher = EVP_aes_192_ccm },
|
||||
{ .name = "aes-ccm256", .cipher = CRYPTO_AES_CCM_16,
|
||||
.mac = CRYPTO_AES_CCM_CBC_MAC, .type = T_CCM,
|
||||
.evp_cipher = EVP_aes_256_ccm },
|
||||
};
|
||||
|
||||
static bool verbose;
|
||||
@ -1158,6 +1170,214 @@ run_gcm_test(struct alg *alg, size_t size)
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void
|
||||
openssl_ccm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
|
||||
const char *iv, size_t iv_len, const char *aad, size_t aad_len,
|
||||
const char *input, char *output, size_t size, char *tag)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
int outl, total;
|
||||
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL)
|
||||
errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, AES_CBC_MAC_HASH_LEN, NULL) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) setting tag length failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
if (EVP_EncryptInit_ex(ctx, NULL, NULL, (const u_char *)key,
|
||||
(const u_char *)iv) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
if (EVP_EncryptUpdate(ctx, NULL, &outl, NULL, size) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) unable to set data length: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
if (aad != NULL) {
|
||||
if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
|
||||
aad_len) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) aad update failed: %s",
|
||||
alg->name, size,
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl,
|
||||
(const u_char *)input, size) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
total = outl;
|
||||
if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
total += outl;
|
||||
if (total != size)
|
||||
errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name,
|
||||
size, total);
|
||||
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, AES_CBC_MAC_HASH_LEN,
|
||||
tag) != 1)
|
||||
errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
|
||||
size, ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static bool
|
||||
ocf_ccm(struct alg *alg, const char *key, size_t key_len, const char *iv,
|
||||
size_t iv_len, const char *aad, size_t aad_len, const char *input,
|
||||
char *output, size_t size, char *tag, int enc, int *cridp)
|
||||
{
|
||||
struct session2_op sop;
|
||||
struct crypt_aead caead;
|
||||
int fd;
|
||||
bool rv;
|
||||
|
||||
memset(&sop, 0, sizeof(sop));
|
||||
memset(&caead, 0, sizeof(caead));
|
||||
sop.crid = crid;
|
||||
sop.keylen = key_len;
|
||||
sop.key = (char *)key;
|
||||
sop.cipher = alg->cipher;
|
||||
sop.mackeylen = key_len;
|
||||
sop.mackey = (char *)key;
|
||||
sop.mac = alg->mac;
|
||||
fd = crget();
|
||||
if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
|
||||
warn("cryptodev %s not supported for device %s",
|
||||
alg->name, crfind(crid));
|
||||
close(fd);
|
||||
return (false);
|
||||
}
|
||||
|
||||
caead.ses = sop.ses;
|
||||
caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
|
||||
caead.len = size;
|
||||
caead.aadlen = aad_len;
|
||||
caead.ivlen = iv_len;
|
||||
caead.src = (char *)input;
|
||||
caead.dst = output;
|
||||
caead.aad = (char *)aad;
|
||||
caead.tag = tag;
|
||||
caead.iv = (char *)iv;
|
||||
|
||||
if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
|
||||
warn("cryptodev %s (%zu) failed for device %s",
|
||||
alg->name, size, crfind(crid));
|
||||
rv = false;
|
||||
} else
|
||||
rv = true;
|
||||
|
||||
if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
|
||||
warn("ioctl(CIOCFSESSION)");
|
||||
|
||||
close(fd);
|
||||
*cridp = sop.crid;
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static void
|
||||
run_ccm_test(struct alg *alg, size_t size)
|
||||
{
|
||||
const EVP_CIPHER *cipher;
|
||||
char *aad, *buffer, *cleartext, *ciphertext;
|
||||
char *iv, *key;
|
||||
u_int iv_len, key_len;
|
||||
int crid;
|
||||
char control_tag[AES_CBC_MAC_HASH_LEN], test_tag[AES_CBC_MAC_HASH_LEN];
|
||||
|
||||
cipher = alg->evp_cipher();
|
||||
if (size % EVP_CIPHER_block_size(cipher) != 0) {
|
||||
if (verbose)
|
||||
printf(
|
||||
"%s (%zu): invalid buffer size (block size %d)\n",
|
||||
alg->name, size, EVP_CIPHER_block_size(cipher));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(control_tag, 0x3c, sizeof(control_tag));
|
||||
memset(test_tag, 0x3c, sizeof(test_tag));
|
||||
|
||||
/*
|
||||
* We only have one algorithm constant for CBC-MAC; however, the
|
||||
* alg structure uses the different openssl types, which gives us
|
||||
* the key length. We need that for the OCF code.
|
||||
*/
|
||||
key_len = EVP_CIPHER_key_length(cipher);
|
||||
|
||||
/*
|
||||
* AES-CCM can have varying IV lengths; however, for the moment
|
||||
* we only support AES_CCM_IV_LEN (12). So if the sizes are
|
||||
* different, we'll fail.
|
||||
*/
|
||||
iv_len = EVP_CIPHER_iv_length(cipher);
|
||||
if (iv_len != AES_CCM_IV_LEN) {
|
||||
if (verbose)
|
||||
printf("OpenSSL CCM IV length (%d) != AES_CCM_IV_LEN",
|
||||
iv_len);
|
||||
return;
|
||||
}
|
||||
|
||||
key = alloc_buffer(key_len);
|
||||
iv = generate_iv(iv_len, alg);
|
||||
cleartext = alloc_buffer(size);
|
||||
buffer = malloc(size);
|
||||
ciphertext = malloc(size);
|
||||
if (aad_len != 0)
|
||||
aad = alloc_buffer(aad_len);
|
||||
else
|
||||
aad = NULL;
|
||||
|
||||
/* OpenSSL encrypt */
|
||||
openssl_ccm_encrypt(alg, cipher, key, iv, iv_len, aad, aad_len, cleartext,
|
||||
ciphertext, size, control_tag);
|
||||
|
||||
/* OCF encrypt */
|
||||
if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext,
|
||||
buffer, size, test_tag, 1, &crid))
|
||||
goto out;
|
||||
if (memcmp(ciphertext, buffer, size) != 0) {
|
||||
printf("%s (%zu) encryption mismatch:\n", alg->name, size);
|
||||
printf("control:\n");
|
||||
hexdump(ciphertext, size, NULL, 0);
|
||||
printf("test (cryptodev device %s):\n", crfind(crid));
|
||||
hexdump(buffer, size, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) {
|
||||
printf("%s (%zu) enc tag mismatch:\n", alg->name, size);
|
||||
printf("control:\n");
|
||||
hexdump(control_tag, sizeof(control_tag), NULL, 0);
|
||||
printf("test (cryptodev device %s):\n", crfind(crid));
|
||||
hexdump(test_tag, sizeof(test_tag), NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* OCF decrypt */
|
||||
if (!ocf_ccm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext,
|
||||
buffer, size, control_tag, 0, &crid))
|
||||
goto out;
|
||||
if (memcmp(cleartext, buffer, size) != 0) {
|
||||
printf("%s (%zu) decryption mismatch:\n", alg->name, size);
|
||||
printf("control:\n");
|
||||
hexdump(cleartext, size, NULL, 0);
|
||||
printf("test (cryptodev device %s):\n", crfind(crid));
|
||||
hexdump(buffer, size, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("%s (%zu) matched (cryptodev device %s)\n",
|
||||
alg->name, size, crfind(crid));
|
||||
|
||||
out:
|
||||
free(aad);
|
||||
free(ciphertext);
|
||||
free(buffer);
|
||||
free(cleartext);
|
||||
free(iv);
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void
|
||||
run_test(struct alg *alg, size_t size)
|
||||
{
|
||||
@ -1178,6 +1398,9 @@ run_test(struct alg *alg, size_t size)
|
||||
case T_GCM:
|
||||
run_gcm_test(alg, size);
|
||||
break;
|
||||
case T_CCM:
|
||||
run_ccm_test(alg, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1247,7 +1470,8 @@ run_aead_tests(size_t *sizes, u_int nsizes)
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(algs); i++)
|
||||
if (algs[i].type == T_GCM)
|
||||
if (algs[i].type == T_GCM ||
|
||||
algs[i].type == T_CCM)
|
||||
run_test_sizes(&algs[i], sizes, nsizes);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user