Annotation of embedaddon/strongswan/src/libstrongswan/plugins/aesni/aesni_ccm.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010-2015 Martin Willi
! 3: * Copyright (C) 2010-2015 revosec AG
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "aesni_ccm.h"
! 17: #include "aesni_key.h"
! 18:
! 19: #include <crypto/iv/iv_gen_seq.h>
! 20:
! 21: #include <tmmintrin.h>
! 22:
! 23: #define SALT_SIZE 3
! 24: #define IV_SIZE 8
! 25: #define NONCE_SIZE (SALT_SIZE + IV_SIZE) /* 11 */
! 26: #define Q_SIZE (AES_BLOCK_SIZE - NONCE_SIZE - 1) /* 4 */
! 27:
! 28: typedef struct private_aesni_ccm_t private_aesni_ccm_t;
! 29:
! 30: /**
! 31: * CCM en/decryption method type
! 32: */
! 33: typedef void (*aesni_ccm_fn_t)(private_aesni_ccm_t*, size_t, u_char*, u_char*,
! 34: u_char*, size_t, u_char*, u_char*);
! 35:
! 36: /**
! 37: * Private data of an aesni_ccm_t object.
! 38: */
! 39: struct private_aesni_ccm_t {
! 40:
! 41: /**
! 42: * Public aesni_ccm_t interface.
! 43: */
! 44: aesni_ccm_t public;
! 45:
! 46: /**
! 47: * Encryption key schedule
! 48: */
! 49: aesni_key_t *key;
! 50:
! 51: /**
! 52: * IV generator.
! 53: */
! 54: iv_gen_t *iv_gen;
! 55:
! 56: /**
! 57: * Length of the integrity check value
! 58: */
! 59: size_t icv_size;
! 60:
! 61: /**
! 62: * Length of the key in bytes
! 63: */
! 64: size_t key_size;
! 65:
! 66: /**
! 67: * CCM encryption function
! 68: */
! 69: aesni_ccm_fn_t encrypt;
! 70:
! 71: /**
! 72: * CCM decryption function
! 73: */
! 74: aesni_ccm_fn_t decrypt;
! 75:
! 76: /**
! 77: * salt to add to nonce
! 78: */
! 79: u_char salt[SALT_SIZE];
! 80: };
! 81:
! 82: /**
! 83: * First block with control information
! 84: */
! 85: typedef struct __attribute__((packed)) {
! 86: BITFIELD4(uint8_t,
! 87: /* size of p length field q, as q-1 */
! 88: q_len: 3,
! 89: /* size of our ICV t, as (t-2)/2 */
! 90: t_len: 3,
! 91: /* do we have associated data */
! 92: assoc: 1,
! 93: reserved: 1,
! 94: ) flags;
! 95: /* nonce value */
! 96: struct __attribute__((packed)) {
! 97: u_char salt[SALT_SIZE];
! 98: u_char iv[IV_SIZE];
! 99: } nonce;
! 100: /* length of plain text, q */
! 101: u_char q[Q_SIZE];
! 102: } b0_t;
! 103:
! 104: /**
! 105: * Counter block
! 106: */
! 107: typedef struct __attribute__((packed)) {
! 108: BITFIELD3(uint8_t,
! 109: /* size of p length field q, as q-1 */
! 110: q_len: 3,
! 111: zero: 3,
! 112: reserved: 2,
! 113: ) flags;
! 114: /* nonce value */
! 115: struct __attribute__((packed)) {
! 116: u_char salt[SALT_SIZE];
! 117: u_char iv[IV_SIZE];
! 118: } nonce;
! 119: /* counter value */
! 120: u_char i[Q_SIZE];
! 121: } ctr_t;
! 122:
! 123: /**
! 124: * Build the first block B0
! 125: */
! 126: static void build_b0(private_aesni_ccm_t *this, size_t len, size_t alen,
! 127: u_char *iv, void *out)
! 128: {
! 129: b0_t *block = out;
! 130:
! 131: block->flags.reserved = 0;
! 132: block->flags.assoc = alen ? 1 : 0;
! 133: block->flags.t_len = (this->icv_size - 2) / 2;
! 134: block->flags.q_len = Q_SIZE - 1;
! 135: memcpy(block->nonce.salt, this->salt, SALT_SIZE);
! 136: memcpy(block->nonce.iv, iv, IV_SIZE);
! 137: htoun32(block->q, len);
! 138: }
! 139:
! 140: /**
! 141: * Build a counter block for counter i
! 142: */
! 143: static void build_ctr(private_aesni_ccm_t *this, uint32_t i, u_char *iv,
! 144: void *out)
! 145: {
! 146: ctr_t *ctr = out;
! 147:
! 148: ctr->flags.reserved = 0;
! 149: ctr->flags.zero = 0;
! 150: ctr->flags.q_len = Q_SIZE - 1;
! 151: memcpy(ctr->nonce.salt, this->salt, SALT_SIZE);
! 152: memcpy(ctr->nonce.iv, iv, IV_SIZE);
! 153: htoun32(ctr->i, i);
! 154: }
! 155:
! 156: /**
! 157: * Calculate the ICV for the b0 and associated data
! 158: */
! 159: static __m128i icv_header(private_aesni_ccm_t *this, size_t len, u_char *iv,
! 160: uint16_t alen, u_char *assoc)
! 161: {
! 162: __m128i *ks, b, t, c;
! 163: u_int i, round, blocks, rem;
! 164:
! 165: ks = this->key->schedule;
! 166: build_b0(this, len, alen, iv, &b);
! 167: c = _mm_loadu_si128(&b);
! 168: c = _mm_xor_si128(c, ks[0]);
! 169: for (round = 1; round < this->key->rounds; round++)
! 170: {
! 171: c = _mm_aesenc_si128(c, ks[round]);
! 172: }
! 173: c = _mm_aesenclast_si128(c, ks[this->key->rounds]);
! 174:
! 175: if (alen)
! 176: {
! 177: blocks = (alen + sizeof(alen)) / AES_BLOCK_SIZE;
! 178: rem = (alen + sizeof(alen)) % AES_BLOCK_SIZE;
! 179: if (rem)
! 180: {
! 181: blocks++;
! 182: }
! 183: for (i = 0; i < blocks; i++)
! 184: {
! 185: if (i == 0)
! 186: { /* first block */
! 187: memset(&b, 0, sizeof(b));
! 188: htoun16(&b, alen);
! 189: memcpy(((u_char*)&b) + sizeof(alen), assoc,
! 190: min(alen, sizeof(b) - sizeof(alen)));
! 191: t = _mm_loadu_si128(&b);
! 192: }
! 193: else if (i == blocks - 1 && rem)
! 194: { /* last block with padding */
! 195: memset(&b, 0, sizeof(b));
! 196: memcpy(&b, ((__m128i*)(assoc - sizeof(alen))) + i, rem);
! 197: t = _mm_loadu_si128(&b);
! 198: }
! 199: else
! 200: { /* full block */
! 201: t = _mm_loadu_si128(((__m128i*)(assoc - sizeof(alen))) + i);
! 202: }
! 203: c = _mm_xor_si128(t, c);
! 204: c = _mm_xor_si128(c, ks[0]);
! 205: for (round = 1; round < this->key->rounds; round++)
! 206: {
! 207: c = _mm_aesenc_si128(c, ks[round]);
! 208: }
! 209: c = _mm_aesenclast_si128(c, ks[this->key->rounds]);
! 210: }
! 211: }
! 212: return c;
! 213: }
! 214:
! 215: /**
! 216: * En-/Decrypt the ICV, trim and store it
! 217: */
! 218: static void crypt_icv(private_aesni_ccm_t *this, u_char *iv,
! 219: __m128i c, u_char *icv)
! 220: {
! 221: __m128i *ks, b, t;
! 222: u_int round;
! 223:
! 224: ks = this->key->schedule;
! 225: build_ctr(this, 0, iv, &b);
! 226:
! 227: t = _mm_loadu_si128(&b);
! 228: t = _mm_xor_si128(t, ks[0]);
! 229: for (round = 1; round < this->key->rounds; round++)
! 230: {
! 231: t = _mm_aesenc_si128(t, ks[round]);
! 232: }
! 233: t = _mm_aesenclast_si128(t, ks[this->key->rounds]);
! 234:
! 235: t = _mm_xor_si128(t, c);
! 236:
! 237: _mm_storeu_si128(&b, t);
! 238: memcpy(icv, &b, this->icv_size);
! 239: }
! 240:
! 241: /**
! 242: * Do big-endian increment on x
! 243: */
! 244: static inline __m128i increment_be(__m128i x)
! 245: {
! 246: __m128i swap;
! 247:
! 248: swap = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
! 249:
! 250: x = _mm_shuffle_epi8(x, swap);
! 251: x = _mm_add_epi64(x, _mm_set_epi32(0, 0, 0, 1));
! 252: x = _mm_shuffle_epi8(x, swap);
! 253:
! 254: return x;
! 255: }
! 256:
! 257: /**
! 258: * Encrypt a remaining incomplete block
! 259: */
! 260: static __m128i encrypt_ccm_rem(aesni_key_t *key, u_int rem, __m128i state,
! 261: void *in, void *out, __m128i c)
! 262: {
! 263: __m128i *ks, t, b, d;
! 264: u_int round;
! 265:
! 266: ks = key->schedule;
! 267: memset(&b, 0, sizeof(b));
! 268: memcpy(&b, in, rem);
! 269: d = _mm_loadu_si128(&b);
! 270:
! 271: c = _mm_xor_si128(d, c);
! 272: c = _mm_xor_si128(c, ks[0]);
! 273: t = _mm_xor_si128(state, ks[0]);
! 274: for (round = 1; round < key->rounds; round++)
! 275: {
! 276: c = _mm_aesenc_si128(c, ks[round]);
! 277: t = _mm_aesenc_si128(t, ks[round]);
! 278: }
! 279: c = _mm_aesenclast_si128(c, ks[key->rounds]);
! 280: t = _mm_aesenclast_si128(t, ks[key->rounds]);
! 281:
! 282: t = _mm_xor_si128(t, d);
! 283: _mm_storeu_si128(&b, t);
! 284:
! 285: memcpy(out, &b, rem);
! 286:
! 287: return c;
! 288: }
! 289:
! 290: /**
! 291: * Decrypt a remaining incomplete block
! 292: */
! 293: static __m128i decrypt_ccm_rem(aesni_key_t *key, u_int rem, __m128i state,
! 294: void *in, void *out, __m128i c)
! 295: {
! 296: __m128i *ks, t, b, d;
! 297: u_int round;
! 298:
! 299: ks = key->schedule;
! 300: memset(&b, 0, sizeof(b));
! 301: memcpy(&b, in, rem);
! 302: d = _mm_loadu_si128(&b);
! 303:
! 304: t = _mm_xor_si128(state, ks[0]);
! 305: for (round = 1; round < key->rounds; round++)
! 306: {
! 307: t = _mm_aesenc_si128(t, ks[round]);
! 308: }
! 309: t = _mm_aesenclast_si128(t, ks[key->rounds]);
! 310: t = _mm_xor_si128(t, d);
! 311: _mm_storeu_si128(&b, t);
! 312:
! 313: memset((u_char*)&b + rem, 0, sizeof(b) - rem);
! 314: t = _mm_loadu_si128(&b);
! 315: c = _mm_xor_si128(t, c);
! 316: c = _mm_xor_si128(c, ks[0]);
! 317: for (round = 1; round < key->rounds; round++)
! 318: {
! 319: c = _mm_aesenc_si128(c, ks[round]);
! 320: }
! 321: c = _mm_aesenclast_si128(c, ks[key->rounds]);
! 322:
! 323: memcpy(out, &b, rem);
! 324:
! 325: return c;
! 326: }
! 327:
! 328: /**
! 329: * AES-128 CCM encryption/ICV generation
! 330: */
! 331: static void encrypt_ccm128(private_aesni_ccm_t *this,
! 332: size_t len, u_char *in, u_char *out, u_char *iv,
! 333: size_t alen, u_char *assoc, u_char *icv)
! 334: {
! 335: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 336: u_int blocks, rem, i;
! 337:
! 338: c = icv_header(this, len, iv, alen, assoc);
! 339: build_ctr(this, 1, iv, &b);
! 340: state = _mm_load_si128(&b);
! 341: blocks = len / AES_BLOCK_SIZE;
! 342: rem = len % AES_BLOCK_SIZE;
! 343: bi = (__m128i*)in;
! 344: bo = (__m128i*)out;
! 345:
! 346: ks = this->key->schedule;
! 347:
! 348: for (i = 0; i < blocks; i++)
! 349: {
! 350: d = _mm_loadu_si128(bi + i);
! 351:
! 352: c = _mm_xor_si128(d, c);
! 353: c = _mm_xor_si128(c, ks[0]);
! 354: t = _mm_xor_si128(state, ks[0]);
! 355:
! 356: c = _mm_aesenc_si128(c, ks[1]);
! 357: t = _mm_aesenc_si128(t, ks[1]);
! 358: c = _mm_aesenc_si128(c, ks[2]);
! 359: t = _mm_aesenc_si128(t, ks[2]);
! 360: c = _mm_aesenc_si128(c, ks[3]);
! 361: t = _mm_aesenc_si128(t, ks[3]);
! 362: c = _mm_aesenc_si128(c, ks[4]);
! 363: t = _mm_aesenc_si128(t, ks[4]);
! 364: c = _mm_aesenc_si128(c, ks[5]);
! 365: t = _mm_aesenc_si128(t, ks[5]);
! 366: c = _mm_aesenc_si128(c, ks[6]);
! 367: t = _mm_aesenc_si128(t, ks[6]);
! 368: c = _mm_aesenc_si128(c, ks[7]);
! 369: t = _mm_aesenc_si128(t, ks[7]);
! 370: c = _mm_aesenc_si128(c, ks[8]);
! 371: t = _mm_aesenc_si128(t, ks[8]);
! 372: c = _mm_aesenc_si128(c, ks[9]);
! 373: t = _mm_aesenc_si128(t, ks[9]);
! 374:
! 375: c = _mm_aesenclast_si128(c, ks[10]);
! 376: t = _mm_aesenclast_si128(t, ks[10]);
! 377:
! 378: t = _mm_xor_si128(t, d);
! 379: _mm_storeu_si128(bo + i, t);
! 380:
! 381: state = increment_be(state);
! 382: }
! 383:
! 384: if (rem)
! 385: {
! 386: c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 387: }
! 388: crypt_icv(this, iv, c, icv);
! 389: }
! 390:
! 391: /**
! 392: * AES-128 CCM decryption/ICV generation
! 393: */
! 394: static void decrypt_ccm128(private_aesni_ccm_t *this,
! 395: size_t len, u_char *in, u_char *out, u_char *iv,
! 396: size_t alen, u_char *assoc, u_char *icv)
! 397: {
! 398: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 399: u_int blocks, rem, i;
! 400:
! 401: c = icv_header(this, len, iv, alen, assoc);
! 402: build_ctr(this, 1, iv, &b);
! 403: state = _mm_load_si128(&b);
! 404: blocks = len / AES_BLOCK_SIZE;
! 405: rem = len % AES_BLOCK_SIZE;
! 406: bi = (__m128i*)in;
! 407: bo = (__m128i*)out;
! 408:
! 409: ks = this->key->schedule;
! 410:
! 411: for (i = 0; i < blocks; i++)
! 412: {
! 413: d = _mm_loadu_si128(bi + i);
! 414:
! 415: t = _mm_xor_si128(state, ks[0]);
! 416:
! 417: t = _mm_aesenc_si128(t, ks[1]);
! 418: t = _mm_aesenc_si128(t, ks[2]);
! 419: t = _mm_aesenc_si128(t, ks[3]);
! 420: t = _mm_aesenc_si128(t, ks[4]);
! 421: t = _mm_aesenc_si128(t, ks[5]);
! 422: t = _mm_aesenc_si128(t, ks[6]);
! 423: t = _mm_aesenc_si128(t, ks[7]);
! 424: t = _mm_aesenc_si128(t, ks[8]);
! 425: t = _mm_aesenc_si128(t, ks[9]);
! 426:
! 427: t = _mm_aesenclast_si128(t, ks[10]);
! 428: t = _mm_xor_si128(t, d);
! 429: _mm_storeu_si128(bo + i, t);
! 430:
! 431: c = _mm_xor_si128(t, c);
! 432: c = _mm_xor_si128(c, ks[0]);
! 433:
! 434: c = _mm_aesenc_si128(c, ks[1]);
! 435: c = _mm_aesenc_si128(c, ks[2]);
! 436: c = _mm_aesenc_si128(c, ks[3]);
! 437: c = _mm_aesenc_si128(c, ks[4]);
! 438: c = _mm_aesenc_si128(c, ks[5]);
! 439: c = _mm_aesenc_si128(c, ks[6]);
! 440: c = _mm_aesenc_si128(c, ks[7]);
! 441: c = _mm_aesenc_si128(c, ks[8]);
! 442: c = _mm_aesenc_si128(c, ks[9]);
! 443:
! 444: c = _mm_aesenclast_si128(c, ks[10]);
! 445:
! 446: state = increment_be(state);
! 447: }
! 448:
! 449: if (rem)
! 450: {
! 451: c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 452: }
! 453: crypt_icv(this, iv, c, icv);
! 454: }
! 455:
! 456: /**
! 457: * AES-192 CCM encryption/ICV generation
! 458: */
! 459: static void encrypt_ccm192(private_aesni_ccm_t *this,
! 460: size_t len, u_char *in, u_char *out, u_char *iv,
! 461: size_t alen, u_char *assoc, u_char *icv)
! 462: {
! 463: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 464: u_int blocks, rem, i;
! 465:
! 466: c = icv_header(this, len, iv, alen, assoc);
! 467: build_ctr(this, 1, iv, &b);
! 468: state = _mm_load_si128(&b);
! 469: blocks = len / AES_BLOCK_SIZE;
! 470: rem = len % AES_BLOCK_SIZE;
! 471: bi = (__m128i*)in;
! 472: bo = (__m128i*)out;
! 473:
! 474: ks = this->key->schedule;
! 475:
! 476: for (i = 0; i < blocks; i++)
! 477: {
! 478: d = _mm_loadu_si128(bi + i);
! 479:
! 480: c = _mm_xor_si128(d, c);
! 481: c = _mm_xor_si128(c, ks[0]);
! 482: t = _mm_xor_si128(state, ks[0]);
! 483:
! 484: c = _mm_aesenc_si128(c, ks[1]);
! 485: t = _mm_aesenc_si128(t, ks[1]);
! 486: c = _mm_aesenc_si128(c, ks[2]);
! 487: t = _mm_aesenc_si128(t, ks[2]);
! 488: c = _mm_aesenc_si128(c, ks[3]);
! 489: t = _mm_aesenc_si128(t, ks[3]);
! 490: c = _mm_aesenc_si128(c, ks[4]);
! 491: t = _mm_aesenc_si128(t, ks[4]);
! 492: c = _mm_aesenc_si128(c, ks[5]);
! 493: t = _mm_aesenc_si128(t, ks[5]);
! 494: c = _mm_aesenc_si128(c, ks[6]);
! 495: t = _mm_aesenc_si128(t, ks[6]);
! 496: c = _mm_aesenc_si128(c, ks[7]);
! 497: t = _mm_aesenc_si128(t, ks[7]);
! 498: c = _mm_aesenc_si128(c, ks[8]);
! 499: t = _mm_aesenc_si128(t, ks[8]);
! 500: c = _mm_aesenc_si128(c, ks[9]);
! 501: t = _mm_aesenc_si128(t, ks[9]);
! 502: c = _mm_aesenc_si128(c, ks[10]);
! 503: t = _mm_aesenc_si128(t, ks[10]);
! 504: c = _mm_aesenc_si128(c, ks[11]);
! 505: t = _mm_aesenc_si128(t, ks[11]);
! 506:
! 507: c = _mm_aesenclast_si128(c, ks[12]);
! 508: t = _mm_aesenclast_si128(t, ks[12]);
! 509:
! 510: t = _mm_xor_si128(t, d);
! 511: _mm_storeu_si128(bo + i, t);
! 512:
! 513: state = increment_be(state);
! 514: }
! 515:
! 516: if (rem)
! 517: {
! 518: c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 519: }
! 520: crypt_icv(this, iv, c, icv);
! 521: }
! 522:
! 523: /**
! 524: * AES-192 CCM decryption/ICV generation
! 525: */
! 526: static void decrypt_ccm192(private_aesni_ccm_t *this,
! 527: size_t len, u_char *in, u_char *out, u_char *iv,
! 528: size_t alen, u_char *assoc, u_char *icv)
! 529: {
! 530: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 531: u_int blocks, rem, i;
! 532:
! 533: c = icv_header(this, len, iv, alen, assoc);
! 534: build_ctr(this, 1, iv, &b);
! 535: state = _mm_load_si128(&b);
! 536: blocks = len / AES_BLOCK_SIZE;
! 537: rem = len % AES_BLOCK_SIZE;
! 538: bi = (__m128i*)in;
! 539: bo = (__m128i*)out;
! 540:
! 541: ks = this->key->schedule;
! 542:
! 543: for (i = 0; i < blocks; i++)
! 544: {
! 545: d = _mm_loadu_si128(bi + i);
! 546:
! 547: t = _mm_xor_si128(state, ks[0]);
! 548:
! 549: t = _mm_aesenc_si128(t, ks[1]);
! 550: t = _mm_aesenc_si128(t, ks[2]);
! 551: t = _mm_aesenc_si128(t, ks[3]);
! 552: t = _mm_aesenc_si128(t, ks[4]);
! 553: t = _mm_aesenc_si128(t, ks[5]);
! 554: t = _mm_aesenc_si128(t, ks[6]);
! 555: t = _mm_aesenc_si128(t, ks[7]);
! 556: t = _mm_aesenc_si128(t, ks[8]);
! 557: t = _mm_aesenc_si128(t, ks[9]);
! 558: t = _mm_aesenc_si128(t, ks[10]);
! 559: t = _mm_aesenc_si128(t, ks[11]);
! 560:
! 561: t = _mm_aesenclast_si128(t, ks[12]);
! 562: t = _mm_xor_si128(t, d);
! 563: _mm_storeu_si128(bo + i, t);
! 564:
! 565: c = _mm_xor_si128(t, c);
! 566: c = _mm_xor_si128(c, ks[0]);
! 567:
! 568: c = _mm_aesenc_si128(c, ks[1]);
! 569: c = _mm_aesenc_si128(c, ks[2]);
! 570: c = _mm_aesenc_si128(c, ks[3]);
! 571: c = _mm_aesenc_si128(c, ks[4]);
! 572: c = _mm_aesenc_si128(c, ks[5]);
! 573: c = _mm_aesenc_si128(c, ks[6]);
! 574: c = _mm_aesenc_si128(c, ks[7]);
! 575: c = _mm_aesenc_si128(c, ks[8]);
! 576: c = _mm_aesenc_si128(c, ks[9]);
! 577: c = _mm_aesenc_si128(c, ks[10]);
! 578: c = _mm_aesenc_si128(c, ks[11]);
! 579:
! 580: c = _mm_aesenclast_si128(c, ks[12]);
! 581:
! 582: state = increment_be(state);
! 583: }
! 584:
! 585: if (rem)
! 586: {
! 587: c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 588: }
! 589: crypt_icv(this, iv, c, icv);
! 590: }
! 591:
! 592: /**
! 593: * AES-256 CCM encryption/ICV generation
! 594: */
! 595: static void encrypt_ccm256(private_aesni_ccm_t *this,
! 596: size_t len, u_char *in, u_char *out, u_char *iv,
! 597: size_t alen, u_char *assoc, u_char *icv)
! 598: {
! 599: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 600: u_int blocks, rem, i;
! 601:
! 602: c = icv_header(this, len, iv, alen, assoc);
! 603: build_ctr(this, 1, iv, &b);
! 604: state = _mm_load_si128(&b);
! 605: blocks = len / AES_BLOCK_SIZE;
! 606: rem = len % AES_BLOCK_SIZE;
! 607: bi = (__m128i*)in;
! 608: bo = (__m128i*)out;
! 609:
! 610: ks = this->key->schedule;
! 611:
! 612: for (i = 0; i < blocks; i++)
! 613: {
! 614: d = _mm_loadu_si128(bi + i);
! 615:
! 616: c = _mm_xor_si128(d, c);
! 617: c = _mm_xor_si128(c, ks[0]);
! 618: t = _mm_xor_si128(state, ks[0]);
! 619:
! 620: c = _mm_aesenc_si128(c, ks[1]);
! 621: t = _mm_aesenc_si128(t, ks[1]);
! 622: c = _mm_aesenc_si128(c, ks[2]);
! 623: t = _mm_aesenc_si128(t, ks[2]);
! 624: c = _mm_aesenc_si128(c, ks[3]);
! 625: t = _mm_aesenc_si128(t, ks[3]);
! 626: c = _mm_aesenc_si128(c, ks[4]);
! 627: t = _mm_aesenc_si128(t, ks[4]);
! 628: c = _mm_aesenc_si128(c, ks[5]);
! 629: t = _mm_aesenc_si128(t, ks[5]);
! 630: c = _mm_aesenc_si128(c, ks[6]);
! 631: t = _mm_aesenc_si128(t, ks[6]);
! 632: c = _mm_aesenc_si128(c, ks[7]);
! 633: t = _mm_aesenc_si128(t, ks[7]);
! 634: c = _mm_aesenc_si128(c, ks[8]);
! 635: t = _mm_aesenc_si128(t, ks[8]);
! 636: c = _mm_aesenc_si128(c, ks[9]);
! 637: t = _mm_aesenc_si128(t, ks[9]);
! 638: c = _mm_aesenc_si128(c, ks[10]);
! 639: t = _mm_aesenc_si128(t, ks[10]);
! 640: c = _mm_aesenc_si128(c, ks[11]);
! 641: t = _mm_aesenc_si128(t, ks[11]);
! 642: c = _mm_aesenc_si128(c, ks[12]);
! 643: t = _mm_aesenc_si128(t, ks[12]);
! 644: c = _mm_aesenc_si128(c, ks[13]);
! 645: t = _mm_aesenc_si128(t, ks[13]);
! 646:
! 647: c = _mm_aesenclast_si128(c, ks[14]);
! 648: t = _mm_aesenclast_si128(t, ks[14]);
! 649:
! 650: t = _mm_xor_si128(t, d);
! 651: _mm_storeu_si128(bo + i, t);
! 652:
! 653: state = increment_be(state);
! 654: }
! 655:
! 656: if (rem)
! 657: {
! 658: c = encrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 659: }
! 660: crypt_icv(this, iv, c, icv);
! 661: }
! 662:
! 663: /**
! 664: * AES-256 CCM decryption/ICV generation
! 665: */
! 666: static void decrypt_ccm256(private_aesni_ccm_t *this,
! 667: size_t len, u_char *in, u_char *out, u_char *iv,
! 668: size_t alen, u_char *assoc, u_char *icv)
! 669: {
! 670: __m128i *ks, d, t, c, b, state, *bi, *bo;
! 671: u_int blocks, rem, i;
! 672:
! 673: c = icv_header(this, len, iv, alen, assoc);
! 674: build_ctr(this, 1, iv, &b);
! 675: state = _mm_load_si128(&b);
! 676: blocks = len / AES_BLOCK_SIZE;
! 677: rem = len % AES_BLOCK_SIZE;
! 678: bi = (__m128i*)in;
! 679: bo = (__m128i*)out;
! 680:
! 681: ks = this->key->schedule;
! 682:
! 683: for (i = 0; i < blocks; i++)
! 684: {
! 685: d = _mm_loadu_si128(bi + i);
! 686:
! 687: t = _mm_xor_si128(state, ks[0]);
! 688:
! 689: t = _mm_aesenc_si128(t, ks[1]);
! 690: t = _mm_aesenc_si128(t, ks[2]);
! 691: t = _mm_aesenc_si128(t, ks[3]);
! 692: t = _mm_aesenc_si128(t, ks[4]);
! 693: t = _mm_aesenc_si128(t, ks[5]);
! 694: t = _mm_aesenc_si128(t, ks[6]);
! 695: t = _mm_aesenc_si128(t, ks[7]);
! 696: t = _mm_aesenc_si128(t, ks[8]);
! 697: t = _mm_aesenc_si128(t, ks[9]);
! 698: t = _mm_aesenc_si128(t, ks[10]);
! 699: t = _mm_aesenc_si128(t, ks[11]);
! 700: t = _mm_aesenc_si128(t, ks[12]);
! 701: t = _mm_aesenc_si128(t, ks[13]);
! 702:
! 703: t = _mm_aesenclast_si128(t, ks[14]);
! 704: t = _mm_xor_si128(t, d);
! 705: _mm_storeu_si128(bo + i, t);
! 706:
! 707: c = _mm_xor_si128(t, c);
! 708: c = _mm_xor_si128(c, ks[0]);
! 709:
! 710: c = _mm_aesenc_si128(c, ks[1]);
! 711: c = _mm_aesenc_si128(c, ks[2]);
! 712: c = _mm_aesenc_si128(c, ks[3]);
! 713: c = _mm_aesenc_si128(c, ks[4]);
! 714: c = _mm_aesenc_si128(c, ks[5]);
! 715: c = _mm_aesenc_si128(c, ks[6]);
! 716: c = _mm_aesenc_si128(c, ks[7]);
! 717: c = _mm_aesenc_si128(c, ks[8]);
! 718: c = _mm_aesenc_si128(c, ks[9]);
! 719: c = _mm_aesenc_si128(c, ks[10]);
! 720: c = _mm_aesenc_si128(c, ks[11]);
! 721: c = _mm_aesenc_si128(c, ks[12]);
! 722: c = _mm_aesenc_si128(c, ks[13]);
! 723:
! 724: c = _mm_aesenclast_si128(c, ks[14]);
! 725:
! 726: state = increment_be(state);
! 727: }
! 728:
! 729: if (rem)
! 730: {
! 731: c = decrypt_ccm_rem(this->key, rem, state, bi + blocks, bo + blocks, c);
! 732: }
! 733: crypt_icv(this, iv, c, icv);
! 734: }
! 735:
! 736: METHOD(aead_t, encrypt, bool,
! 737: private_aesni_ccm_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
! 738: chunk_t *encr)
! 739: {
! 740: u_char *out;
! 741:
! 742: if (!this->key || iv.len != IV_SIZE)
! 743: {
! 744: return FALSE;
! 745: }
! 746: out = plain.ptr;
! 747: if (encr)
! 748: {
! 749: *encr = chunk_alloc(plain.len + this->icv_size);
! 750: out = encr->ptr;
! 751: }
! 752: this->encrypt(this, plain.len, plain.ptr, out, iv.ptr,
! 753: assoc.len, assoc.ptr, out + plain.len);
! 754: return TRUE;
! 755: }
! 756:
! 757: METHOD(aead_t, decrypt, bool,
! 758: private_aesni_ccm_t *this, chunk_t encr, chunk_t assoc, chunk_t iv,
! 759: chunk_t *plain)
! 760: {
! 761: u_char *out, icv[this->icv_size];
! 762:
! 763: if (!this->key || iv.len != IV_SIZE || encr.len < this->icv_size)
! 764: {
! 765: return FALSE;
! 766: }
! 767: encr.len -= this->icv_size;
! 768: out = encr.ptr;
! 769: if (plain)
! 770: {
! 771: *plain = chunk_alloc(encr.len);
! 772: out = plain->ptr;
! 773: }
! 774:
! 775: this->decrypt(this, encr.len, encr.ptr, out, iv.ptr,
! 776: assoc.len, assoc.ptr, icv);
! 777: return memeq_const(icv, encr.ptr + encr.len, this->icv_size);
! 778: }
! 779:
! 780: METHOD(aead_t, get_block_size, size_t,
! 781: private_aesni_ccm_t *this)
! 782: {
! 783: return 1;
! 784: }
! 785:
! 786: METHOD(aead_t, get_icv_size, size_t,
! 787: private_aesni_ccm_t *this)
! 788: {
! 789: return this->icv_size;
! 790: }
! 791:
! 792: METHOD(aead_t, get_iv_size, size_t,
! 793: private_aesni_ccm_t *this)
! 794: {
! 795: return IV_SIZE;
! 796: }
! 797:
! 798: METHOD(aead_t, get_iv_gen, iv_gen_t*,
! 799: private_aesni_ccm_t *this)
! 800: {
! 801: return this->iv_gen;
! 802: }
! 803:
! 804: METHOD(aead_t, get_key_size, size_t,
! 805: private_aesni_ccm_t *this)
! 806: {
! 807: return this->key_size + SALT_SIZE;
! 808: }
! 809:
! 810: METHOD(aead_t, set_key, bool,
! 811: private_aesni_ccm_t *this, chunk_t key)
! 812: {
! 813: if (key.len != this->key_size + SALT_SIZE)
! 814: {
! 815: return FALSE;
! 816: }
! 817:
! 818: memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
! 819: key.len -= SALT_SIZE;
! 820:
! 821: DESTROY_IF(this->key);
! 822: this->key = aesni_key_create(TRUE, key);
! 823: return TRUE;
! 824: }
! 825:
! 826: METHOD(aead_t, destroy, void,
! 827: private_aesni_ccm_t *this)
! 828: {
! 829: DESTROY_IF(this->key);
! 830: this->iv_gen->destroy(this->iv_gen);
! 831: free_align(this);
! 832: }
! 833:
! 834: /**
! 835: * See header
! 836: */
! 837: aesni_ccm_t *aesni_ccm_create(encryption_algorithm_t algo,
! 838: size_t key_size, size_t salt_size)
! 839: {
! 840: private_aesni_ccm_t *this;
! 841: size_t icv_size;
! 842:
! 843: switch (key_size)
! 844: {
! 845: case 0:
! 846: key_size = 16;
! 847: break;
! 848: case 16:
! 849: case 24:
! 850: case 32:
! 851: break;
! 852: default:
! 853: return NULL;
! 854: }
! 855: if (salt_size && salt_size != SALT_SIZE)
! 856: {
! 857: /* currently not supported */
! 858: return NULL;
! 859: }
! 860: switch (algo)
! 861: {
! 862: case ENCR_AES_CCM_ICV8:
! 863: algo = ENCR_AES_CBC;
! 864: icv_size = 8;
! 865: break;
! 866: case ENCR_AES_CCM_ICV12:
! 867: algo = ENCR_AES_CBC;
! 868: icv_size = 12;
! 869: break;
! 870: case ENCR_AES_CCM_ICV16:
! 871: algo = ENCR_AES_CBC;
! 872: icv_size = 16;
! 873: break;
! 874: default:
! 875: return NULL;
! 876: }
! 877:
! 878: INIT_ALIGN(this, sizeof(__m128i),
! 879: .public = {
! 880: .aead = {
! 881: .encrypt = _encrypt,
! 882: .decrypt = _decrypt,
! 883: .get_block_size = _get_block_size,
! 884: .get_icv_size = _get_icv_size,
! 885: .get_iv_size = _get_iv_size,
! 886: .get_iv_gen = _get_iv_gen,
! 887: .get_key_size = _get_key_size,
! 888: .set_key = _set_key,
! 889: .destroy = _destroy,
! 890: },
! 891: },
! 892: .key_size = key_size,
! 893: .iv_gen = iv_gen_seq_create(),
! 894: .icv_size = icv_size,
! 895: );
! 896:
! 897: switch (key_size)
! 898: {
! 899: case 16:
! 900: this->encrypt = encrypt_ccm128;
! 901: this->decrypt = decrypt_ccm128;
! 902: break;
! 903: case 24:
! 904: this->encrypt = encrypt_ccm192;
! 905: this->decrypt = decrypt_ccm192;
! 906: break;
! 907: case 32:
! 908: this->encrypt = encrypt_ccm256;
! 909: this->decrypt = decrypt_ccm256;
! 910: break;
! 911: }
! 912:
! 913: return &this->public;
! 914: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>