diff options
-rw-r--r-- | sys/opencrypto/cryptodev.c | 3 | ||||
-rw-r--r-- | sys/opencrypto/cryptodev.h | 3 | ||||
-rw-r--r-- | sys/opencrypto/cryptosoft.c | 64 | ||||
-rw-r--r-- | sys/opencrypto/xform.c | 146 | ||||
-rw-r--r-- | sys/opencrypto/xform.h | 2 |
5 files changed, 203 insertions, 15 deletions
diff --git a/sys/opencrypto/cryptodev.c b/sys/opencrypto/cryptodev.c index 8edbc8e..6a10f9a 100644 --- a/sys/opencrypto/cryptodev.c +++ b/sys/opencrypto/cryptodev.c @@ -419,6 +419,9 @@ cryptof_ioctl( case CRYPTO_AES_CBC: txform = &enc_xform_rijndael128; break; + case CRYPTO_AES_XTS: + txform = &enc_xform_aes_xts; + break; case CRYPTO_NULL_CBC: txform = &enc_xform_null; break; diff --git a/sys/opencrypto/cryptodev.h b/sys/opencrypto/cryptodev.h index afd79c8..e299522 100644 --- a/sys/opencrypto/cryptodev.h +++ b/sys/opencrypto/cryptodev.h @@ -123,7 +123,8 @@ #define CRYPTO_SHA2_384_HMAC 19 #define CRYPTO_SHA2_512_HMAC 20 #define CRYPTO_CAMELLIA_CBC 21 -#define CRYPTO_ALGORITHM_MAX 21 /* Keep updated - see below */ +#define CRYPTO_AES_XTS 22 +#define CRYPTO_ALGORITHM_MAX 22 /* Keep updated - see below */ /* Algorithm flags */ #define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ diff --git a/sys/opencrypto/cryptosoft.c b/sys/opencrypto/cryptosoft.c index a404cbc..e05b015 100644 --- a/sys/opencrypto/cryptosoft.c +++ b/sys/opencrypto/cryptosoft.c @@ -114,8 +114,16 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, if (error) return (error); } + ivp = iv; + /* + * xforms that provide a reinit method perform all IV + * handling themselves. + */ + if (exf->reinit) + exf->reinit(sw->sw_kschedule, iv); + if (flags & CRYPTO_F_IMBUF) { struct mbuf *m = (struct mbuf *) buf; @@ -135,7 +143,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, m_copydata(m, k, blks, blk); /* Actual encryption/decryption */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + blk); + } else { + exf->decrypt(sw->sw_kschedule, + blk); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block */ for (j = 0; j < blks; j++) blk[j] ^= ivp[j]; @@ -205,7 +221,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, idat = mtod(m, unsigned char *) + k; while (m->m_len >= k + blks && i > 0) { - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + idat); + } else { + exf->decrypt(sw->sw_kschedule, + idat); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block/IV */ for (j = 0; j < blks; j++) idat[j] ^= ivp[j]; @@ -261,7 +285,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, cuio_copydata(uio, k, blks, blk); /* Actual encryption/decryption */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + blk); + } else { + exf->decrypt(sw->sw_kschedule, + blk); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block */ for (j = 0; j < blks; j++) blk[j] ^= ivp[j]; @@ -319,7 +351,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, idat = (char *)iov->iov_base + k; while (iov->iov_len >= k + blks && i > 0) { - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + idat); + } else { + exf->decrypt(sw->sw_kschedule, + idat); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { /* XOR with previous block/IV */ for (j = 0; j < blks; j++) idat[j] ^= ivp[j]; @@ -360,7 +400,15 @@ swcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf, return 0; /* Done with iovec encryption/decryption */ } else { /* contiguous buffer */ - if (crd->crd_flags & CRD_F_ENCRYPT) { + if (exf->reinit) { + for (i = crd->crd_skip; + i < crd->crd_skip + crd->crd_len; i += blks) { + if (crd->crd_flags & CRD_F_ENCRYPT) + exf->encrypt(sw->sw_kschedule, buf + i); + else + exf->decrypt(sw->sw_kschedule, buf + i); + } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { for (i = crd->crd_skip; i < crd->crd_skip + crd->crd_len; i += blks) { /* XOR with the IV/previous block, as appropriate. */ @@ -687,6 +735,9 @@ swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri) case CRYPTO_RIJNDAEL128_CBC: txf = &enc_xform_rijndael128; goto enccommon; + case CRYPTO_AES_XTS: + txf = &enc_xform_aes_xts; + goto enccommon; case CRYPTO_CAMELLIA_CBC: txf = &enc_xform_camellia; goto enccommon; @@ -845,6 +896,7 @@ swcr_freesession(device_t dev, u_int64_t tid) case CRYPTO_CAST_CBC: case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: + case CRYPTO_AES_XTS: case CRYPTO_CAMELLIA_CBC: case CRYPTO_NULL_CBC: txf = swd->sw_exf; @@ -958,6 +1010,7 @@ swcr_process(device_t dev, struct cryptop *crp, int hint) case CRYPTO_CAST_CBC: case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: + case CRYPTO_AES_XTS: case CRYPTO_CAMELLIA_CBC: if ((crp->crp_etype = swcr_encdec(crd, sw, crp->crp_buf, crp->crp_flags)) != 0) @@ -1050,6 +1103,7 @@ swcr_attach(device_t dev) REGISTER(CRYPTO_MD5); REGISTER(CRYPTO_SHA1); REGISTER(CRYPTO_RIJNDAEL128_CBC); + REGISTER(CRYPTO_AES_XTS); REGISTER(CRYPTO_CAMELLIA_CBC); REGISTER(CRYPTO_DEFLATE_COMP); #undef REGISTER diff --git a/sys/opencrypto/xform.c b/sys/opencrypto/xform.c index f3ec33f..26e383c 100644 --- a/sys/opencrypto/xform.c +++ b/sys/opencrypto/xform.c @@ -64,40 +64,48 @@ __FBSDID("$FreeBSD$"); #include <opencrypto/cryptodev.h> #include <opencrypto/xform.h> -static void null_encrypt(caddr_t, u_int8_t *); -static void null_decrypt(caddr_t, u_int8_t *); -static int null_setkey(u_int8_t **, u_int8_t *, int); -static void null_zerokey(u_int8_t **); - +static int null_setkey(u_int8_t **, u_int8_t *, int); static int des1_setkey(u_int8_t **, u_int8_t *, int); static int des3_setkey(u_int8_t **, u_int8_t *, int); static int blf_setkey(u_int8_t **, u_int8_t *, int); static int cast5_setkey(u_int8_t **, u_int8_t *, int); static int skipjack_setkey(u_int8_t **, u_int8_t *, int); static int rijndael128_setkey(u_int8_t **, u_int8_t *, int); +static int aes_xts_setkey(u_int8_t **, u_int8_t *, int); static int cml_setkey(u_int8_t **, u_int8_t *, int); + +static void null_encrypt(caddr_t, u_int8_t *); static void des1_encrypt(caddr_t, u_int8_t *); static void des3_encrypt(caddr_t, u_int8_t *); static void blf_encrypt(caddr_t, u_int8_t *); static void cast5_encrypt(caddr_t, u_int8_t *); static void skipjack_encrypt(caddr_t, u_int8_t *); static void rijndael128_encrypt(caddr_t, u_int8_t *); +static void aes_xts_encrypt(caddr_t, u_int8_t *); static void cml_encrypt(caddr_t, u_int8_t *); + +static void null_decrypt(caddr_t, u_int8_t *); static void des1_decrypt(caddr_t, u_int8_t *); static void des3_decrypt(caddr_t, u_int8_t *); static void blf_decrypt(caddr_t, u_int8_t *); static void cast5_decrypt(caddr_t, u_int8_t *); static void skipjack_decrypt(caddr_t, u_int8_t *); static void rijndael128_decrypt(caddr_t, u_int8_t *); +static void aes_xts_decrypt(caddr_t, u_int8_t *); static void cml_decrypt(caddr_t, u_int8_t *); + +static void null_zerokey(u_int8_t **); static void des1_zerokey(u_int8_t **); static void des3_zerokey(u_int8_t **); static void blf_zerokey(u_int8_t **); static void cast5_zerokey(u_int8_t **); static void skipjack_zerokey(u_int8_t **); static void rijndael128_zerokey(u_int8_t **); +static void aes_xts_zerokey(u_int8_t **); static void cml_zerokey(u_int8_t **); +static void aes_xts_reinit(caddr_t, u_int8_t *); + static void null_init(void *); static int null_update(void *, u_int8_t *, u_int16_t); static void null_final(u_int8_t *, void *); @@ -124,6 +132,7 @@ struct enc_xform enc_xform_null = { null_decrypt, null_setkey, null_zerokey, + NULL }; struct enc_xform enc_xform_des = { @@ -133,6 +142,7 @@ struct enc_xform enc_xform_des = { des1_decrypt, des1_setkey, des1_zerokey, + NULL }; struct enc_xform enc_xform_3des = { @@ -141,7 +151,8 @@ struct enc_xform enc_xform_3des = { des3_encrypt, des3_decrypt, des3_setkey, - des3_zerokey + des3_zerokey, + NULL }; struct enc_xform enc_xform_blf = { @@ -150,7 +161,8 @@ struct enc_xform enc_xform_blf = { blf_encrypt, blf_decrypt, blf_setkey, - blf_zerokey + blf_zerokey, + NULL }; struct enc_xform enc_xform_cast5 = { @@ -159,7 +171,8 @@ struct enc_xform enc_xform_cast5 = { cast5_encrypt, cast5_decrypt, cast5_setkey, - cast5_zerokey + cast5_zerokey, + NULL }; struct enc_xform enc_xform_skipjack = { @@ -168,7 +181,8 @@ struct enc_xform enc_xform_skipjack = { skipjack_encrypt, skipjack_decrypt, skipjack_setkey, - skipjack_zerokey + skipjack_zerokey, + NULL }; struct enc_xform enc_xform_rijndael128 = { @@ -178,6 +192,17 @@ struct enc_xform enc_xform_rijndael128 = { rijndael128_decrypt, rijndael128_setkey, rijndael128_zerokey, + NULL +}; + +struct enc_xform enc_xform_aes_xts = { + CRYPTO_AES_XTS, "AES-XTS", + RIJNDAEL128_BLOCK_LEN, 32, 64, + aes_xts_encrypt, + aes_xts_decrypt, + aes_xts_setkey, + aes_xts_zerokey, + aes_xts_reinit }; struct enc_xform enc_xform_arc4 = { @@ -187,6 +212,7 @@ struct enc_xform enc_xform_arc4 = { NULL, NULL, NULL, + NULL }; struct enc_xform enc_xform_camellia = { @@ -196,6 +222,7 @@ struct enc_xform enc_xform_camellia = { cml_decrypt, cml_setkey, cml_zerokey, + NULL }; /* Authentication instances */ @@ -547,6 +574,107 @@ rijndael128_zerokey(u_int8_t **sched) *sched = NULL; } +#define AES_XTS_BLOCKSIZE 16 +#define AES_XTS_IVSIZE 8 +#define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ + +struct aes_xts_ctx { + rijndael_ctx key1; + rijndael_ctx key2; + u_int8_t tweak[AES_XTS_BLOCKSIZE]; +}; + +void +aes_xts_reinit(caddr_t key, u_int8_t *iv) +{ + struct aes_xts_ctx *ctx = (struct aes_xts_ctx *)key; + u_int64_t blocknum; + u_int i; + + /* + * Prepare tweak as E_k2(IV). IV is specified as LE representation + * of a 64-bit block number which we allow to be passed in directly. + */ + bcopy(iv, &blocknum, AES_XTS_IVSIZE); + for (i = 0; i < AES_XTS_IVSIZE; i++) { + ctx->tweak[i] = blocknum & 0xff; + blocknum >>= 8; + } + /* Last 64 bits of IV are always zero */ + bzero(ctx->tweak + AES_XTS_IVSIZE, AES_XTS_IVSIZE); + + rijndael_encrypt(&ctx->key2, ctx->tweak, ctx->tweak); +} + +static void +aes_xts_crypt(struct aes_xts_ctx *ctx, u_int8_t *data, u_int do_encrypt) +{ + u_int8_t block[AES_XTS_BLOCKSIZE]; + u_int i, carry_in, carry_out; + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + block[i] = data[i] ^ ctx->tweak[i]; + + if (do_encrypt) + rijndael_encrypt(&ctx->key1, block, data); + else + rijndael_decrypt(&ctx->key1, block, data); + + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) + data[i] ^= ctx->tweak[i]; + + /* Exponentiate tweak */ + carry_in = 0; + for (i = 0; i < AES_XTS_BLOCKSIZE; i++) { + carry_out = ctx->tweak[i] & 0x80; + ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0); + carry_in = carry_out; + } + if (carry_in) + ctx->tweak[0] ^= AES_XTS_ALPHA; + bzero(block, sizeof(block)); +} + +void +aes_xts_encrypt(caddr_t key, u_int8_t *data) +{ + aes_xts_crypt((struct aes_xts_ctx *)key, data, 1); +} + +void +aes_xts_decrypt(caddr_t key, u_int8_t *data) +{ + aes_xts_crypt((struct aes_xts_ctx *)key, data, 0); +} + +int +aes_xts_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + struct aes_xts_ctx *ctx; + + if (len != 32 && len != 64) + return EINVAL; + + *sched = malloc(sizeof(struct aes_xts_ctx), M_CRYPTO_DATA, + M_NOWAIT | M_ZERO); + if (*sched == NULL) + return ENOMEM; + ctx = (struct aes_xts_ctx *)*sched; + + rijndael_set_key(&ctx->key1, key, len * 4); + rijndael_set_key(&ctx->key2, key + (len / 2), len * 4); + + return 0; +} + +void +aes_xts_zerokey(u_int8_t **sched) +{ + bzero(*sched, sizeof(struct aes_xts_ctx)); + free(*sched, M_CRYPTO_DATA); + *sched = NULL; +} + static void cml_encrypt(caddr_t key, u_int8_t *blk) { diff --git a/sys/opencrypto/xform.h b/sys/opencrypto/xform.h index de7528b..0a7f981 100644 --- a/sys/opencrypto/xform.h +++ b/sys/opencrypto/xform.h @@ -54,6 +54,7 @@ struct enc_xform { void (*decrypt) (caddr_t, u_int8_t *); int (*setkey) (u_int8_t **, u_int8_t *, int len); void (*zerokey) (u_int8_t **); + void (*reinit) (caddr_t, u_int8_t *); }; struct comp_algo { @@ -80,6 +81,7 @@ extern struct enc_xform enc_xform_blf; extern struct enc_xform enc_xform_cast5; extern struct enc_xform enc_xform_skipjack; extern struct enc_xform enc_xform_rijndael128; +extern struct enc_xform enc_xform_aes_xts; extern struct enc_xform enc_xform_arc4; extern struct enc_xform enc_xform_camellia; |