Annotation of embedaddon/strongswan/src/libstrongswan/plugins/ccm/ccm_aead.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010 Martin Willi
! 3: * Copyright (C) 2010 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 "ccm_aead.h"
! 17:
! 18: #include <crypto/iv/iv_gen_seq.h>
! 19:
! 20: #define BLOCK_SIZE 16
! 21: #define SALT_SIZE 3
! 22: #define IV_SIZE 8
! 23: #define NONCE_SIZE (SALT_SIZE + IV_SIZE) /* 11 */
! 24: #define Q_SIZE (BLOCK_SIZE - NONCE_SIZE - 1) /* 4 */
! 25:
! 26: typedef struct private_ccm_aead_t private_ccm_aead_t;
! 27:
! 28: /**
! 29: * Private data of an ccm_aead_t object.
! 30: */
! 31: struct private_ccm_aead_t {
! 32:
! 33: /**
! 34: * Public ccm_aead_t interface.
! 35: */
! 36: ccm_aead_t public;
! 37:
! 38: /**
! 39: * Underlying CBC crypter.
! 40: */
! 41: crypter_t *crypter;
! 42:
! 43: /**
! 44: * IV generator.
! 45: */
! 46: iv_gen_t *iv_gen;
! 47:
! 48: /**
! 49: * Length of the integrity check value
! 50: */
! 51: size_t icv_size;
! 52:
! 53: /**
! 54: * salt to add to nonce
! 55: */
! 56: u_char salt[SALT_SIZE];
! 57: };
! 58:
! 59: /**
! 60: * First block with control information
! 61: */
! 62: typedef struct __attribute__((packed)) {
! 63: BITFIELD4(uint8_t,
! 64: /* size of p length field q, as q-1 */
! 65: q_len: 3,
! 66: /* size of our ICV t, as (t-2)/2 */
! 67: t_len: 3,
! 68: /* do we have associated data */
! 69: assoc: 1,
! 70: reserved: 1,
! 71: ) flags;
! 72: /* nonce value */
! 73: struct __attribute__((packed)) {
! 74: u_char salt[SALT_SIZE];
! 75: u_char iv[IV_SIZE];
! 76: } nonce;
! 77: /* length of plain text, q */
! 78: u_char q[Q_SIZE];
! 79: } b0_t;
! 80:
! 81: /**
! 82: * Counter block
! 83: */
! 84: typedef struct __attribute__((packed)) {
! 85: BITFIELD3(uint8_t,
! 86: /* size of p length field q, as q-1 */
! 87: q_len: 3,
! 88: zero: 3,
! 89: reserved: 2,
! 90: ) flags;
! 91: /* nonce value */
! 92: struct __attribute__((packed)) {
! 93: u_char salt[SALT_SIZE];
! 94: u_char iv[IV_SIZE];
! 95: } nonce;
! 96: /* counter value */
! 97: u_char i[Q_SIZE];
! 98: } ctr_t;
! 99:
! 100: /**
! 101: * Build the first block B0
! 102: */
! 103: static void build_b0(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
! 104: chunk_t iv, char *out)
! 105: {
! 106: b0_t *block = (b0_t*)out;
! 107:
! 108: block->flags.reserved = 0;
! 109: block->flags.assoc = assoc.len ? 1 : 0;
! 110: block->flags.t_len = (this->icv_size - 2) / 2;
! 111: block->flags.q_len = Q_SIZE - 1;
! 112: memcpy(block->nonce.salt, this->salt, SALT_SIZE);
! 113: memcpy(block->nonce.iv, iv.ptr, IV_SIZE);
! 114: htoun32(block->q, plain.len);
! 115: }
! 116:
! 117: /**
! 118: * Build a counter block for counter i
! 119: */
! 120: static void build_ctr(private_ccm_aead_t *this, uint32_t i, chunk_t iv,
! 121: char *out)
! 122: {
! 123: ctr_t *ctr = (ctr_t*)out;
! 124:
! 125: ctr->flags.reserved = 0;
! 126: ctr->flags.zero = 0;
! 127: ctr->flags.q_len = Q_SIZE - 1;
! 128: memcpy(ctr->nonce.salt, this->salt, SALT_SIZE);
! 129: memcpy(ctr->nonce.iv, iv.ptr, IV_SIZE);
! 130: htoun32(ctr->i, i);
! 131: }
! 132:
! 133: /**
! 134: * En-/Decrypt data
! 135: */
! 136: static bool crypt_data(private_ccm_aead_t *this, chunk_t iv,
! 137: chunk_t in, chunk_t out)
! 138: {
! 139: char ctr[BLOCK_SIZE];
! 140: char zero[BLOCK_SIZE];
! 141: char block[BLOCK_SIZE];
! 142:
! 143: build_ctr(this, 1, iv, ctr);
! 144: memset(zero, 0, BLOCK_SIZE);
! 145:
! 146: while (in.len > 0)
! 147: {
! 148: memcpy(block, ctr, BLOCK_SIZE);
! 149: if (!this->crypter->encrypt(this->crypter, chunk_from_thing(block),
! 150: chunk_from_thing(zero), NULL))
! 151: {
! 152: return FALSE;
! 153: }
! 154: chunk_increment(chunk_from_thing(ctr));
! 155:
! 156: if (in.ptr != out.ptr)
! 157: {
! 158: memcpy(out.ptr, in.ptr, min(in.len, BLOCK_SIZE));
! 159: }
! 160: memxor(out.ptr, block, min(in.len, BLOCK_SIZE));
! 161: in = chunk_skip(in, BLOCK_SIZE);
! 162: out = chunk_skip(out, BLOCK_SIZE);
! 163: }
! 164: return TRUE;
! 165: }
! 166:
! 167: /**
! 168: * En-/Decrypt the ICV
! 169: */
! 170: static bool crypt_icv(private_ccm_aead_t *this, chunk_t iv, char *icv)
! 171: {
! 172: char ctr[BLOCK_SIZE];
! 173: char zero[BLOCK_SIZE];
! 174:
! 175: build_ctr(this, 0, iv, ctr);
! 176: memset(zero, 0, BLOCK_SIZE);
! 177:
! 178: if (!this->crypter->encrypt(this->crypter, chunk_from_thing(ctr),
! 179: chunk_from_thing(zero), NULL))
! 180: {
! 181: return FALSE;
! 182: }
! 183: memxor(icv, ctr, this->icv_size);
! 184: return TRUE;
! 185: }
! 186:
! 187: /**
! 188: * Create the ICV
! 189: */
! 190: static bool create_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
! 191: chunk_t iv, char *icv)
! 192: {
! 193: char zero[BLOCK_SIZE];
! 194: chunk_t chunk;
! 195: char *pos;
! 196: int r, len;
! 197:
! 198: memset(zero, 0, BLOCK_SIZE);
! 199:
! 200: /* calculate number of blocks, including b0 */
! 201: r = 1;
! 202: if (assoc.len)
! 203: { /* assoc gets a 2 byte length header, gets padded to BLOCK_SIZE */
! 204: r += (2 + assoc.len + BLOCK_SIZE - 1) / BLOCK_SIZE;
! 205: }
! 206: /* plain text gets padded to BLOCK_SIZE */
! 207: r += (plain.len + BLOCK_SIZE - 1) / BLOCK_SIZE;
! 208:
! 209: /* concatenate data to a new chunk */
! 210: chunk = chunk_alloc(r * BLOCK_SIZE);
! 211: /* write control block */
! 212: build_b0(this, plain, assoc, iv, chunk.ptr);
! 213: pos = chunk.ptr + BLOCK_SIZE;
! 214: /* append associated data, with length header */
! 215: if (assoc.len)
! 216: {
! 217: /* currently we support two byte headers only (up to 2^16-2^8 bytes) */
! 218: htoun16(pos, assoc.len);
! 219: memcpy(pos + 2, assoc.ptr, assoc.len);
! 220: pos += 2 + assoc.len;
! 221: /* padding */
! 222: len = (BLOCK_SIZE - ((2 + assoc.len) % BLOCK_SIZE)) % BLOCK_SIZE;
! 223: memset(pos, 0, len);
! 224: pos += len;
! 225: }
! 226: /* write plain data */
! 227: memcpy(pos, plain.ptr, plain.len);
! 228: pos += plain.len;
! 229: /* padding */
! 230: len = (BLOCK_SIZE - (plain.len % BLOCK_SIZE)) % BLOCK_SIZE;
! 231:
! 232: memset(pos, 0, len);
! 233:
! 234: /* encrypt inline with CBC, zero IV */
! 235: if (!this->crypter->encrypt(this->crypter, chunk,
! 236: chunk_from_thing(zero), NULL))
! 237: {
! 238: free(chunk.ptr);
! 239: return FALSE;
! 240: }
! 241: /* copy last icv_size bytes as ICV to output */
! 242: memcpy(icv, chunk.ptr + chunk.len - BLOCK_SIZE, this->icv_size);
! 243:
! 244: free(chunk.ptr);
! 245:
! 246: /* encrypt the ICV value */
! 247: return crypt_icv(this, iv, icv);
! 248: }
! 249:
! 250: /**
! 251: * Verify the ICV
! 252: */
! 253: static bool verify_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc,
! 254: chunk_t iv, char *icv)
! 255: {
! 256: char buf[this->icv_size];
! 257:
! 258: return create_icv(this, plain, assoc, iv, buf) &&
! 259: memeq_const(buf, icv, this->icv_size);
! 260: }
! 261:
! 262: METHOD(aead_t, encrypt, bool,
! 263: private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
! 264: chunk_t *encrypted)
! 265: {
! 266: if (encrypted)
! 267: {
! 268: *encrypted = chunk_alloc(plain.len + this->icv_size);
! 269: return create_icv(this, plain, assoc, iv, encrypted->ptr + plain.len) &&
! 270: crypt_data(this, iv, plain, *encrypted);
! 271: }
! 272: return create_icv(this, plain, assoc, iv, plain.ptr + plain.len) &&
! 273: crypt_data(this, iv, plain, plain);
! 274: }
! 275:
! 276: METHOD(aead_t, decrypt, bool,
! 277: private_ccm_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
! 278: chunk_t *plain)
! 279: {
! 280: if (encrypted.len < this->icv_size)
! 281: {
! 282: return FALSE;
! 283: }
! 284: encrypted.len -= this->icv_size;
! 285: if (plain)
! 286: {
! 287: *plain = chunk_alloc(encrypted.len);
! 288: return crypt_data(this, iv, encrypted, *plain) &&
! 289: verify_icv(this, *plain, assoc, iv,
! 290: encrypted.ptr + encrypted.len);
! 291: }
! 292: return crypt_data(this, iv, encrypted, encrypted) &&
! 293: verify_icv(this, encrypted, assoc, iv,
! 294: encrypted.ptr + encrypted.len);
! 295: }
! 296:
! 297: METHOD(aead_t, get_block_size, size_t,
! 298: private_ccm_aead_t *this)
! 299: {
! 300: return 1;
! 301: }
! 302:
! 303: METHOD(aead_t, get_icv_size, size_t,
! 304: private_ccm_aead_t *this)
! 305: {
! 306: return this->icv_size;
! 307: }
! 308:
! 309: METHOD(aead_t, get_iv_size, size_t,
! 310: private_ccm_aead_t *this)
! 311: {
! 312: return IV_SIZE;
! 313: }
! 314:
! 315: METHOD(aead_t, get_iv_gen, iv_gen_t*,
! 316: private_ccm_aead_t *this)
! 317: {
! 318: return this->iv_gen;
! 319: }
! 320:
! 321: METHOD(aead_t, get_key_size, size_t,
! 322: private_ccm_aead_t *this)
! 323: {
! 324: return this->crypter->get_key_size(this->crypter) + SALT_SIZE;
! 325: }
! 326:
! 327: METHOD(aead_t, set_key, bool,
! 328: private_ccm_aead_t *this, chunk_t key)
! 329: {
! 330: memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
! 331: key.len -= SALT_SIZE;
! 332: return this->crypter->set_key(this->crypter, key);
! 333: }
! 334:
! 335: METHOD(aead_t, destroy, void,
! 336: private_ccm_aead_t *this)
! 337: {
! 338: this->crypter->destroy(this->crypter);
! 339: this->iv_gen->destroy(this->iv_gen);
! 340: free(this);
! 341: }
! 342:
! 343: /**
! 344: * See header
! 345: */
! 346: ccm_aead_t *ccm_aead_create(encryption_algorithm_t algo,
! 347: size_t key_size, size_t salt_size)
! 348: {
! 349: private_ccm_aead_t *this;
! 350: size_t icv_size;
! 351:
! 352: switch (key_size)
! 353: {
! 354: case 0:
! 355: key_size = 16;
! 356: break;
! 357: case 16:
! 358: case 24:
! 359: case 32:
! 360: break;
! 361: default:
! 362: return NULL;
! 363: }
! 364: if (salt_size && salt_size != SALT_SIZE)
! 365: {
! 366: /* currently not supported */
! 367: return NULL;
! 368: }
! 369: switch (algo)
! 370: {
! 371: case ENCR_AES_CCM_ICV8:
! 372: algo = ENCR_AES_CBC;
! 373: icv_size = 8;
! 374: break;
! 375: case ENCR_AES_CCM_ICV12:
! 376: algo = ENCR_AES_CBC;
! 377: icv_size = 12;
! 378: break;
! 379: case ENCR_AES_CCM_ICV16:
! 380: algo = ENCR_AES_CBC;
! 381: icv_size = 16;
! 382: break;
! 383: case ENCR_CAMELLIA_CCM_ICV8:
! 384: algo = ENCR_CAMELLIA_CBC;
! 385: icv_size = 8;
! 386: break;
! 387: case ENCR_CAMELLIA_CCM_ICV12:
! 388: algo = ENCR_CAMELLIA_CBC;
! 389: icv_size = 12;
! 390: break;
! 391: case ENCR_CAMELLIA_CCM_ICV16:
! 392: algo = ENCR_CAMELLIA_CBC;
! 393: icv_size = 16;
! 394: break;
! 395: default:
! 396: return NULL;
! 397: }
! 398:
! 399: INIT(this,
! 400: .public = {
! 401: .aead = {
! 402: .encrypt = _encrypt,
! 403: .decrypt = _decrypt,
! 404: .get_block_size = _get_block_size,
! 405: .get_icv_size = _get_icv_size,
! 406: .get_iv_size = _get_iv_size,
! 407: .get_iv_gen = _get_iv_gen,
! 408: .get_key_size = _get_key_size,
! 409: .set_key = _set_key,
! 410: .destroy = _destroy,
! 411: },
! 412: },
! 413: .crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size),
! 414: .iv_gen = iv_gen_seq_create(),
! 415: .icv_size = icv_size,
! 416: );
! 417:
! 418: if (!this->crypter)
! 419: {
! 420: free(this);
! 421: return NULL;
! 422: }
! 423:
! 424: return &this->public;
! 425: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>