blob: 8b058e5655ba1b3e990ea4742a6b23bf62e4911f [file] [log] [blame]
Harald Weltee076ac02011-12-07 00:10:18 +01001
2#include <stdlib.h>
3#include <stdio.h>
4#include <errno.h>
5#include <string.h>
Neels Hofmeyr8e1b5982017-03-13 17:36:36 +01006#include <inttypes.h>
Harald Weltee076ac02011-12-07 00:10:18 +01007
8#include <osmocom/crypt/auth.h>
9#include <osmocom/core/utils.h>
10
Jacob Erlbeck73ae7a92013-10-08 12:04:42 +020011int milenage_opc_gen(uint8_t *opc, const uint8_t *k, const uint8_t *op);
12
Harald Weltee076ac02011-12-07 00:10:18 +010013static void dump_auth_vec(struct osmo_auth_vector *vec)
14{
15 printf("RAND:\t%s\n", osmo_hexdump(vec->rand, sizeof(vec->rand)));
16
17 if (vec->auth_types & OSMO_AUTH_TYPE_UMTS) {
18 printf("AUTN:\t%s\n", osmo_hexdump(vec->autn, sizeof(vec->autn)));
19 printf("IK:\t%s\n", osmo_hexdump(vec->ik, sizeof(vec->ik)));
20 printf("CK:\t%s\n", osmo_hexdump(vec->ck, sizeof(vec->ck)));
21 printf("RES:\t%s\n", osmo_hexdump(vec->res, vec->res_len));
22 }
23
24 if (vec->auth_types & OSMO_AUTH_TYPE_GSM) {
25 printf("SRES:\t%s\n", osmo_hexdump(vec->sres, sizeof(vec->sres)));
Maxaf25c372018-12-19 20:12:19 +010026 /* According to 3GPP TS 55.205 Sec. 4 the GSM-MILENAGE output is limited to 64 bits.
27 According to 3GPP TS 33.102 Annex. B5 in UMTS security context Kc can be 128 bits.
28 Here we test the former, so make sure we only print interesting Kc bits. */
29 printf("Kc:\t%s\n", osmo_hexdump(vec->kc, OSMO_A5_MAX_KEY_LEN_BYTES/2));
Harald Weltee076ac02011-12-07 00:10:18 +010030 }
31}
32
33static struct osmo_sub_auth_data test_aud = {
34 .type = OSMO_AUTH_TYPE_UMTS,
35 .algo = OSMO_AUTH_ALG_MILENAGE,
Harald Welteaae23622011-12-07 11:35:02 +010036 .u.umts = {
Harald Weltee076ac02011-12-07 00:10:18 +010037 .opc = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
38 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
39 .k = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
40 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
41 .amf = { 0x00, 0x00 },
Neels Hofmeyr82c9a0e2017-03-13 17:36:17 +010042 .sqn = 0x21,
Neels Hofmeyrbb6f7b72017-03-13 17:27:17 +010043 .ind_bitlen = 0,
44 .ind = 0,
Harald Weltee076ac02011-12-07 00:10:18 +010045 },
46};
47
Harald Welte042afe72012-03-21 08:19:47 +010048static int opc_test(const struct osmo_sub_auth_data *aud)
49{
50 int rc;
51 uint8_t opc[16];
52#if 0
53 const uint8_t op[16] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
54 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
55#else
56 const uint8_t op[16] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 };
57#endif
58
Maxeb59f242016-06-27 15:44:16 +020059 printf("MILENAGE supported: %d\n",
60 osmo_auth_supported(osmo_auth_alg_parse("MILENAGE")));
61
Harald Welte042afe72012-03-21 08:19:47 +010062 rc = milenage_opc_gen(opc, aud->u.umts.k, op);
63
64 printf("OP:\t%s\n", osmo_hexdump(op, sizeof(op)));
65 printf("OPC:\t%s\n", osmo_hexdump(opc, sizeof(opc)));
66 return rc;
67}
68
Neels Hofmeyr6761c3f2017-03-14 02:31:41 +010069#define RECALC_AUTS 0
70#if RECALC_AUTS
71typedef uint8_t u8;
72extern int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
73 u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar);
74extern int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
75 const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s);
76#endif
77
Harald Weltee076ac02011-12-07 00:10:18 +010078int main(int argc, char **argv)
79{
80 struct osmo_auth_vector _vec;
81 struct osmo_auth_vector *vec = &_vec;
82 uint8_t _rand[16];
83 int rc;
84
85#if 0
86 srand(time(NULL));
87 *(uint32_t *)&_rand[0] = rand();
88 *(uint32_t *)(&_rand[4]) = rand();
89 *(uint32_t *)(&_rand[8]) = rand();
90 *(uint32_t *)(&_rand[12]) = rand();
91#else
92 memset(_rand, 0, sizeof(_rand));
93#endif
94 memset(vec, 0, sizeof(*vec));
95
Neels Hofmeyrbb6f7b72017-03-13 17:27:17 +010096 /* ind_bitlen == 0 uses the legacy mode of incrementing SQN by 1.
97 * sqn == 0x21 == 33, so the SQN used to generate the vector is
98 * sqn + 1 == 34. */
Harald Weltee076ac02011-12-07 00:10:18 +010099 rc = osmo_auth_gen_vec(vec, &test_aud, _rand);
100 if (rc < 0) {
101 fprintf(stderr, "error generating auth vector\n");
102 exit(1);
103 }
104
105 dump_auth_vec(vec);
106
Neels Hofmeyr6761c3f2017-03-14 02:31:41 +0100107 /* The USIM generates an AUTS to tell us it is at SQN == 31:
108 *
109 * SQN_MS = 00000000001f
110 *
111 * AUTS = Conc(SQN_MS) || MAC-S
112 * Conc(SQN_MS) = SQN_MS ⊕ f5*[K](RAND)
113 * MAC-S = f1*[K] (SQN MS || RAND || AMF)
114 *
115 * K = 000102030405060708090a0b0c0d0e0f
116 * RAND = 00000000000000000000000000000000
117 *
118 * f5*--> Conc(SQN_MS) = SQN_MS ^ f5*(K,RAND)
119 * = 00000000001f ^ 8711a0ec9e09
120 * = 8711a0ec9e16
121 * AMF = 0000 (TS 33.102 v7.0.0, 6.3.3)
122 * MAC-S = f1*[K] (SQN MS || RAND || AMF)
123 * = f1*[K] (00000000001f || 00000000000000000000000000000000 || 0000)
124 * = 37df17f80b384ee4
125 *
126 * AUTS = 8711a0ec9e16 || 37df17f80b384ee4
127 */
128#if RECALC_AUTS
129 uint8_t ak[6];
130 uint8_t akstar[6];
131 uint8_t opc[16];
132 uint8_t k[16];
133 uint8_t rand[16];
134 osmo_hexparse("000102030405060708090a0b0c0d0e0f", k, sizeof(k));
135 osmo_hexparse("000102030405060708090a0b0c0d0e0f", opc, sizeof(opc));
136 osmo_hexparse("00000000000000000000000000000000", rand, sizeof(rand));
137 milenage_f2345(opc, k, rand, NULL, NULL, NULL, ak, akstar);
138 printf("ak = %s\n", osmo_hexdump_nospc(ak, sizeof(ak)));
139 printf("akstar = %s\n", osmo_hexdump_nospc(akstar, sizeof(akstar)));
140
141 uint8_t sqn_ms[6] = { 0, 0, 0, 0, 0, 31 };
142 uint8_t amf[2] = {};
143 uint8_t mac_s[8];
144 milenage_f1(opc, k, rand, sqn_ms, amf, NULL, mac_s);
145 printf("mac_s = %s\n", osmo_hexdump_nospc(mac_s, sizeof(mac_s)));
146 /* verify valid AUTS resulting in SQN 31 with:
147 osmo-auc-gen -3 -a milenage -k 000102030405060708090a0b0c0d0e0f \
148 -o 000102030405060708090a0b0c0d0e0f \
149 -r 00000000000000000000000000000000 \
150 -A 8711a0ec9e1637df17f80b384ee4
151 */
152#endif
153
Harald Weltee076ac02011-12-07 00:10:18 +0100154 const uint8_t auts[14] = { 0x87, 0x11, 0xa0, 0xec, 0x9e, 0x16, 0x37, 0xdf,
155 0x17, 0xf8, 0x0b, 0x38, 0x4e, 0xe4 };
156
Neels Hofmeyrbb6f7b72017-03-13 17:27:17 +0100157 /* Invoking with ind_bitlen == 0, the next SQN after 31 is 32. */
Harald Weltee076ac02011-12-07 00:10:18 +0100158 rc = osmo_auth_gen_vec_auts(vec, &test_aud, auts, _rand, _rand);
159 if (rc < 0) {
160 printf("AUTS failed\n");
161 } else {
Neels Hofmeyr8e1b5982017-03-13 17:36:36 +0100162 printf("AUTS success: tuple generated with SQN = %" PRIu64 "\n",
163 test_aud.u.umts.sqn);
Harald Weltee076ac02011-12-07 00:10:18 +0100164 }
165
Neels Hofmeyr45e778d2017-03-14 02:53:56 +0100166 /* Now test SQN incrementing scheme using SEQ and IND parts:
167 * with ind_bitlen == 5 and ind == 10, the next SQN after 31 is
168 * 32 + 10 == 42. */
169 test_aud.u.umts.ind_bitlen = 5;
170 test_aud.u.umts.ind = 10;
171 rc = osmo_auth_gen_vec_auts(vec, &test_aud, auts, _rand, _rand);
172 if (rc < 0)
173 printf("AUTS failed\n");
174 else
175 printf("AUTS success: tuple generated with SQN = %" PRIu64 "\n",
176 test_aud.u.umts.sqn);
177
178 /* And the one after that is 64 + 10 == 74 */
179 rc = osmo_auth_gen_vec(vec, &test_aud, _rand);
180 if (rc < 0)
181 printf("generating vector failed\n");
182 else
183 printf("tuple generated with SQN = %" PRIu64 "\n",
184 test_aud.u.umts.sqn);
185
186 /* And the one after *that* is 96 + 10 == 106 */
187 rc = osmo_auth_gen_vec(vec, &test_aud, _rand);
188 if (rc < 0)
189 printf("generating vector failed\n");
190 else
191 printf("tuple generated with SQN = %" PRIu64 "\n",
192 test_aud.u.umts.sqn);
193
Harald Welte042afe72012-03-21 08:19:47 +0100194 opc_test(&test_aud);
195
Harald Weltee076ac02011-12-07 00:10:18 +0100196 exit(0);
197
198}