milenage.c
Go to the documentation of this file.
00001 /*
00002  * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
00003  * Copyright (c) 2006-2007 <j@w1.fi>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  *
00009  * Alternatively, this software may be distributed under the terms of BSD
00010  * license.
00011  *
00012  * See README and COPYING for more details.
00013  *
00014  * This file implements an example authentication algorithm defined for 3GPP
00015  * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
00016  * EAP-AKA to be tested properly with real USIM cards.
00017  *
00018  * This implementations assumes that the r1..r5 and c1..c5 constants defined in
00019  * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
00020  * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
00021  * be AES (Rijndael).
00022  */
00023 
00024 #include "includes.h"
00025 
00026 #include "common.h"
00027 #include "crypto/aes_wrap.h"
00028 #include "milenage.h"
00029 
00030 
00042 int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
00043                 const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
00044 {
00045         u8 tmp1[16], tmp2[16], tmp3[16];
00046         int i;
00047 
00048         /* tmp1 = TEMP = E_K(RAND XOR OP_C) */
00049         for (i = 0; i < 16; i++)
00050                 tmp1[i] = _rand[i] ^ opc[i];
00051         if (aes_128_encrypt_block(k, tmp1, tmp1))
00052                 return -1;
00053 
00054         /* tmp2 = IN1 = SQN || AMF || SQN || AMF */
00055         os_memcpy(tmp2, sqn, 6);
00056         os_memcpy(tmp2 + 6, amf, 2);
00057         os_memcpy(tmp2 + 8, tmp2, 8);
00058 
00059         /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
00060 
00061         /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
00062         for (i = 0; i < 16; i++)
00063                 tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
00064         /* XOR with TEMP = E_K(RAND XOR OP_C) */
00065         for (i = 0; i < 16; i++)
00066                 tmp3[i] ^= tmp1[i];
00067         /* XOR with c1 (= ..00, i.e., NOP) */
00068 
00069         /* f1 || f1* = E_K(tmp3) XOR OP_c */
00070         if (aes_128_encrypt_block(k, tmp3, tmp1))
00071                 return -1;
00072         for (i = 0; i < 16; i++)
00073                 tmp1[i] ^= opc[i];
00074         if (mac_a)
00075                 os_memcpy(mac_a, tmp1, 8); /* f1 */
00076         if (mac_s)
00077                 os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
00078         return 0;
00079 }
00080 
00081 
00094 int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
00095                    u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
00096 {
00097         u8 tmp1[16], tmp2[16], tmp3[16];
00098         int i;
00099 
00100         /* tmp2 = TEMP = E_K(RAND XOR OP_C) */
00101         for (i = 0; i < 16; i++)
00102                 tmp1[i] = _rand[i] ^ opc[i];
00103         if (aes_128_encrypt_block(k, tmp1, tmp2))
00104                 return -1;
00105 
00106         /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
00107         /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
00108         /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
00109         /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
00110 
00111         /* f2 and f5 */
00112         /* rotate by r2 (= 0, i.e., NOP) */
00113         for (i = 0; i < 16; i++)
00114                 tmp1[i] = tmp2[i] ^ opc[i];
00115         tmp1[15] ^= 1; /* XOR c2 (= ..01) */
00116         /* f5 || f2 = E_K(tmp1) XOR OP_c */
00117         if (aes_128_encrypt_block(k, tmp1, tmp3))
00118                 return -1;
00119         for (i = 0; i < 16; i++)
00120                 tmp3[i] ^= opc[i];
00121         if (res)
00122                 os_memcpy(res, tmp3 + 8, 8); /* f2 */
00123         if (ak)
00124                 os_memcpy(ak, tmp3, 6); /* f5 */
00125 
00126         /* f3 */
00127         if (ck) {
00128                 /* rotate by r3 = 0x20 = 4 bytes */
00129                 for (i = 0; i < 16; i++)
00130                         tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
00131                 tmp1[15] ^= 2; /* XOR c3 (= ..02) */
00132                 if (aes_128_encrypt_block(k, tmp1, ck))
00133                         return -1;
00134                 for (i = 0; i < 16; i++)
00135                         ck[i] ^= opc[i];
00136         }
00137 
00138         /* f4 */
00139         if (ik) {
00140                 /* rotate by r4 = 0x40 = 8 bytes */
00141                 for (i = 0; i < 16; i++)
00142                         tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
00143                 tmp1[15] ^= 4; /* XOR c4 (= ..04) */
00144                 if (aes_128_encrypt_block(k, tmp1, ik))
00145                         return -1;
00146                 for (i = 0; i < 16; i++)
00147                         ik[i] ^= opc[i];
00148         }
00149 
00150         /* f5* */
00151         if (akstar) {
00152                 /* rotate by r5 = 0x60 = 12 bytes */
00153                 for (i = 0; i < 16; i++)
00154                         tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
00155                 tmp1[15] ^= 8; /* XOR c5 (= ..08) */
00156                 if (aes_128_encrypt_block(k, tmp1, tmp1))
00157                         return -1;
00158                 for (i = 0; i < 6; i++)
00159                         akstar[i] = tmp1[i] ^ opc[i];
00160         }
00161 
00162         return 0;
00163 }
00164 
00165 
00179 void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
00180                        const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
00181                        u8 *ck, u8 *res, size_t *res_len)
00182 {
00183         int i;
00184         u8 mac_a[8], ak[6];
00185 
00186         if (*res_len < 8) {
00187                 *res_len = 0;
00188                 return;
00189         }
00190         if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
00191             milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
00192                 *res_len = 0;
00193                 return;
00194         }
00195         *res_len = 8;
00196 
00197         /* AUTN = (SQN ^ AK) || AMF || MAC */
00198         for (i = 0; i < 6; i++)
00199                 autn[i] = sqn[i] ^ ak[i];
00200         os_memcpy(autn + 6, amf, 2);
00201         os_memcpy(autn + 8, mac_a, 8);
00202 }
00203 
00204 
00214 int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
00215                   u8 *sqn)
00216 {
00217         u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
00218         u8 ak[6], mac_s[8];
00219         int i;
00220 
00221         if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
00222                 return -1;
00223         for (i = 0; i < 6; i++)
00224                 sqn[i] = auts[i] ^ ak[i];
00225         if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
00226             memcmp(mac_s, auts + 6, 8) != 0)
00227                 return -1;
00228         return 0;
00229 }
00230 
00231 
00241 int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
00242 {
00243         u8 res[8], ck[16], ik[16];
00244         int i;
00245 
00246         if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
00247                 return -1;
00248 
00249         for (i = 0; i < 8; i++)
00250                 kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
00251 
00252 #ifdef GSM_MILENAGE_ALT_SRES
00253         os_memcpy(sres, res, 4);
00254 #else /* GSM_MILENAGE_ALT_SRES */
00255         for (i = 0; i < 4; i++)
00256                 sres[i] = res[i] ^ res[i + 4];
00257 #endif /* GSM_MILENAGE_ALT_SRES */
00258         return 0;
00259 }
00260 
00261 
00276 int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
00277                    const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
00278                    u8 *auts)
00279 {
00280         int i;
00281         u8 mac_a[8], ak[6], rx_sqn[6];
00282         const u8 *amf;
00283 
00284         wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
00285         wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
00286 
00287         if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
00288                 return -1;
00289 
00290         *res_len = 8;
00291         wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
00292         wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
00293         wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
00294         wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
00295 
00296         /* AUTN = (SQN ^ AK) || AMF || MAC */
00297         for (i = 0; i < 6; i++)
00298                 rx_sqn[i] = autn[i] ^ ak[i];
00299         wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
00300 
00301         if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
00302                 u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
00303                 if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
00304                         return -1;
00305                 wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
00306                 for (i = 0; i < 6; i++)
00307                         auts[i] = sqn[i] ^ ak[i];
00308                 if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
00309                         return -1;
00310                 wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
00311                 return -2;
00312         }
00313 
00314         amf = autn + 6;
00315         wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
00316         if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
00317                 return -1;
00318 
00319         wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
00320 
00321         if (os_memcmp(mac_a, autn + 8, 8) != 0) {
00322                 wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
00323                 wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
00324                             autn + 8, 8);
00325                 return -1;
00326         }
00327 
00328         return 0;
00329 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35