Annotation of embedaddon/strongswan/src/libstrongswan/plugins/cmac/cmac.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 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 <string.h>
! 17:
! 18: #include "cmac.h"
! 19:
! 20: #include <utils/debug.h>
! 21: #include <crypto/mac.h>
! 22: #include <crypto/prfs/mac_prf.h>
! 23: #include <crypto/signers/mac_signer.h>
! 24:
! 25: typedef struct private_mac_t private_mac_t;
! 26:
! 27: /**
! 28: * Private data of a mac_t object.
! 29: *
! 30: * The variable names are the same as in the RFC.
! 31: */
! 32: struct private_mac_t {
! 33:
! 34: /**
! 35: * Public interface.
! 36: */
! 37: mac_t public;
! 38:
! 39: /**
! 40: * Block size, in bytes
! 41: */
! 42: uint8_t b;
! 43:
! 44: /**
! 45: * Crypter with key K
! 46: */
! 47: crypter_t *k;
! 48:
! 49: /**
! 50: * K1
! 51: */
! 52: uint8_t *k1;
! 53:
! 54: /**
! 55: * K2
! 56: */
! 57: uint8_t *k2;
! 58:
! 59: /**
! 60: * T
! 61: */
! 62: uint8_t *t;
! 63:
! 64: /**
! 65: * remaining, unprocessed bytes in append mode
! 66: */
! 67: uint8_t *remaining;
! 68:
! 69: /**
! 70: * number of bytes in remaining
! 71: */
! 72: int remaining_bytes;
! 73: };
! 74:
! 75: /**
! 76: * process supplied data, but do not run final operation
! 77: */
! 78: static bool update(private_mac_t *this, chunk_t data)
! 79: {
! 80: chunk_t iv;
! 81:
! 82: if (this->remaining_bytes + data.len <= this->b)
! 83: { /* no complete block (or last block), just copy into remaining */
! 84: memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len);
! 85: this->remaining_bytes += data.len;
! 86: return TRUE;
! 87: }
! 88:
! 89: iv = chunk_alloca(this->b);
! 90: memset(iv.ptr, 0, iv.len);
! 91:
! 92: /* T := 0x00000000000000000000000000000000 (initially)
! 93: * for each block M_i (except the last)
! 94: * X := T XOR M_i;
! 95: * T := AES-128(K, X);
! 96: */
! 97:
! 98: /* append data to remaining bytes, process block M_1 */
! 99: memcpy(this->remaining + this->remaining_bytes, data.ptr,
! 100: this->b - this->remaining_bytes);
! 101: data = chunk_skip(data, this->b - this->remaining_bytes);
! 102: memxor(this->t, this->remaining, this->b);
! 103: if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
! 104: {
! 105: return FALSE;
! 106: }
! 107:
! 108: /* process blocks M_2 ... M_n-1 */
! 109: while (data.len > this->b)
! 110: {
! 111: memcpy(this->remaining, data.ptr, this->b);
! 112: data = chunk_skip(data, this->b);
! 113: memxor(this->t, this->remaining, this->b);
! 114: if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
! 115: {
! 116: return FALSE;
! 117: }
! 118: }
! 119:
! 120: /* store remaining bytes of block M_n */
! 121: memcpy(this->remaining, data.ptr, data.len);
! 122: this->remaining_bytes = data.len;
! 123:
! 124: return TRUE;
! 125: }
! 126:
! 127: /**
! 128: * process last block M_last
! 129: */
! 130: static bool final(private_mac_t *this, uint8_t *out)
! 131: {
! 132: chunk_t iv;
! 133:
! 134: iv = chunk_alloca(this->b);
! 135: memset(iv.ptr, 0, iv.len);
! 136:
! 137: /* if last block is complete
! 138: * M_last := M_n XOR K1;
! 139: * else
! 140: * M_last := padding(M_n) XOR K2;
! 141: */
! 142: if (this->remaining_bytes == this->b)
! 143: {
! 144: memxor(this->remaining, this->k1, this->b);
! 145: }
! 146: else
! 147: {
! 148: /* padding(x) = x || 10^i where i is 128-8*r-1
! 149: * That is, padding(x) is the concatenation of x and a single '1',
! 150: * followed by the minimum number of '0's, so that the total length is
! 151: * equal to 128 bits.
! 152: */
! 153: if (this->remaining_bytes < this->b)
! 154: {
! 155: this->remaining[this->remaining_bytes] = 0x80;
! 156: while (++this->remaining_bytes < this->b)
! 157: {
! 158: this->remaining[this->remaining_bytes] = 0x00;
! 159: }
! 160: }
! 161: memxor(this->remaining, this->k2, this->b);
! 162: }
! 163: /* T := M_last XOR T;
! 164: * T := AES-128(K,T);
! 165: */
! 166: memxor(this->t, this->remaining, this->b);
! 167: if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL))
! 168: {
! 169: return FALSE;
! 170: }
! 171:
! 172: memcpy(out, this->t, this->b);
! 173:
! 174: /* reset state */
! 175: memset(this->t, 0, this->b);
! 176: this->remaining_bytes = 0;
! 177:
! 178: return TRUE;
! 179: }
! 180:
! 181: METHOD(mac_t, get_mac, bool,
! 182: private_mac_t *this, chunk_t data, uint8_t *out)
! 183: {
! 184: /* update T, do not process last block */
! 185: if (!update(this, data))
! 186: {
! 187: return FALSE;
! 188: }
! 189:
! 190: if (out)
! 191: { /* if not in append mode, process last block and output result */
! 192: return final(this, out);
! 193: }
! 194: return TRUE;
! 195: }
! 196:
! 197: METHOD(mac_t, get_mac_size, size_t,
! 198: private_mac_t *this)
! 199: {
! 200: return this->b;
! 201: }
! 202:
! 203: /**
! 204: * Left-shift the given chunk by one bit.
! 205: */
! 206: static void bit_shift(chunk_t chunk)
! 207: {
! 208: size_t i;
! 209:
! 210: for (i = 0; i < chunk.len; i++)
! 211: {
! 212: chunk.ptr[i] <<= 1;
! 213: if (i < chunk.len - 1 && chunk.ptr[i + 1] & 0x80)
! 214: {
! 215: chunk.ptr[i] |= 0x01;
! 216: }
! 217: }
! 218: }
! 219:
! 220: /**
! 221: * Apply the following key derivation (in-place):
! 222: * if MSB(C) == 0
! 223: * C := C << 1
! 224: * else
! 225: * C := (C << 1) XOR 0x00000000000000000000000000000087
! 226: */
! 227: static void derive_key(chunk_t chunk)
! 228: {
! 229: if (chunk.ptr[0] & 0x80)
! 230: {
! 231: chunk_t rb;
! 232:
! 233: rb = chunk_alloca(chunk.len);
! 234: memset(rb.ptr, 0, rb.len);
! 235: rb.ptr[rb.len - 1] = 0x87;
! 236: bit_shift(chunk);
! 237: memxor(chunk.ptr, rb.ptr, chunk.len);
! 238: }
! 239: else
! 240: {
! 241: bit_shift(chunk);
! 242: }
! 243: }
! 244:
! 245: METHOD(mac_t, set_key, bool,
! 246: private_mac_t *this, chunk_t key)
! 247: {
! 248: chunk_t resized, iv, l;
! 249:
! 250: memset(this->t, 0, this->b);
! 251: this->remaining_bytes = 0;
! 252:
! 253: /* we support variable keys as defined in RFC 4615 */
! 254: if (key.len == this->b)
! 255: {
! 256: resized = key;
! 257: }
! 258: else
! 259: { /* use cmac recursively to resize longer or shorter keys */
! 260: resized = chunk_alloca(this->b);
! 261: memset(resized.ptr, 0, resized.len);
! 262: if (!set_key(this, resized) ||
! 263: !get_mac(this, key, resized.ptr))
! 264: {
! 265: return FALSE;
! 266: }
! 267: }
! 268:
! 269: /*
! 270: * Rb = 0x00000000000000000000000000000087
! 271: * L = 0x00000000000000000000000000000000 encrypted with K
! 272: * if MSB(L) == 0
! 273: * K1 = L << 1
! 274: * else
! 275: * K1 = (L << 1) XOR Rb
! 276: * if MSB(K1) == 0
! 277: * K2 = K1 << 1
! 278: * else
! 279: * K2 = (K1 << 1) XOR Rb
! 280: */
! 281: iv = chunk_alloca(this->b);
! 282: memset(iv.ptr, 0, iv.len);
! 283: l = chunk_alloca(this->b);
! 284: memset(l.ptr, 0, l.len);
! 285: if (!this->k->set_key(this->k, resized) ||
! 286: !this->k->encrypt(this->k, l, iv, NULL))
! 287: {
! 288: return FALSE;
! 289: }
! 290: derive_key(l);
! 291: memcpy(this->k1, l.ptr, l.len);
! 292: derive_key(l);
! 293: memcpy(this->k2, l.ptr, l.len);
! 294: memwipe(l.ptr, l.len);
! 295:
! 296: return TRUE;
! 297: }
! 298:
! 299: METHOD(mac_t, destroy, void,
! 300: private_mac_t *this)
! 301: {
! 302: this->k->destroy(this->k);
! 303: memwipe(this->k1, this->b);
! 304: free(this->k1);
! 305: memwipe(this->k2, this->b);
! 306: free(this->k2);
! 307: free(this->t);
! 308: free(this->remaining);
! 309: free(this);
! 310: }
! 311:
! 312: /*
! 313: * Described in header
! 314: */
! 315: mac_t *cmac_create(encryption_algorithm_t algo, size_t key_size)
! 316: {
! 317: private_mac_t *this;
! 318: crypter_t *crypter;
! 319: uint8_t b;
! 320:
! 321: crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
! 322: if (!crypter)
! 323: {
! 324: return NULL;
! 325: }
! 326: b = crypter->get_block_size(crypter);
! 327: /* input and output of crypter must be equal for cmac */
! 328: if (b != key_size)
! 329: {
! 330: crypter->destroy(crypter);
! 331: return NULL;
! 332: }
! 333:
! 334: INIT(this,
! 335: .public = {
! 336: .get_mac = _get_mac,
! 337: .get_mac_size = _get_mac_size,
! 338: .set_key = _set_key,
! 339: .destroy = _destroy,
! 340: },
! 341: .b = b,
! 342: .k = crypter,
! 343: .k1 = malloc(b),
! 344: .k2 = malloc(b),
! 345: .t = malloc(b),
! 346: .remaining = malloc(b),
! 347: );
! 348: memset(this->t, 0, b);
! 349:
! 350: return &this->public;
! 351: }
! 352:
! 353: /*
! 354: * Described in header.
! 355: */
! 356: prf_t *cmac_prf_create(pseudo_random_function_t algo)
! 357: {
! 358: mac_t *cmac;
! 359:
! 360: switch (algo)
! 361: {
! 362: case PRF_AES128_CMAC:
! 363: cmac = cmac_create(ENCR_AES_CBC, 16);
! 364: break;
! 365: default:
! 366: return NULL;
! 367: }
! 368: if (cmac)
! 369: {
! 370: return mac_prf_create(cmac);
! 371: }
! 372: return NULL;
! 373: }
! 374:
! 375: /*
! 376: * Described in header
! 377: */
! 378: signer_t *cmac_signer_create(integrity_algorithm_t algo)
! 379: {
! 380: size_t truncation;
! 381: mac_t *cmac;
! 382:
! 383: switch (algo)
! 384: {
! 385: case AUTH_AES_CMAC_96:
! 386: cmac = cmac_create(ENCR_AES_CBC, 16);
! 387: truncation = 12;
! 388: break;
! 389: default:
! 390: return NULL;
! 391: }
! 392: if (cmac)
! 393: {
! 394: return mac_signer_create(cmac, truncation);
! 395: }
! 396: return NULL;
! 397: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>