blob: 66dae9bb10947bc3b5352a6f499c1c0954eab83d [file] [log] [blame]
Benny Prijono7977f9f2007-10-10 11:37:56 +00001/*-------------------------------------------------------------------
2 * Example algorithms f1, f1*, f2, f3, f4, f5, f5*
3 *-------------------------------------------------------------------
4 *
5 * A sample implementation of the example 3GPP authentication and
6 * key agreement functions f1, f1*, f2, f3, f4, f5 and f5*. This is
7 * a byte-oriented implementation of the functions, and of the block
8 * cipher kernel function Rijndael.
9 *
10 * This has been coded for clarity, not necessarily for efficiency.
11 *
12 * The functions f2, f3, f4 and f5 share the same inputs and have
13 * been coded together as a single function. f1, f1* and f5* are
14 * all coded separately.
15 *
16 *-----------------------------------------------------------------*/
17
18#include "milenage.h"
19#include "rijndael.h"
20
21/*--------------------------- prototypes --------------------------*/
22
23
24
25/*-------------------------------------------------------------------
26 * Algorithm f1
27 *-------------------------------------------------------------------
28 *
29 * Computes network authentication code MAC-A from key K, random
30 * challenge RAND, sequence number SQN and authentication management
31 * field AMF.
32 *
33 *-----------------------------------------------------------------*/
34
35void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2],
36 u8 mac_a[8], u8 op[16] )
37{
38 u8 op_c[16];
39 u8 temp[16];
40 u8 in1[16];
41 u8 out1[16];
42 u8 rijndaelInput[16];
43 u8 i;
44
45 RijndaelKeySchedule( k );
46
47 ComputeOPc( op_c, op );
48
49 for (i=0; i<16; i++)
50 rijndaelInput[i] = rand[i] ^ op_c[i];
51 RijndaelEncrypt( rijndaelInput, temp );
52
53 for (i=0; i<6; i++)
54 {
55 in1[i] = sqn[i];
56 in1[i+8] = sqn[i];
57 }
58 for (i=0; i<2; i++)
59 {
60 in1[i+6] = amf[i];
61 in1[i+14] = amf[i];
62 }
63
64 /* XOR op_c and in1, rotate by r1=64, and XOR *
65 * on the constant c1 (which is all zeroes) */
66
67 for (i=0; i<16; i++)
68 rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
69
70 /* XOR on the value temp computed before */
71
72 for (i=0; i<16; i++)
73 rijndaelInput[i] ^= temp[i];
74
75 RijndaelEncrypt( rijndaelInput, out1 );
76 for (i=0; i<16; i++)
77 out1[i] ^= op_c[i];
78
79 for (i=0; i<8; i++)
80 mac_a[i] = out1[i];
81
82 return;
83} /* end of function f1 */
84
85
86
87/*-------------------------------------------------------------------
88 * Algorithms f2-f5
89 *-------------------------------------------------------------------
90 *
91 * Takes key K and random challenge RAND, and returns response RES,
92 * confidentiality key CK, integrity key IK and anonymity key AK.
93 *
94 *-----------------------------------------------------------------*/
95
96void f2345 ( u8 k[16], u8 rand[16],
97 u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6], u8 op[16] )
98{
99 u8 op_c[16];
100 u8 temp[16];
101 u8 out[16];
102 u8 rijndaelInput[16];
103 u8 i;
104
105 RijndaelKeySchedule( k );
106
107 ComputeOPc( op_c, op );
108
109 for (i=0; i<16; i++)
110 rijndaelInput[i] = rand[i] ^ op_c[i];
111 RijndaelEncrypt( rijndaelInput, temp );
112
113 /* To obtain output block OUT2: XOR OPc and TEMP, *
114 * rotate by r2=0, and XOR on the constant c2 (which *
115 * is all zeroes except that the last bit is 1). */
116
117 for (i=0; i<16; i++)
118 rijndaelInput[i] = temp[i] ^ op_c[i];
119 rijndaelInput[15] ^= 1;
120
121 RijndaelEncrypt( rijndaelInput, out );
122 for (i=0; i<16; i++)
123 out[i] ^= op_c[i];
124
125 for (i=0; i<8; i++)
126 res[i] = out[i+8];
127 for (i=0; i<6; i++)
128 ak[i] = out[i];
129
130 /* To obtain output block OUT3: XOR OPc and TEMP, *
131 * rotate by r3=32, and XOR on the constant c3 (which *
132 * is all zeroes except that the next to last bit is 1). */
133
134 for (i=0; i<16; i++)
135 rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i];
136 rijndaelInput[15] ^= 2;
137
138 RijndaelEncrypt( rijndaelInput, out );
139 for (i=0; i<16; i++)
140 out[i] ^= op_c[i];
141
142 for (i=0; i<16; i++)
143 ck[i] = out[i];
144
145 /* To obtain output block OUT4: XOR OPc and TEMP, *
146 * rotate by r4=64, and XOR on the constant c4 (which *
147 * is all zeroes except that the 2nd from last bit is 1). */
148
149 for (i=0; i<16; i++)
150 rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i];
151 rijndaelInput[15] ^= 4;
152
153 RijndaelEncrypt( rijndaelInput, out );
154 for (i=0; i<16; i++)
155 out[i] ^= op_c[i];
156
157 for (i=0; i<16; i++)
158 ik[i] = out[i];
159
160 return;
161} /* end of function f2345 */
162
163
164/*-------------------------------------------------------------------
165 * Algorithm f1*
166 *-------------------------------------------------------------------
167 *
168 * Computes resynch authentication code MAC-S from key K, random
169 * challenge RAND, sequence number SQN and authentication management
170 * field AMF.
171 *
172 *-----------------------------------------------------------------*/
173
174void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2],
175 u8 mac_s[8], u8 op[16] )
176{
177 u8 op_c[16];
178 u8 temp[16];
179 u8 in1[16];
180 u8 out1[16];
181 u8 rijndaelInput[16];
182 u8 i;
183
184 RijndaelKeySchedule( k );
185
186 ComputeOPc( op_c, op );
187
188 for (i=0; i<16; i++)
189 rijndaelInput[i] = rand[i] ^ op_c[i];
190 RijndaelEncrypt( rijndaelInput, temp );
191
192 for (i=0; i<6; i++)
193 {
194 in1[i] = sqn[i];
195 in1[i+8] = sqn[i];
196 }
197 for (i=0; i<2; i++)
198 {
199 in1[i+6] = amf[i];
200 in1[i+14] = amf[i];
201 }
202
203 /* XOR op_c and in1, rotate by r1=64, and XOR *
204 * on the constant c1 (which is all zeroes) */
205
206 for (i=0; i<16; i++)
207 rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
208
209 /* XOR on the value temp computed before */
210
211 for (i=0; i<16; i++)
212 rijndaelInput[i] ^= temp[i];
213
214 RijndaelEncrypt( rijndaelInput, out1 );
215 for (i=0; i<16; i++)
216 out1[i] ^= op_c[i];
217
218 for (i=0; i<8; i++)
219 mac_s[i] = out1[i+8];
220
221 return;
222} /* end of function f1star */
223
224
225/*-------------------------------------------------------------------
226 * Algorithm f5*
227 *-------------------------------------------------------------------
228 *
229 * Takes key K and random challenge RAND, and returns resynch
230 * anonymity key AK.
231 *
232 *-----------------------------------------------------------------*/
233
234void f5star( u8 k[16], u8 rand[16],
235 u8 ak[6], u8 op[16] )
236{
237 u8 op_c[16];
238 u8 temp[16];
239 u8 out[16];
240 u8 rijndaelInput[16];
241 u8 i;
242
243 RijndaelKeySchedule( k );
244
245 ComputeOPc( op_c, op );
246
247 for (i=0; i<16; i++)
248 rijndaelInput[i] = rand[i] ^ op_c[i];
249 RijndaelEncrypt( rijndaelInput, temp );
250
251 /* To obtain output block OUT5: XOR OPc and TEMP, *
252 * rotate by r5=96, and XOR on the constant c5 (which *
253 * is all zeroes except that the 3rd from last bit is 1). */
254
255 for (i=0; i<16; i++)
256 rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i];
257 rijndaelInput[15] ^= 8;
258
259 RijndaelEncrypt( rijndaelInput, out );
260 for (i=0; i<16; i++)
261 out[i] ^= op_c[i];
262
263 for (i=0; i<6; i++)
264 ak[i] = out[i];
265
266 return;
267} /* end of function f5star */
268
269
270/*-------------------------------------------------------------------
271 * Function to compute OPc from OP and K. Assumes key schedule has
272 already been performed.
273 *-----------------------------------------------------------------*/
274
275void ComputeOPc( u8 op_c[16], u8 op[16] )
276{
277 u8 i;
278
279 RijndaelEncrypt( op, op_c );
280 for (i=0; i<16; i++)
281 op_c[i] ^= op[i];
282
283 return;
284} /* end of function ComputeOPc */