LCOV - code coverage report
Current view: top level - src/crypto - milenage.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1393793999 Lines: 109 127 85.8 %
Date: 2014-03-02 Functions: 6 6 100.0 %
Branches: 74 92 80.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
       3                 :            :  * Copyright (c) 2006-2007 <j@w1.fi>
       4                 :            :  *
       5                 :            :  * This software may be distributed under the terms of the BSD license.
       6                 :            :  * See README for more details.
       7                 :            :  *
       8                 :            :  * This file implements an example authentication algorithm defined for 3GPP
       9                 :            :  * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
      10                 :            :  * EAP-AKA to be tested properly with real USIM cards.
      11                 :            :  *
      12                 :            :  * This implementations assumes that the r1..r5 and c1..c5 constants defined in
      13                 :            :  * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
      14                 :            :  * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
      15                 :            :  * be AES (Rijndael).
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "includes.h"
      19                 :            : 
      20                 :            : #include "common.h"
      21                 :            : #include "crypto/aes_wrap.h"
      22                 :            : #include "milenage.h"
      23                 :            : 
      24                 :            : 
      25                 :            : /**
      26                 :            :  * milenage_f1 - Milenage f1 and f1* algorithms
      27                 :            :  * @opc: OPc = 128-bit value derived from OP and K
      28                 :            :  * @k: K = 128-bit subscriber key
      29                 :            :  * @_rand: RAND = 128-bit random challenge
      30                 :            :  * @sqn: SQN = 48-bit sequence number
      31                 :            :  * @amf: AMF = 16-bit authentication management field
      32                 :            :  * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
      33                 :            :  * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
      34                 :            :  * Returns: 0 on success, -1 on failure
      35                 :            :  */
      36                 :         15 : int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
      37                 :            :                 const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
      38                 :            : {
      39                 :            :         u8 tmp1[16], tmp2[16], tmp3[16];
      40                 :            :         int i;
      41                 :            : 
      42                 :            :         /* tmp1 = TEMP = E_K(RAND XOR OP_C) */
      43         [ +  + ]:        255 :         for (i = 0; i < 16; i++)
      44                 :        240 :                 tmp1[i] = _rand[i] ^ opc[i];
      45         [ -  + ]:         15 :         if (aes_128_encrypt_block(k, tmp1, tmp1))
      46                 :          0 :                 return -1;
      47                 :            : 
      48                 :            :         /* tmp2 = IN1 = SQN || AMF || SQN || AMF */
      49                 :         15 :         os_memcpy(tmp2, sqn, 6);
      50                 :         15 :         os_memcpy(tmp2 + 6, amf, 2);
      51                 :         15 :         os_memcpy(tmp2 + 8, tmp2, 8);
      52                 :            : 
      53                 :            :         /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
      54                 :            : 
      55                 :            :         /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
      56         [ +  + ]:        255 :         for (i = 0; i < 16; i++)
      57                 :        240 :                 tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
      58                 :            :         /* XOR with TEMP = E_K(RAND XOR OP_C) */
      59         [ +  + ]:        255 :         for (i = 0; i < 16; i++)
      60                 :        240 :                 tmp3[i] ^= tmp1[i];
      61                 :            :         /* XOR with c1 (= ..00, i.e., NOP) */
      62                 :            : 
      63                 :            :         /* f1 || f1* = E_K(tmp3) XOR OP_c */
      64         [ -  + ]:         15 :         if (aes_128_encrypt_block(k, tmp3, tmp1))
      65                 :          0 :                 return -1;
      66         [ +  + ]:        255 :         for (i = 0; i < 16; i++)
      67                 :        240 :                 tmp1[i] ^= opc[i];
      68         [ +  + ]:         15 :         if (mac_a)
      69                 :         13 :                 os_memcpy(mac_a, tmp1, 8); /* f1 */
      70         [ +  + ]:         15 :         if (mac_s)
      71                 :          2 :                 os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
      72                 :         15 :         return 0;
      73                 :            : }
      74                 :            : 
      75                 :            : 
      76                 :            : /**
      77                 :            :  * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
      78                 :            :  * @opc: OPc = 128-bit value derived from OP and K
      79                 :            :  * @k: K = 128-bit subscriber key
      80                 :            :  * @_rand: RAND = 128-bit random challenge
      81                 :            :  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
      82                 :            :  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
      83                 :            :  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
      84                 :            :  * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
      85                 :            :  * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
      86                 :            :  * Returns: 0 on success, -1 on failure
      87                 :            :  */
      88                 :         58 : int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
      89                 :            :                    u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
      90                 :            : {
      91                 :            :         u8 tmp1[16], tmp2[16], tmp3[16];
      92                 :            :         int i;
      93                 :            : 
      94                 :            :         /* tmp2 = TEMP = E_K(RAND XOR OP_C) */
      95         [ +  + ]:        986 :         for (i = 0; i < 16; i++)
      96                 :        928 :                 tmp1[i] = _rand[i] ^ opc[i];
      97         [ -  + ]:         58 :         if (aes_128_encrypt_block(k, tmp1, tmp2))
      98                 :          0 :                 return -1;
      99                 :            : 
     100                 :            :         /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
     101                 :            :         /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
     102                 :            :         /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
     103                 :            :         /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
     104                 :            : 
     105                 :            :         /* f2 and f5 */
     106                 :            :         /* rotate by r2 (= 0, i.e., NOP) */
     107         [ +  + ]:        986 :         for (i = 0; i < 16; i++)
     108                 :        928 :                 tmp1[i] = tmp2[i] ^ opc[i];
     109                 :         58 :         tmp1[15] ^= 1; /* XOR c2 (= ..01) */
     110                 :            :         /* f5 || f2 = E_K(tmp1) XOR OP_c */
     111         [ -  + ]:         58 :         if (aes_128_encrypt_block(k, tmp1, tmp3))
     112                 :          0 :                 return -1;
     113         [ +  + ]:        986 :         for (i = 0; i < 16; i++)
     114                 :        928 :                 tmp3[i] ^= opc[i];
     115         [ +  + ]:         58 :         if (res)
     116                 :         56 :                 os_memcpy(res, tmp3 + 8, 8); /* f2 */
     117         [ +  + ]:         58 :         if (ak)
     118                 :         14 :                 os_memcpy(ak, tmp3, 6); /* f5 */
     119                 :            : 
     120                 :            :         /* f3 */
     121         [ +  + ]:         58 :         if (ck) {
     122                 :            :                 /* rotate by r3 = 0x20 = 4 bytes */
     123         [ +  + ]:        952 :                 for (i = 0; i < 16; i++)
     124                 :        896 :                         tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
     125                 :         56 :                 tmp1[15] ^= 2; /* XOR c3 (= ..02) */
     126         [ -  + ]:         56 :                 if (aes_128_encrypt_block(k, tmp1, ck))
     127                 :          0 :                         return -1;
     128         [ +  + ]:        952 :                 for (i = 0; i < 16; i++)
     129                 :        896 :                         ck[i] ^= opc[i];
     130                 :            :         }
     131                 :            : 
     132                 :            :         /* f4 */
     133         [ +  + ]:         58 :         if (ik) {
     134                 :            :                 /* rotate by r4 = 0x40 = 8 bytes */
     135         [ +  + ]:        952 :                 for (i = 0; i < 16; i++)
     136                 :        896 :                         tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
     137                 :         56 :                 tmp1[15] ^= 4; /* XOR c4 (= ..04) */
     138         [ -  + ]:         56 :                 if (aes_128_encrypt_block(k, tmp1, ik))
     139                 :          0 :                         return -1;
     140         [ +  + ]:        952 :                 for (i = 0; i < 16; i++)
     141                 :        896 :                         ik[i] ^= opc[i];
     142                 :            :         }
     143                 :            : 
     144                 :            :         /* f5* */
     145         [ +  + ]:         58 :         if (akstar) {
     146                 :            :                 /* rotate by r5 = 0x60 = 12 bytes */
     147         [ +  + ]:         34 :                 for (i = 0; i < 16; i++)
     148                 :         32 :                         tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
     149                 :          2 :                 tmp1[15] ^= 8; /* XOR c5 (= ..08) */
     150         [ -  + ]:          2 :                 if (aes_128_encrypt_block(k, tmp1, tmp1))
     151                 :          0 :                         return -1;
     152         [ +  + ]:         14 :                 for (i = 0; i < 6; i++)
     153                 :         12 :                         akstar[i] = tmp1[i] ^ opc[i];
     154                 :            :         }
     155                 :            : 
     156                 :         58 :         return 0;
     157                 :            : }
     158                 :            : 
     159                 :            : 
     160                 :            : /**
     161                 :            :  * milenage_generate - Generate AKA AUTN,IK,CK,RES
     162                 :            :  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
     163                 :            :  * @amf: AMF = 16-bit authentication management field
     164                 :            :  * @k: K = 128-bit subscriber key
     165                 :            :  * @sqn: SQN = 48-bit sequence number
     166                 :            :  * @_rand: RAND = 128-bit random challenge
     167                 :            :  * @autn: Buffer for AUTN = 128-bit authentication token
     168                 :            :  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
     169                 :            :  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
     170                 :            :  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
     171                 :            :  * @res_len: Max length for res; set to used length or 0 on failure
     172                 :            :  */
     173                 :          7 : void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
     174                 :            :                        const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
     175                 :            :                        u8 *ck, u8 *res, size_t *res_len)
     176                 :            : {
     177                 :            :         int i;
     178                 :            :         u8 mac_a[8], ak[6];
     179                 :            : 
     180         [ -  + ]:          7 :         if (*res_len < 8) {
     181                 :          0 :                 *res_len = 0;
     182                 :          0 :                 return;
     183                 :            :         }
     184   [ +  -  -  + ]:         14 :         if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
     185                 :          7 :             milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
     186                 :          0 :                 *res_len = 0;
     187                 :          0 :                 return;
     188                 :            :         }
     189                 :          7 :         *res_len = 8;
     190                 :            : 
     191                 :            :         /* AUTN = (SQN ^ AK) || AMF || MAC */
     192         [ +  + ]:         49 :         for (i = 0; i < 6; i++)
     193                 :         42 :                 autn[i] = sqn[i] ^ ak[i];
     194                 :          7 :         os_memcpy(autn + 6, amf, 2);
     195                 :          7 :         os_memcpy(autn + 8, mac_a, 8);
     196                 :            : }
     197                 :            : 
     198                 :            : 
     199                 :            : /**
     200                 :            :  * milenage_auts - Milenage AUTS validation
     201                 :            :  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
     202                 :            :  * @k: K = 128-bit subscriber key
     203                 :            :  * @_rand: RAND = 128-bit random challenge
     204                 :            :  * @auts: AUTS = 112-bit authentication token from client
     205                 :            :  * @sqn: Buffer for SQN = 48-bit sequence number
     206                 :            :  * Returns: 0 = success (sqn filled), -1 on failure
     207                 :            :  */
     208                 :          1 : int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
     209                 :            :                   u8 *sqn)
     210                 :            : {
     211                 :          1 :         u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
     212                 :            :         u8 ak[6], mac_s[8];
     213                 :            :         int i;
     214                 :            : 
     215         [ -  + ]:          1 :         if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
     216                 :          0 :                 return -1;
     217         [ +  + ]:          7 :         for (i = 0; i < 6; i++)
     218                 :          6 :                 sqn[i] = auts[i] ^ ak[i];
     219 [ +  - ][ -  + ]:          1 :         if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
     220                 :          1 :             memcmp(mac_s, auts + 6, 8) != 0)
     221                 :          0 :                 return -1;
     222                 :          1 :         return 0;
     223                 :            : }
     224                 :            : 
     225                 :            : 
     226                 :            : /**
     227                 :            :  * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
     228                 :            :  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
     229                 :            :  * @k: K = 128-bit subscriber key
     230                 :            :  * @_rand: RAND = 128-bit random challenge
     231                 :            :  * @sres: Buffer for SRES = 32-bit SRES
     232                 :            :  * @kc: Buffer for Kc = 64-bit Kc
     233                 :            :  * Returns: 0 on success, -1 on failure
     234                 :            :  */
     235                 :         42 : int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
     236                 :            : {
     237                 :            :         u8 res[8], ck[16], ik[16];
     238                 :            :         int i;
     239                 :            : 
     240         [ -  + ]:         42 :         if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
     241                 :          0 :                 return -1;
     242                 :            : 
     243         [ +  + ]:        378 :         for (i = 0; i < 8; i++)
     244                 :        336 :                 kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
     245                 :            : 
     246                 :            : #ifdef GSM_MILENAGE_ALT_SRES
     247                 :            :         os_memcpy(sres, res, 4);
     248                 :            : #else /* GSM_MILENAGE_ALT_SRES */
     249         [ +  + ]:        210 :         for (i = 0; i < 4; i++)
     250                 :        168 :                 sres[i] = res[i] ^ res[i + 4];
     251                 :            : #endif /* GSM_MILENAGE_ALT_SRES */
     252                 :         42 :         return 0;
     253                 :            : }
     254                 :            : 
     255                 :            : 
     256                 :            : /**
     257                 :            :  * milenage_generate - Generate AKA AUTN,IK,CK,RES
     258                 :            :  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
     259                 :            :  * @k: K = 128-bit subscriber key
     260                 :            :  * @sqn: SQN = 48-bit sequence number
     261                 :            :  * @_rand: RAND = 128-bit random challenge
     262                 :            :  * @autn: AUTN = 128-bit authentication token
     263                 :            :  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
     264                 :            :  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
     265                 :            :  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
     266                 :            :  * @res_len: Variable that will be set to RES length
     267                 :            :  * @auts: 112-bit buffer for AUTS
     268                 :            :  * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
     269                 :            :  */
     270                 :          7 : int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
     271                 :            :                    const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
     272                 :            :                    u8 *auts)
     273                 :            : {
     274                 :            :         int i;
     275                 :            :         u8 mac_a[8], ak[6], rx_sqn[6];
     276                 :            :         const u8 *amf;
     277                 :            : 
     278                 :          7 :         wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
     279                 :          7 :         wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
     280                 :            : 
     281         [ -  + ]:          7 :         if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
     282                 :          0 :                 return -1;
     283                 :            : 
     284                 :          7 :         *res_len = 8;
     285                 :          7 :         wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
     286                 :          7 :         wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
     287                 :          7 :         wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
     288                 :          7 :         wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
     289                 :            : 
     290                 :            :         /* AUTN = (SQN ^ AK) || AMF || MAC */
     291         [ +  + ]:         49 :         for (i = 0; i < 6; i++)
     292                 :         42 :                 rx_sqn[i] = autn[i] ^ ak[i];
     293                 :          7 :         wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
     294                 :            : 
     295         [ +  + ]:          7 :         if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
     296                 :          1 :                 u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
     297         [ -  + ]:          1 :                 if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
     298                 :          0 :                         return -1;
     299                 :          1 :                 wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
     300         [ +  + ]:          7 :                 for (i = 0; i < 6; i++)
     301                 :          6 :                         auts[i] = sqn[i] ^ ak[i];
     302         [ -  + ]:          1 :                 if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
     303                 :          0 :                         return -1;
     304                 :          1 :                 wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
     305                 :          1 :                 return -2;
     306                 :            :         }
     307                 :            : 
     308                 :          6 :         amf = autn + 6;
     309                 :          6 :         wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
     310         [ -  + ]:          6 :         if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
     311                 :          0 :                 return -1;
     312                 :            : 
     313                 :          6 :         wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
     314                 :            : 
     315         [ +  + ]:          6 :         if (os_memcmp(mac_a, autn + 8, 8) != 0) {
     316                 :          2 :                 wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
     317                 :          2 :                 wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
     318                 :            :                             autn + 8, 8);
     319                 :          2 :                 return -1;
     320                 :            :         }
     321                 :            : 
     322                 :          7 :         return 0;
     323                 :            : }

Generated by: LCOV version 1.9