Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 1 | /*------------------------------------------------------------------- |
| 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 | |
| 35 | void 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 | |
| 96 | void 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 | |
| 174 | void 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 | |
| 234 | void 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 | |
| 275 | void 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 */ |