Annotation of embedaddon/strongswan/src/libstrongswan/plugins/xcbc/xcbc.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012 Tobias Brunner
! 3: * Copyright (C) 2008 Martin Willi
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include <string.h>
! 18:
! 19: #include "xcbc.h"
! 20:
! 21: #include <utils/debug.h>
! 22: #include <crypto/mac.h>
! 23: #include <crypto/prfs/mac_prf.h>
! 24: #include <crypto/signers/mac_signer.h>
! 25:
! 26: typedef struct private_mac_t private_mac_t;
! 27:
! 28: /**
! 29: * Private data of a mac_t object.
! 30: *
! 31: * The variable names are the same as in the RFC.
! 32: */
! 33: struct private_mac_t {
! 34:
! 35: /**
! 36: * Public mac_t interface.
! 37: */
! 38: mac_t public;
! 39:
! 40: /**
! 41: * Block size, in bytes
! 42: */
! 43: uint8_t b;
! 44:
! 45: /**
! 46: * crypter using k1
! 47: */
! 48: crypter_t *k1;
! 49:
! 50: /**
! 51: * k2
! 52: */
! 53: uint8_t *k2;
! 54:
! 55: /**
! 56: * k3
! 57: */
! 58: uint8_t *k3;
! 59:
! 60: /**
! 61: * E
! 62: */
! 63: uint8_t *e;
! 64:
! 65: /**
! 66: * remaining, unprocessed bytes in append mode
! 67: */
! 68: uint8_t *remaining;
! 69:
! 70: /**
! 71: * number of bytes in remaining
! 72: */
! 73: int remaining_bytes;
! 74:
! 75: /**
! 76: * TRUE if we have zero bytes to xcbc in final()
! 77: */
! 78: bool zero;
! 79: };
! 80:
! 81: /**
! 82: * xcbc supplied data, but do not run final operation
! 83: */
! 84: static bool update(private_mac_t *this, chunk_t data)
! 85: {
! 86: chunk_t iv;
! 87:
! 88: if (data.len)
! 89: {
! 90: this->zero = FALSE;
! 91: }
! 92:
! 93: if (this->remaining_bytes + data.len <= this->b)
! 94: { /* no complete block, just copy into remaining */
! 95: memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len);
! 96: this->remaining_bytes += data.len;
! 97: return TRUE;
! 98: }
! 99:
! 100: iv = chunk_alloca(this->b);
! 101: memset(iv.ptr, 0, iv.len);
! 102:
! 103: /* (3) For each block M[i], where i = 1 ... n-1:
! 104: * XOR M[i] with E[i-1], then encrypt the result with Key K1,
! 105: * yielding E[i].
! 106: */
! 107:
! 108: /* append data to remaining bytes, process block M[1] */
! 109: memcpy(this->remaining + this->remaining_bytes, data.ptr,
! 110: this->b - this->remaining_bytes);
! 111: data = chunk_skip(data, this->b - this->remaining_bytes);
! 112: memxor(this->e, this->remaining, this->b);
! 113: if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL))
! 114: {
! 115: return FALSE;
! 116: }
! 117:
! 118: /* process blocks M[2] ... M[n-1] */
! 119: while (data.len > this->b)
! 120: {
! 121: memcpy(this->remaining, data.ptr, this->b);
! 122: data = chunk_skip(data, this->b);
! 123: memxor(this->e, this->remaining, this->b);
! 124: if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b),
! 125: iv, NULL))
! 126: {
! 127: return FALSE;
! 128: }
! 129: }
! 130:
! 131: /* store remaining bytes of block M[n] */
! 132: memcpy(this->remaining, data.ptr, data.len);
! 133: this->remaining_bytes = data.len;
! 134:
! 135: return TRUE;
! 136: }
! 137:
! 138: /**
! 139: * run last round, data is in this->e
! 140: */
! 141: static bool final(private_mac_t *this, uint8_t *out)
! 142: {
! 143: chunk_t iv;
! 144:
! 145: iv = chunk_alloca(this->b);
! 146: memset(iv.ptr, 0, iv.len);
! 147:
! 148: /* (4) For block M[n]: */
! 149: if (this->remaining_bytes == this->b && !this->zero)
! 150: {
! 151: /* a) If the blocksize of M[n] is 128 bits:
! 152: * XOR M[n] with E[n-1] and Key K2, then encrypt the result with
! 153: * Key K1, yielding E[n].
! 154: */
! 155: memxor(this->e, this->remaining, this->b);
! 156: memxor(this->e, this->k2, this->b);
! 157: }
! 158: else
! 159: {
! 160: /* b) If the blocksize of M[n] is less than 128 bits:
! 161: *
! 162: * i) Pad M[n] with a single "1" bit, followed by the number of
! 163: * "0" bits (possibly none) required to increase M[n]'s
! 164: * blocksize to 128 bits.
! 165: */
! 166: if (this->remaining_bytes < this->b)
! 167: {
! 168: this->remaining[this->remaining_bytes] = 0x80;
! 169: while (++this->remaining_bytes < this->b)
! 170: {
! 171: this->remaining[this->remaining_bytes] = 0x00;
! 172: }
! 173: }
! 174: /* ii) XOR M[n] with E[n-1] and Key K3, then encrypt the result
! 175: * with Key K1, yielding E[n].
! 176: */
! 177: memxor(this->e, this->remaining, this->b);
! 178: memxor(this->e, this->k3, this->b);
! 179: }
! 180: if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL))
! 181: {
! 182: return FALSE;
! 183: }
! 184:
! 185: memcpy(out, this->e, this->b);
! 186:
! 187: /* (2) Define E[0] = 0x00000000000000000000000000000000 */
! 188: memset(this->e, 0, this->b);
! 189: this->remaining_bytes = 0;
! 190: this->zero = TRUE;
! 191:
! 192: return TRUE;
! 193: }
! 194:
! 195: METHOD(mac_t, get_mac, bool,
! 196: private_mac_t *this, chunk_t data, uint8_t *out)
! 197: {
! 198: /* update E, do not process last block */
! 199: if (!update(this, data))
! 200: {
! 201: return FALSE;
! 202: }
! 203:
! 204: if (out)
! 205: { /* if not in append mode, process last block and output result */
! 206: return final(this, out);
! 207: }
! 208: return TRUE;
! 209: }
! 210:
! 211: METHOD(mac_t, get_mac_size, size_t,
! 212: private_mac_t *this)
! 213: {
! 214: return this->b;
! 215: }
! 216:
! 217: METHOD(mac_t, set_key, bool,
! 218: private_mac_t *this, chunk_t key)
! 219: {
! 220: chunk_t iv, k1, lengthened;
! 221:
! 222: memset(this->e, 0, this->b);
! 223: this->remaining_bytes = 0;
! 224: this->zero = TRUE;
! 225:
! 226: /* we support variable keys from RFC4434 */
! 227: if (key.len == this->b)
! 228: {
! 229: lengthened = key;
! 230: }
! 231: else if (key.len < this->b)
! 232: { /* pad short keys */
! 233: lengthened = chunk_alloca(this->b);
! 234: memset(lengthened.ptr, 0, lengthened.len);
! 235: memcpy(lengthened.ptr, key.ptr, key.len);
! 236: }
! 237: else
! 238: { /* shorten key using xcbc */
! 239: lengthened = chunk_alloca(this->b);
! 240: memset(lengthened.ptr, 0, lengthened.len);
! 241: if (!set_key(this, lengthened) ||
! 242: !get_mac(this, key, lengthened.ptr))
! 243: {
! 244: return FALSE;
! 245: }
! 246: }
! 247:
! 248: k1 = chunk_alloca(this->b);
! 249: iv = chunk_alloca(this->b);
! 250: memset(iv.ptr, 0, iv.len);
! 251:
! 252: /*
! 253: * (1) Derive 3 128-bit keys (K1, K2 and K3) from the 128-bit secret
! 254: * key K, as follows:
! 255: * K1 = 0x01010101010101010101010101010101 encrypted with Key K
! 256: * K2 = 0x02020202020202020202020202020202 encrypted with Key K
! 257: * K3 = 0x03030303030303030303030303030303 encrypted with Key K
! 258: */
! 259:
! 260: memset(k1.ptr, 0x01, this->b);
! 261: memset(this->k2, 0x02, this->b);
! 262: memset(this->k3, 0x03, this->b);
! 263:
! 264: if (!this->k1->set_key(this->k1, lengthened) ||
! 265: !this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL) ||
! 266: !this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL) ||
! 267: !this->k1->encrypt(this->k1, k1, iv, NULL) ||
! 268: !this->k1->set_key(this->k1, k1))
! 269: {
! 270: memwipe(k1.ptr, k1.len);
! 271: return FALSE;
! 272: }
! 273: memwipe(k1.ptr, k1.len);
! 274: return TRUE;
! 275: }
! 276:
! 277: METHOD(mac_t, destroy, void,
! 278: private_mac_t *this)
! 279: {
! 280: this->k1->destroy(this->k1);
! 281: memwipe(this->k2, this->b);
! 282: free(this->k2);
! 283: memwipe(this->k3, this->b);
! 284: free(this->k3);
! 285: free(this->e);
! 286: free(this->remaining);
! 287: free(this);
! 288: }
! 289:
! 290: /*
! 291: * Described in header
! 292: */
! 293: static mac_t *xcbc_create(encryption_algorithm_t algo, size_t key_size)
! 294: {
! 295: private_mac_t *this;
! 296: crypter_t *crypter;
! 297: uint8_t b;
! 298:
! 299: crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size);
! 300: if (!crypter)
! 301: {
! 302: return NULL;
! 303: }
! 304: b = crypter->get_block_size(crypter);
! 305: /* input and output of crypter must be equal for xcbc */
! 306: if (b != key_size)
! 307: {
! 308: crypter->destroy(crypter);
! 309: return NULL;
! 310: }
! 311:
! 312: INIT(this,
! 313: .public = {
! 314: .get_mac = _get_mac,
! 315: .get_mac_size = _get_mac_size,
! 316: .set_key = _set_key,
! 317: .destroy = _destroy,
! 318: },
! 319: .b = b,
! 320: .k1 = crypter,
! 321: .k2 = malloc(b),
! 322: .k3 = malloc(b),
! 323: .e = malloc(b),
! 324: .remaining = malloc(b),
! 325: .zero = TRUE,
! 326: );
! 327: memset(this->e, 0, b);
! 328:
! 329: return &this->public;
! 330: }
! 331:
! 332: /*
! 333: * Described in header.
! 334: */
! 335: prf_t *xcbc_prf_create(pseudo_random_function_t algo)
! 336: {
! 337: mac_t *xcbc;
! 338:
! 339: switch (algo)
! 340: {
! 341: case PRF_AES128_XCBC:
! 342: xcbc = xcbc_create(ENCR_AES_CBC, 16);
! 343: break;
! 344: case PRF_CAMELLIA128_XCBC:
! 345: xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16);
! 346: break;
! 347: default:
! 348: return NULL;
! 349: }
! 350: if (xcbc)
! 351: {
! 352: return mac_prf_create(xcbc);
! 353: }
! 354: return NULL;
! 355: }
! 356:
! 357: /*
! 358: * Described in header
! 359: */
! 360: signer_t *xcbc_signer_create(integrity_algorithm_t algo)
! 361: {
! 362: size_t trunc;
! 363: mac_t *xcbc;
! 364:
! 365: switch (algo)
! 366: {
! 367: case AUTH_AES_XCBC_96:
! 368: xcbc = xcbc_create(ENCR_AES_CBC, 16);
! 369: trunc = 12;
! 370: break;
! 371: case AUTH_CAMELLIA_XCBC_96:
! 372: xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16);
! 373: trunc = 12;
! 374: break;
! 375: default:
! 376: return NULL;
! 377: }
! 378: if (xcbc)
! 379: {
! 380: return mac_signer_create(xcbc, trunc);
! 381: }
! 382: return NULL;
! 383: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>