Annotation of embedaddon/strongswan/src/libstrongswan/plugins/aesni/aesni_cmac.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: * Copyright (C) 2015 Martin Willi
! 5: * Copyright (C) 2015 revosec AG
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include "aesni_cmac.h"
! 19: #include "aesni_key.h"
! 20:
! 21: #include <crypto/prfs/mac_prf.h>
! 22: #include <crypto/signers/mac_signer.h>
! 23:
! 24: typedef struct private_mac_t private_mac_t;
! 25:
! 26: /**
! 27: * Private data of a mac_t object.
! 28: */
! 29: struct private_mac_t {
! 30:
! 31: /**
! 32: * Public interface.
! 33: */
! 34: mac_t public;
! 35:
! 36: /**
! 37: * Key schedule for key K
! 38: */
! 39: aesni_key_t *k;
! 40:
! 41: /**
! 42: * K1
! 43: */
! 44: __m128i k1;
! 45:
! 46: /**
! 47: * K2
! 48: */
! 49: __m128i k2;
! 50:
! 51: /**
! 52: * T
! 53: */
! 54: __m128i t;
! 55:
! 56: /**
! 57: * remaining, unprocessed bytes in append mode
! 58: */
! 59: u_char rem[AES_BLOCK_SIZE];
! 60:
! 61: /**
! 62: * number of bytes in remaining
! 63: */
! 64: int rem_size;
! 65: };
! 66:
! 67: METHOD(mac_t, get_mac, bool,
! 68: private_mac_t *this, chunk_t data, uint8_t *out)
! 69: {
! 70: __m128i *ks, t, l, *bi;
! 71: u_int blocks, rem, i;
! 72:
! 73: if (!this->k)
! 74: {
! 75: return FALSE;
! 76: }
! 77:
! 78: ks = this->k->schedule;
! 79: t = this->t;
! 80:
! 81: if (this->rem_size + data.len > AES_BLOCK_SIZE)
! 82: {
! 83: /* T := 0x00000000000000000000000000000000 (initially)
! 84: * for each block M_i (except the last)
! 85: * X := T XOR M_i;
! 86: * T := AES-128(K, X);
! 87: */
! 88:
! 89: /* append data to remaining bytes, process block M_1 */
! 90: memcpy(this->rem + this->rem_size, data.ptr,
! 91: AES_BLOCK_SIZE - this->rem_size);
! 92: data = chunk_skip(data, AES_BLOCK_SIZE - this->rem_size);
! 93:
! 94: t = _mm_xor_si128(t, _mm_loadu_si128((__m128i*)this->rem));
! 95:
! 96: t = _mm_xor_si128(t, ks[0]);
! 97: t = _mm_aesenc_si128(t, ks[1]);
! 98: t = _mm_aesenc_si128(t, ks[2]);
! 99: t = _mm_aesenc_si128(t, ks[3]);
! 100: t = _mm_aesenc_si128(t, ks[4]);
! 101: t = _mm_aesenc_si128(t, ks[5]);
! 102: t = _mm_aesenc_si128(t, ks[6]);
! 103: t = _mm_aesenc_si128(t, ks[7]);
! 104: t = _mm_aesenc_si128(t, ks[8]);
! 105: t = _mm_aesenc_si128(t, ks[9]);
! 106: t = _mm_aesenclast_si128(t, ks[10]);
! 107:
! 108: /* process blocks M_2 ... M_n-1 */
! 109: bi = (__m128i*)data.ptr;
! 110: rem = data.len % AES_BLOCK_SIZE;
! 111: blocks = data.len / AES_BLOCK_SIZE;
! 112: if (!rem && blocks)
! 113: { /* don't do last block */
! 114: rem = AES_BLOCK_SIZE;
! 115: blocks--;
! 116: }
! 117:
! 118: /* process blocks M[2] ... M[n-1] */
! 119: for (i = 0; i < blocks; i++)
! 120: {
! 121: t = _mm_xor_si128(t, _mm_loadu_si128(bi + i));
! 122:
! 123: t = _mm_xor_si128(t, ks[0]);
! 124: t = _mm_aesenc_si128(t, ks[1]);
! 125: t = _mm_aesenc_si128(t, ks[2]);
! 126: t = _mm_aesenc_si128(t, ks[3]);
! 127: t = _mm_aesenc_si128(t, ks[4]);
! 128: t = _mm_aesenc_si128(t, ks[5]);
! 129: t = _mm_aesenc_si128(t, ks[6]);
! 130: t = _mm_aesenc_si128(t, ks[7]);
! 131: t = _mm_aesenc_si128(t, ks[8]);
! 132: t = _mm_aesenc_si128(t, ks[9]);
! 133: t = _mm_aesenclast_si128(t, ks[10]);
! 134: }
! 135:
! 136: /* store remaining bytes of block M_n */
! 137: memcpy(this->rem, data.ptr + data.len - rem, rem);
! 138: this->rem_size = rem;
! 139: }
! 140: else
! 141: {
! 142: /* no complete block (or last block), just copy into remaining */
! 143: memcpy(this->rem + this->rem_size, data.ptr, data.len);
! 144: this->rem_size += data.len;
! 145: }
! 146: if (out)
! 147: {
! 148: /* if last block is complete
! 149: * M_last := M_n XOR K1;
! 150: * else
! 151: * M_last := padding(M_n) XOR K2;
! 152: */
! 153: if (this->rem_size == AES_BLOCK_SIZE)
! 154: {
! 155: l = _mm_loadu_si128((__m128i*)this->rem);
! 156: l = _mm_xor_si128(l, this->k1);
! 157: }
! 158: else
! 159: {
! 160: /* padding(x) = x || 10^i where i is 128-8*r-1
! 161: * That is, padding(x) is the concatenation of x and a single '1',
! 162: * followed by the minimum number of '0's, so that the total length is
! 163: * equal to 128 bits.
! 164: */
! 165: if (this->rem_size < AES_BLOCK_SIZE)
! 166: {
! 167: memset(this->rem + this->rem_size, 0,
! 168: AES_BLOCK_SIZE - this->rem_size);
! 169: this->rem[this->rem_size] = 0x80;
! 170: }
! 171: l = _mm_loadu_si128((__m128i*)this->rem);
! 172: l = _mm_xor_si128(l, this->k2);
! 173: }
! 174: /* T := M_last XOR T;
! 175: * T := AES-128(K,T);
! 176: */
! 177: t = _mm_xor_si128(l, t);
! 178:
! 179: t = _mm_xor_si128(t, ks[0]);
! 180: t = _mm_aesenc_si128(t, ks[1]);
! 181: t = _mm_aesenc_si128(t, ks[2]);
! 182: t = _mm_aesenc_si128(t, ks[3]);
! 183: t = _mm_aesenc_si128(t, ks[4]);
! 184: t = _mm_aesenc_si128(t, ks[5]);
! 185: t = _mm_aesenc_si128(t, ks[6]);
! 186: t = _mm_aesenc_si128(t, ks[7]);
! 187: t = _mm_aesenc_si128(t, ks[8]);
! 188: t = _mm_aesenc_si128(t, ks[9]);
! 189: t = _mm_aesenclast_si128(t, ks[10]);
! 190:
! 191: _mm_storeu_si128((__m128i*)out, t);
! 192:
! 193: /* reset state */
! 194: t = _mm_setzero_si128();
! 195: this->rem_size = 0;
! 196: }
! 197: this->t = t;
! 198: return TRUE;
! 199: }
! 200:
! 201: METHOD(mac_t, get_mac_size, size_t,
! 202: private_mac_t *this)
! 203: {
! 204: return AES_BLOCK_SIZE;
! 205: }
! 206:
! 207: /**
! 208: * Left-shift the given chunk by one bit.
! 209: */
! 210: static void bit_shift(chunk_t chunk)
! 211: {
! 212: size_t i;
! 213:
! 214: for (i = 0; i < chunk.len; i++)
! 215: {
! 216: chunk.ptr[i] <<= 1;
! 217: if (i < chunk.len - 1 && chunk.ptr[i + 1] & 0x80)
! 218: {
! 219: chunk.ptr[i] |= 0x01;
! 220: }
! 221: }
! 222: }
! 223:
! 224: METHOD(mac_t, set_key, bool,
! 225: private_mac_t *this, chunk_t key)
! 226: {
! 227: __m128i rb, msb, l, a;
! 228: u_int round;
! 229: chunk_t k;
! 230:
! 231: this->t = _mm_setzero_si128();
! 232: this->rem_size = 0;
! 233:
! 234: /* we support variable keys as defined in RFC 4615 */
! 235: if (key.len == AES_BLOCK_SIZE)
! 236: {
! 237: k = key;
! 238: }
! 239: else
! 240: { /* use cmac recursively to resize longer or shorter keys */
! 241: k = chunk_alloca(AES_BLOCK_SIZE);
! 242: memset(k.ptr, 0, k.len);
! 243: if (!set_key(this, k) || !get_mac(this, key, k.ptr))
! 244: {
! 245: return FALSE;
! 246: }
! 247: }
! 248:
! 249: DESTROY_IF(this->k);
! 250: this->k = aesni_key_create(TRUE, k);
! 251: if (!this->k)
! 252: {
! 253: return FALSE;
! 254: }
! 255:
! 256: /*
! 257: * Rb = 0x00000000000000000000000000000087
! 258: * L = 0x00000000000000000000000000000000 encrypted with K
! 259: * if MSB(L) == 0
! 260: * K1 = L << 1
! 261: * else
! 262: * K1 = (L << 1) XOR Rb
! 263: * if MSB(K1) == 0
! 264: * K2 = K1 << 1
! 265: * else
! 266: * K2 = (K1 << 1) XOR Rb
! 267: */
! 268:
! 269: rb = _mm_set_epi32(0x87000000, 0, 0, 0);
! 270: msb = _mm_set_epi32(0, 0, 0, 0x80);
! 271:
! 272: l = _mm_setzero_si128();
! 273:
! 274: l = _mm_xor_si128(l, this->k->schedule[0]);
! 275: for (round = 1; round < this->k->rounds; round++)
! 276: {
! 277: l = _mm_aesenc_si128(l, this->k->schedule[round]);
! 278: }
! 279: l = _mm_aesenclast_si128(l, this->k->schedule[this->k->rounds]);
! 280:
! 281: this->k1 = l;
! 282: bit_shift(chunk_from_thing(this->k1));
! 283: a = _mm_and_si128(l, msb);
! 284: if (memchr(&a, 0x80, 1))
! 285: {
! 286: this->k1 = _mm_xor_si128(this->k1, rb);
! 287: }
! 288: this->k2 = this->k1;
! 289: bit_shift(chunk_from_thing(this->k2));
! 290: a = _mm_and_si128(this->k1, msb);
! 291: if (memchr(&a, 0x80, 1))
! 292: {
! 293: this->k2 = _mm_xor_si128(this->k2, rb);
! 294: }
! 295:
! 296: return TRUE;
! 297: }
! 298:
! 299: METHOD(mac_t, destroy, void,
! 300: private_mac_t *this)
! 301: {
! 302: DESTROY_IF(this->k);
! 303: memwipe(&this->k1, sizeof(this->k1));
! 304: memwipe(&this->k2, sizeof(this->k2));
! 305: free_align(this);
! 306: }
! 307:
! 308: /*
! 309: * Described in header
! 310: */
! 311: mac_t *aesni_cmac_create(encryption_algorithm_t algo, size_t key_size)
! 312: {
! 313: private_mac_t *this;
! 314:
! 315: INIT_ALIGN(this, sizeof(__m128i),
! 316: .public = {
! 317: .get_mac = _get_mac,
! 318: .get_mac_size = _get_mac_size,
! 319: .set_key = _set_key,
! 320: .destroy = _destroy,
! 321: },
! 322: );
! 323:
! 324: return &this->public;
! 325: }
! 326:
! 327: /*
! 328: * Described in header.
! 329: */
! 330: prf_t *aesni_cmac_prf_create(pseudo_random_function_t algo)
! 331: {
! 332: mac_t *cmac;
! 333:
! 334: switch (algo)
! 335: {
! 336: case PRF_AES128_CMAC:
! 337: cmac = aesni_cmac_create(ENCR_AES_CBC, 16);
! 338: break;
! 339: default:
! 340: return NULL;
! 341: }
! 342: if (cmac)
! 343: {
! 344: return mac_prf_create(cmac);
! 345: }
! 346: return NULL;
! 347: }
! 348:
! 349: /*
! 350: * Described in header
! 351: */
! 352: signer_t *aesni_cmac_signer_create(integrity_algorithm_t algo)
! 353: {
! 354: size_t truncation;
! 355: mac_t *cmac;
! 356:
! 357: switch (algo)
! 358: {
! 359: case AUTH_AES_CMAC_96:
! 360: cmac = aesni_cmac_create(ENCR_AES_CBC, 16);
! 361: truncation = 12;
! 362: break;
! 363: default:
! 364: return NULL;
! 365: }
! 366: if (cmac)
! 367: {
! 368: return mac_signer_create(cmac, truncation);
! 369: }
! 370: return NULL;
! 371: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>