Annotation of embedaddon/strongswan/src/libstrongswan/plugins/gcm/gcm_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 "gcm_aead.h"
! 17:
! 18: #include <limits.h>
! 19: #include <crypto/iv/iv_gen_seq.h>
! 20:
! 21: #define BLOCK_SIZE 16
! 22: #define NONCE_SIZE 12
! 23: #define IV_SIZE 8
! 24: #define SALT_SIZE (NONCE_SIZE - IV_SIZE)
! 25:
! 26: typedef struct private_gcm_aead_t private_gcm_aead_t;
! 27:
! 28: /**
! 29: * Private data of an gcm_aead_t object.
! 30: */
! 31: struct private_gcm_aead_t {
! 32:
! 33: /**
! 34: * Public gcm_aead_t interface.
! 35: */
! 36: gcm_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: * Size of the integrity check value
! 50: */
! 51: size_t icv_size;
! 52:
! 53: /**
! 54: * Salt value
! 55: */
! 56: char salt[SALT_SIZE];
! 57:
! 58: /**
! 59: * GHASH subkey H
! 60: */
! 61: char h[BLOCK_SIZE];
! 62: };
! 63:
! 64: /**
! 65: * Find a suitable word size and network order conversion functions
! 66: */
! 67: #if ULONG_MAX == 18446744073709551615UL && defined(htobe64)
! 68: # define htobeword htobe64
! 69: # define bewordtoh be64toh
! 70: # define SHIFT_WORD_TYPE uint64_t
! 71: #else
! 72: # define htobeword htonl
! 73: # define bewordtoh ntohl
! 74: # define SHIFT_WORD_TYPE uint32_t
! 75: #endif
! 76:
! 77: /**
! 78: * Bitshift a block right by one bit
! 79: */
! 80: static void sr_block(char *block)
! 81: {
! 82: int i;
! 83: SHIFT_WORD_TYPE *word = (SHIFT_WORD_TYPE*)block;
! 84:
! 85: for (i = 0; i < BLOCK_SIZE / sizeof(*word); i++)
! 86: {
! 87: word[i] = bewordtoh(word[i]);
! 88: }
! 89: for (i = BLOCK_SIZE / sizeof(*word) - 1; i >= 0; i--)
! 90: {
! 91: word[i] >>= 1;
! 92: if (i != 0)
! 93: {
! 94: word[i] |= word[i - 1] << (sizeof(*word) * 8 - 1);
! 95: }
! 96: }
! 97: for (i = 0; i < BLOCK_SIZE / sizeof(*word); i++)
! 98: {
! 99: word[i] = htobeword(word[i]);
! 100: }
! 101: }
! 102:
! 103: /**
! 104: * Naive implementation of block multiplication in GF128, no tables
! 105: */
! 106: static void mult_block(char *x, char *y, char *res)
! 107: {
! 108: char z[BLOCK_SIZE], v[BLOCK_SIZE], r;
! 109: int bit, byte;
! 110:
! 111: r = 0xE1;
! 112: memset(z, 0, BLOCK_SIZE);
! 113: memcpy(v, y, BLOCK_SIZE);
! 114:
! 115: for (byte = 0; byte < BLOCK_SIZE; byte++)
! 116: {
! 117: for (bit = 7; bit >= 0; bit--)
! 118: {
! 119: if (x[byte] & (1 << bit))
! 120: {
! 121: memxor(z, v, BLOCK_SIZE);
! 122: }
! 123: if (v[BLOCK_SIZE - 1] & 0x01)
! 124: {
! 125: sr_block(v);
! 126: v[0] ^= r;
! 127: }
! 128: else
! 129: {
! 130: sr_block(v);
! 131: }
! 132: }
! 133: }
! 134: memcpy(res, z, BLOCK_SIZE);
! 135: }
! 136:
! 137: /**
! 138: * GHASH function
! 139: */
! 140: static void ghash(private_gcm_aead_t *this, chunk_t x, char *res)
! 141: {
! 142: char y[BLOCK_SIZE];
! 143:
! 144: memset(y, 0, BLOCK_SIZE);
! 145:
! 146: while (x.len)
! 147: {
! 148: memxor(y, x.ptr, BLOCK_SIZE);
! 149: mult_block(y, this->h, y);
! 150: x = chunk_skip(x, BLOCK_SIZE);
! 151: }
! 152: memcpy(res, y, BLOCK_SIZE);
! 153: }
! 154:
! 155: /**
! 156: * GCTR function, en-/decrypts x inline
! 157: */
! 158: static bool gctr(private_gcm_aead_t *this, char *icb, chunk_t x)
! 159: {
! 160: char cb[BLOCK_SIZE], iv[BLOCK_SIZE], tmp[BLOCK_SIZE];
! 161:
! 162: memset(iv, 0, BLOCK_SIZE);
! 163: memcpy(cb, icb, BLOCK_SIZE);
! 164:
! 165: while (x.len)
! 166: {
! 167: memcpy(tmp, cb, BLOCK_SIZE);
! 168: if (!this->crypter->encrypt(this->crypter, chunk_from_thing(tmp),
! 169: chunk_from_thing(iv), NULL))
! 170: {
! 171: return FALSE;
! 172: }
! 173: memxor(x.ptr, tmp, min(BLOCK_SIZE, x.len));
! 174: chunk_increment(chunk_from_thing(cb));
! 175: x = chunk_skip(x, BLOCK_SIZE);
! 176: }
! 177: return TRUE;
! 178: }
! 179:
! 180: /**
! 181: * Generate the block J0
! 182: */
! 183: static void create_j(private_gcm_aead_t *this, char *iv, char *j)
! 184: {
! 185: memcpy(j, this->salt, SALT_SIZE);
! 186: memcpy(j + SALT_SIZE, iv, IV_SIZE);
! 187: htoun32(j + SALT_SIZE + IV_SIZE, 1);
! 188: }
! 189:
! 190: /**
! 191: * Create GHASH subkey H
! 192: */
! 193: static bool create_h(private_gcm_aead_t *this, char *h)
! 194: {
! 195: char zero[BLOCK_SIZE];
! 196:
! 197: memset(zero, 0, BLOCK_SIZE);
! 198: memset(h, 0, BLOCK_SIZE);
! 199:
! 200: return this->crypter->encrypt(this->crypter, chunk_create(h, BLOCK_SIZE),
! 201: chunk_from_thing(zero), NULL);
! 202: }
! 203:
! 204: /**
! 205: * Encrypt/decrypt
! 206: */
! 207: static bool crypt(private_gcm_aead_t *this, char *j, chunk_t in, chunk_t out)
! 208: {
! 209: char icb[BLOCK_SIZE];
! 210:
! 211: memcpy(icb, j, BLOCK_SIZE);
! 212: chunk_increment(chunk_from_thing(icb));
! 213:
! 214: out.len = in.len;
! 215: if (in.ptr != out.ptr)
! 216: {
! 217: memcpy(out.ptr, in.ptr, in.len);
! 218: }
! 219: return gctr(this, icb, out);
! 220: }
! 221:
! 222: /**
! 223: * Create ICV
! 224: */
! 225: static bool create_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt,
! 226: char *j, char *icv)
! 227: {
! 228: size_t assoc_pad, crypt_pad;
! 229: chunk_t chunk;
! 230: char s[BLOCK_SIZE], *pos;
! 231:
! 232: assoc_pad = (BLOCK_SIZE - (assoc.len % BLOCK_SIZE)) % BLOCK_SIZE;
! 233: crypt_pad = (BLOCK_SIZE - (crypt.len % BLOCK_SIZE)) % BLOCK_SIZE;
! 234:
! 235: /* concatenate data to a new chunk */
! 236: chunk = chunk_alloc(assoc.len + assoc_pad +
! 237: crypt.len + crypt_pad + BLOCK_SIZE);
! 238: pos = chunk.ptr;
! 239: /* add associated data */
! 240: memcpy(pos, assoc.ptr, assoc.len);
! 241: pos += assoc.len;
! 242: memset(pos, 0, assoc_pad);
! 243: pos += assoc_pad;
! 244: /* add encrypted data */
! 245: memcpy(pos, crypt.ptr, crypt.len);
! 246: pos += crypt.len;
! 247: memset(pos, 0, crypt_pad);
! 248: pos += crypt_pad;
! 249: /* write associated len */
! 250: memset(pos, 0, 4);
! 251: pos += 4;
! 252: htoun32(pos, assoc.len * 8);
! 253: pos += 4;
! 254: /* write encrypted length */
! 255: memset(pos, 0, 4);
! 256: pos += 4;
! 257: htoun32(pos, crypt.len * 8);
! 258: pos += 4;
! 259:
! 260: ghash(this, chunk, s);
! 261: free(chunk.ptr);
! 262: if (!gctr(this, j, chunk_from_thing(s)))
! 263: {
! 264: return FALSE;
! 265: }
! 266: memcpy(icv, s, this->icv_size);
! 267: return TRUE;
! 268: }
! 269:
! 270: /**
! 271: * Verify the ICV value
! 272: */
! 273: static bool verify_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt,
! 274: char *j, char *icv)
! 275: {
! 276: char tmp[this->icv_size];
! 277:
! 278: return create_icv(this, assoc, crypt, j, tmp) &&
! 279: memeq_const(tmp, icv, this->icv_size);
! 280: }
! 281:
! 282: METHOD(aead_t, encrypt, bool,
! 283: private_gcm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
! 284: chunk_t *encrypted)
! 285: {
! 286: char j[BLOCK_SIZE];
! 287:
! 288: create_j(this, iv.ptr, j);
! 289:
! 290: if (encrypted)
! 291: {
! 292: *encrypted = chunk_alloc(plain.len + this->icv_size);
! 293: return crypt(this, j, plain, *encrypted) &&
! 294: create_icv(this, assoc,
! 295: chunk_create(encrypted->ptr, encrypted->len - this->icv_size),
! 296: j, encrypted->ptr + encrypted->len - this->icv_size);
! 297: }
! 298: return crypt(this, j, plain, plain) &&
! 299: create_icv(this, assoc, plain, j, plain.ptr + plain.len);
! 300: }
! 301:
! 302: METHOD(aead_t, decrypt, bool,
! 303: private_gcm_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
! 304: chunk_t *plain)
! 305: {
! 306: char j[BLOCK_SIZE];
! 307:
! 308: if (encrypted.len < this->icv_size)
! 309: {
! 310: return FALSE;
! 311: }
! 312:
! 313: create_j(this, iv.ptr, j);
! 314:
! 315: encrypted.len -= this->icv_size;
! 316: if (!verify_icv(this, assoc, encrypted, j, encrypted.ptr + encrypted.len))
! 317: {
! 318: return FALSE;
! 319: }
! 320: if (plain)
! 321: {
! 322: *plain = chunk_alloc(encrypted.len);
! 323: return crypt(this, j, encrypted, *plain);
! 324: }
! 325: return crypt(this, j, encrypted, encrypted);
! 326: }
! 327:
! 328: METHOD(aead_t, get_block_size, size_t,
! 329: private_gcm_aead_t *this)
! 330: {
! 331: return 1;
! 332: }
! 333:
! 334: METHOD(aead_t, get_icv_size, size_t,
! 335: private_gcm_aead_t *this)
! 336: {
! 337: return this->icv_size;
! 338: }
! 339:
! 340: METHOD(aead_t, get_iv_size, size_t,
! 341: private_gcm_aead_t *this)
! 342: {
! 343: return IV_SIZE;
! 344: }
! 345:
! 346: METHOD(aead_t, get_iv_gen, iv_gen_t*,
! 347: private_gcm_aead_t *this)
! 348: {
! 349: return this->iv_gen;
! 350: }
! 351:
! 352: METHOD(aead_t, get_key_size, size_t,
! 353: private_gcm_aead_t *this)
! 354: {
! 355: return this->crypter->get_key_size(this->crypter) + SALT_SIZE;
! 356: }
! 357:
! 358: METHOD(aead_t, set_key, bool,
! 359: private_gcm_aead_t *this, chunk_t key)
! 360: {
! 361: memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE);
! 362: key.len -= SALT_SIZE;
! 363: return this->crypter->set_key(this->crypter, key) &&
! 364: create_h(this, this->h);
! 365: }
! 366:
! 367: METHOD(aead_t, destroy, void,
! 368: private_gcm_aead_t *this)
! 369: {
! 370: this->crypter->destroy(this->crypter);
! 371: this->iv_gen->destroy(this->iv_gen);
! 372: free(this);
! 373: }
! 374:
! 375: /**
! 376: * See header
! 377: */
! 378: gcm_aead_t *gcm_aead_create(encryption_algorithm_t algo,
! 379: size_t key_size, size_t salt_size)
! 380: {
! 381: private_gcm_aead_t *this;
! 382: size_t icv_size;
! 383:
! 384: switch (key_size)
! 385: {
! 386: case 0:
! 387: key_size = 16;
! 388: break;
! 389: case 16:
! 390: case 24:
! 391: case 32:
! 392: break;
! 393: default:
! 394: return NULL;
! 395: }
! 396: if (salt_size && salt_size != SALT_SIZE)
! 397: {
! 398: /* currently not supported */
! 399: return NULL;
! 400: }
! 401: switch (algo)
! 402: {
! 403: case ENCR_AES_GCM_ICV8:
! 404: algo = ENCR_AES_CBC;
! 405: icv_size = 8;
! 406: break;
! 407: case ENCR_AES_GCM_ICV12:
! 408: algo = ENCR_AES_CBC;
! 409: icv_size = 12;
! 410: break;
! 411: case ENCR_AES_GCM_ICV16:
! 412: algo = ENCR_AES_CBC;
! 413: icv_size = 16;
! 414: break;
! 415: default:
! 416: return NULL;
! 417: }
! 418:
! 419: INIT(this,
! 420: .public = {
! 421: .aead = {
! 422: .encrypt = _encrypt,
! 423: .decrypt = _decrypt,
! 424: .get_block_size = _get_block_size,
! 425: .get_icv_size = _get_icv_size,
! 426: .get_iv_size = _get_iv_size,
! 427: .get_iv_gen = _get_iv_gen,
! 428: .get_key_size = _get_key_size,
! 429: .set_key = _set_key,
! 430: .destroy = _destroy,
! 431: },
! 432: },
! 433: .crypter = lib->crypto->create_crypter(lib->crypto, algo, key_size),
! 434: .iv_gen = iv_gen_seq_create(),
! 435: .icv_size = icv_size,
! 436: );
! 437:
! 438: if (!this->crypter)
! 439: {
! 440: free(this);
! 441: return NULL;
! 442: }
! 443:
! 444: return &this->public;
! 445: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>