Annotation of embedaddon/strongswan/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2009 Martin Willi
! 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 "eap_aka_3gpp2_functions.h"
! 17:
! 18: #include <gmp.h>
! 19: #include <limits.h>
! 20:
! 21: #include <daemon.h>
! 22:
! 23: typedef struct private_eap_aka_3gpp2_functions_t private_eap_aka_3gpp2_functions_t;
! 24:
! 25: /**
! 26: * Private data of an eap_aka_3gpp2_functions_t object.
! 27: */
! 28: struct private_eap_aka_3gpp2_functions_t {
! 29:
! 30: /**
! 31: * Public eap_aka_3gpp2_functions_t interface.
! 32: */
! 33: eap_aka_3gpp2_functions_t public;
! 34:
! 35: /**
! 36: * Used keyed SHA1 function, as PRF
! 37: */
! 38: prf_t *prf;
! 39: };
! 40:
! 41: #define AKA_PAYLOAD_LEN 64
! 42:
! 43: #define F1 0x42
! 44: #define F1STAR 0x43
! 45: #define F2 0x44
! 46: #define F3 0x45
! 47: #define F4 0x46
! 48: #define F5 0x47
! 49: #define F5STAR 0x48
! 50:
! 51: /** Family key, as proposed in S.S0055 */
! 52: static chunk_t fmk = chunk_from_chars(0x41, 0x48, 0x41, 0x47);
! 53:
! 54: /**
! 55: * Binary representation of the polynomial T^160 + T^5 + T^3 + T^2 + 1
! 56: */
! 57: static uint8_t g[] = {
! 58: 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 59: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 60: 0x00, 0x00, 0x00, 0x00, 0x2d
! 61: };
! 62:
! 63: /**
! 64: * Predefined random bits from the RAND Corporation book
! 65: */
! 66: static uint8_t a_def[] = {
! 67: 0x9d, 0xe9, 0xc9, 0xc8, 0xef, 0xd5, 0x78, 0x11,
! 68: 0x48, 0x23, 0x14, 0x01, 0x90, 0x1f, 0x2d, 0x49,
! 69: 0x3f, 0x4c, 0x63, 0x65
! 70: };
! 71:
! 72: /**
! 73: * Predefined random bits from the RAND Corporation book
! 74: */
! 75: static uint8_t b_def[] = {
! 76: 0x75, 0xef, 0xd1, 0x5c, 0x4b, 0x8f, 0x8f, 0x51,
! 77: 0x4e, 0xf3, 0xbc, 0xc3, 0x79, 0x4a, 0x76, 0x5e,
! 78: 0x7e, 0xec, 0x45, 0xe0
! 79: };
! 80:
! 81: /**
! 82: * Multiply two mpz_t with bits interpreted as polynomials.
! 83: */
! 84: static void mpz_mul_poly(mpz_t r, mpz_t a, mpz_t b)
! 85: {
! 86: mpz_t bm, rm;
! 87: int current = 0, shifted = 0, shift;
! 88:
! 89: mpz_init_set(bm, b);
! 90: mpz_init_set_ui(rm, 0);
! 91: /* scan through a, for each found bit: */
! 92: while ((current = mpz_scan1(a, current)) != ULONG_MAX)
! 93: {
! 94: /* XOR shifted b into r */
! 95: shift = current - shifted;
! 96: mpz_mul_2exp(bm, bm, shift);
! 97: shifted += shift;
! 98: mpz_xor(rm, rm, bm);
! 99: current++;
! 100: }
! 101:
! 102: mpz_swap(r, rm);
! 103: mpz_clear(rm);
! 104: mpz_clear(bm);
! 105: }
! 106:
! 107: /**
! 108: * Calculate the sum of a + b interpreted as polynomials.
! 109: */
! 110: static void mpz_add_poly(mpz_t res, mpz_t a, mpz_t b)
! 111: {
! 112: /* addition of polynomials is just the XOR */
! 113: mpz_xor(res, a, b);
! 114: }
! 115:
! 116: /**
! 117: * Calculate the remainder of a/b interpreted as polynomials.
! 118: */
! 119: static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b)
! 120: {
! 121: /* Example:
! 122: * a = 10001010
! 123: * b = 00000101
! 124: */
! 125: int a_bit, b_bit, diff;
! 126: mpz_t bm, am;
! 127:
! 128: mpz_init_set(am, a);
! 129: mpz_init(bm);
! 130:
! 131: a_bit = mpz_sizeinbase(a, 2);
! 132: b_bit = mpz_sizeinbase(b, 2);
! 133:
! 134: /* don't do anything if b > a */
! 135: if (a_bit >= b_bit)
! 136: {
! 137: /* shift b left to align up most significant "1" to a:
! 138: * a = 10001010
! 139: * b = 10100000
! 140: */
! 141: mpz_mul_2exp(bm, b, a_bit - b_bit);
! 142: do
! 143: {
! 144: /* XOR b into a, this kills the most significant "1":
! 145: * a = 00101010
! 146: */
! 147: mpz_xor(am, am, bm);
! 148: /* find the next most significant "1" in a, and align up b:
! 149: * a = 00101010
! 150: * b = 00101000
! 151: */
! 152: diff = a_bit - mpz_sizeinbase(am, 2);
! 153: mpz_div_2exp(bm, bm, diff);
! 154: a_bit -= diff;
! 155: }
! 156: while (b_bit <= mpz_sizeinbase(bm, 2));
! 157: /* While b is not shifted to its original value */
! 158: }
! 159: /* after another iteration:
! 160: * a = 00000010
! 161: * which is the polynomial modulo
! 162: */
! 163:
! 164: mpz_swap(r, am);
! 165: mpz_clear(am);
! 166: mpz_clear(bm);
! 167: }
! 168:
! 169: /**
! 170: * Step 3 of the various fx() functions:
! 171: * XOR the key into the SHA1 IV
! 172: */
! 173: static bool step3(prf_t *prf, u_char k[AKA_K_LEN],
! 174: u_char payload[AKA_PAYLOAD_LEN], uint8_t h[HASH_SIZE_SHA1])
! 175: {
! 176: /* use the keyed hasher to build the hash */
! 177: return prf->set_key(prf, chunk_create(k, AKA_K_LEN)) &&
! 178: prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h);
! 179: }
! 180:
! 181: /**
! 182: * Step 4 of the various fx() functions:
! 183: * Polynomial whiten calculations
! 184: */
! 185: static void step4(u_char x[HASH_SIZE_SHA1])
! 186: {
! 187: mpz_t xm, am, bm, gm;
! 188:
! 189: mpz_init(xm);
! 190: mpz_init(am);
! 191: mpz_init(bm);
! 192: mpz_init(gm);
! 193:
! 194: mpz_import(xm, HASH_SIZE_SHA1, 1, 1, 1, 0, x);
! 195: mpz_import(am, sizeof(a_def), 1, 1, 1, 0, a_def);
! 196: mpz_import(bm, sizeof(b_def), 1, 1, 1, 0, b_def);
! 197: mpz_import(gm, sizeof(g), 1, 1, 1, 0, g);
! 198:
! 199: mpz_mul_poly(xm, am, xm);
! 200: mpz_add_poly(xm, bm, xm);
! 201: mpz_mod_poly(xm, xm, gm);
! 202:
! 203: mpz_export(x, NULL, 1, HASH_SIZE_SHA1, 1, 0, xm);
! 204:
! 205: mpz_clear(xm);
! 206: mpz_clear(am);
! 207: mpz_clear(bm);
! 208: mpz_clear(gm);
! 209: }
! 210:
! 211: /**
! 212: * Calculation function for f2(), f3(), f4()
! 213: */
! 214: static bool fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
! 215: u_char rand[AKA_RAND_LEN], u_char out[AKA_MAC_LEN])
! 216: {
! 217: u_char payload[AKA_PAYLOAD_LEN];
! 218: u_char h[HASH_SIZE_SHA1];
! 219: u_char i;
! 220:
! 221: for (i = 0; i < 2; i++)
! 222: {
! 223: memset(payload, 0x5c, AKA_PAYLOAD_LEN);
! 224: payload[11] ^= f;
! 225: memxor(payload + 12, fmk.ptr, fmk.len);
! 226: memxor(payload + 24, rand, AKA_RAND_LEN);
! 227:
! 228: payload[3] ^= i;
! 229: payload[19] ^= i;
! 230: payload[35] ^= i;
! 231: payload[51] ^= i;
! 232:
! 233: if (!step3(prf, k, payload, h))
! 234: {
! 235: return FALSE;
! 236: }
! 237: step4(h);
! 238: memcpy(out + i * 8, h, 8);
! 239: }
! 240: return TRUE;
! 241: }
! 242:
! 243: /**
! 244: * Calculation function of f1() and f1star()
! 245: */
! 246: static bool f1x(prf_t *prf, uint8_t f, u_char k[AKA_K_LEN],
! 247: u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
! 248: u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
! 249: {
! 250: /* generate MAC = f1(FMK, SQN, RAND, AMF)
! 251: * K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit
! 252: * payload which gets hashed
! 253: */
! 254: u_char payload[AKA_PAYLOAD_LEN];
! 255: u_char h[HASH_SIZE_SHA1];
! 256:
! 257: memset(payload, 0x5c, AKA_PAYLOAD_LEN);
! 258: payload[11] ^= f;
! 259: memxor(payload + 12, fmk.ptr, fmk.len);
! 260: memxor(payload + 16, rand, AKA_RAND_LEN);
! 261: memxor(payload + 34, sqn, AKA_SQN_LEN);
! 262: memxor(payload + 42, amf, AKA_AMF_LEN);
! 263:
! 264: if (!step3(prf, k, payload, h))
! 265: {
! 266: return FALSE;
! 267: }
! 268: step4(h);
! 269: memcpy(mac, h, AKA_MAC_LEN);
! 270: return TRUE;
! 271: }
! 272:
! 273: /**
! 274: * Calculation function of f5() and f5star()
! 275: */
! 276: static bool f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
! 277: u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
! 278: {
! 279: u_char payload[AKA_PAYLOAD_LEN];
! 280: u_char h[HASH_SIZE_SHA1];
! 281:
! 282: memset(payload, 0x5c, AKA_PAYLOAD_LEN);
! 283: payload[11] ^= f;
! 284: memxor(payload + 12, fmk.ptr, fmk.len);
! 285: memxor(payload + 16, rand, AKA_RAND_LEN);
! 286:
! 287: if (!step3(prf, k, payload, h))
! 288: {
! 289: return FALSE;
! 290: }
! 291: step4(h);
! 292: memcpy(ak, h, AKA_AK_LEN);
! 293: return TRUE;
! 294: }
! 295:
! 296: /**
! 297: * Calculate MAC from RAND, SQN, AMF using K
! 298: */
! 299: METHOD(eap_aka_3gpp2_functions_t, f1, bool,
! 300: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 301: u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
! 302: u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
! 303: {
! 304: if (f1x(this->prf, F1, k, rand, sqn, amf, mac))
! 305: {
! 306: DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN);
! 307: return TRUE;
! 308: }
! 309: return FALSE;
! 310: }
! 311:
! 312: /**
! 313: * Calculate MACS from RAND, SQN, AMF using K
! 314: */
! 315: METHOD(eap_aka_3gpp2_functions_t, f1star, bool,
! 316: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 317: u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
! 318: u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN])
! 319: {
! 320: if (f1x(this->prf, F1STAR, k, rand, sqn, amf, macs))
! 321: {
! 322: DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN);
! 323: return TRUE;
! 324: }
! 325: return FALSE;
! 326: }
! 327:
! 328: /**
! 329: * Calculate RES from RAND using K
! 330: */
! 331: METHOD(eap_aka_3gpp2_functions_t, f2, bool,
! 332: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 333: u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX])
! 334: {
! 335: if (fx(this->prf, F2, k, rand, res))
! 336: {
! 337: DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX);
! 338: return TRUE;
! 339: }
! 340: return FALSE;
! 341: }
! 342:
! 343: /**
! 344: * Calculate CK from RAND using K
! 345: */
! 346: METHOD(eap_aka_3gpp2_functions_t, f3, bool,
! 347: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 348: u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN])
! 349: {
! 350: if (fx(this->prf, F3, k, rand, ck))
! 351: {
! 352: DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN);
! 353: return TRUE;
! 354: }
! 355: return FALSE;
! 356: }
! 357:
! 358: /**
! 359: * Calculate IK from RAND using K
! 360: */
! 361: METHOD(eap_aka_3gpp2_functions_t, f4, bool,
! 362: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 363: u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN])
! 364: {
! 365: if (fx(this->prf, F4, k, rand, ik))
! 366: {
! 367: DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN);
! 368: return TRUE;
! 369: }
! 370: return FALSE;
! 371: }
! 372:
! 373: /**
! 374: * Calculate AK from a RAND using K
! 375: */
! 376: METHOD(eap_aka_3gpp2_functions_t, f5, bool,
! 377: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 378: u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
! 379: {
! 380: if (f5x(this->prf, F5, k, rand, ak))
! 381: {
! 382: DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN);
! 383: return TRUE;
! 384: }
! 385: return FALSE;
! 386: }
! 387:
! 388: /**
! 389: * Calculate AKS from a RAND using K
! 390: */
! 391: METHOD(eap_aka_3gpp2_functions_t, f5star, bool,
! 392: private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
! 393: u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN])
! 394: {
! 395: if (f5x(this->prf, F5STAR, k, rand, aks))
! 396: {
! 397: DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN);
! 398: return TRUE;
! 399: }
! 400: return FALSE;
! 401: }
! 402:
! 403: METHOD(eap_aka_3gpp2_functions_t, destroy, void,
! 404: private_eap_aka_3gpp2_functions_t *this)
! 405: {
! 406: this->prf->destroy(this->prf);
! 407: free(this);
! 408: }
! 409:
! 410: /**
! 411: * See header
! 412: */
! 413: eap_aka_3gpp2_functions_t *eap_aka_3gpp2_functions_create()
! 414: {
! 415: private_eap_aka_3gpp2_functions_t *this;
! 416:
! 417: INIT(this,
! 418: .public = {
! 419: .f1 = _f1,
! 420: .f1star = _f1star,
! 421: .f2 = _f2,
! 422: .f3 = _f3,
! 423: .f4 = _f4,
! 424: .f5 = _f5,
! 425: .f5star = _f5star,
! 426: .destroy = _destroy,
! 427: },
! 428: .prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1),
! 429: );
! 430: if (!this->prf)
! 431: {
! 432: DBG1(DBG_CFG, "%N not supported, unable to use 3GPP2 algorithm",
! 433: pseudo_random_function_names, PRF_KEYED_SHA1);
! 434: free(this);
! 435: return NULL;
! 436: }
! 437: return &this->public;
! 438: }
! 439:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>