milenage.c

00001 /*-------------------------------------------------------------------
00002  *          Example algorithms f1, f1*, f2, f3, f4, f5, f5*
00003  *-------------------------------------------------------------------
00004  *
00005  *  A sample implementation of the example 3GPP authentication and
00006  *  key agreement functions f1, f1*, f2, f3, f4, f5 and f5*.  This is
00007  *  a byte-oriented implementation of the functions, and of the block
00008  *  cipher kernel function Rijndael.
00009  *
00010  *  This has been coded for clarity, not necessarily for efficiency.
00011  *
00012  *  The functions f2, f3, f4 and f5 share the same inputs and have
00013  *  been coded together as a single function.  f1, f1* and f5* are
00014  *  all coded separately.
00015  *
00016  *-----------------------------------------------------------------*/
00017 
00018 #include "milenage.h"
00019 #include "rijndael.h"
00020 
00021 /*--------------------------- prototypes --------------------------*/
00022 
00023 
00024 
00025 /*-------------------------------------------------------------------
00026  *                            Algorithm f1
00027  *-------------------------------------------------------------------
00028  *
00029  *  Computes network authentication code MAC-A from key K, random
00030  *  challenge RAND, sequence number SQN and authentication management
00031  *  field AMF.
00032  *
00033  *-----------------------------------------------------------------*/
00034 
00035 void f1    ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 
00036              u8 mac_a[8], u8 op[16] )
00037 {
00038   u8 op_c[16];
00039   u8 temp[16];
00040   u8 in1[16];
00041   u8 out1[16];
00042   u8 rijndaelInput[16];
00043   u8 i;
00044 
00045   RijndaelKeySchedule( k );
00046 
00047   ComputeOPc( op_c, op );
00048 
00049   for (i=0; i<16; i++)
00050     rijndaelInput[i] = rand[i] ^ op_c[i];
00051   RijndaelEncrypt( rijndaelInput, temp );
00052 
00053   for (i=0; i<6; i++)
00054   {
00055     in1[i]    = sqn[i];
00056     in1[i+8]  = sqn[i];
00057   }
00058   for (i=0; i<2; i++)
00059   {
00060     in1[i+6]  = amf[i];
00061     in1[i+14] = amf[i];
00062   }
00063 
00064   /* XOR op_c and in1, rotate by r1=64, and XOR *
00065    * on the constant c1 (which is all zeroes)   */
00066 
00067   for (i=0; i<16; i++)
00068     rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
00069 
00070   /* XOR on the value temp computed before */
00071 
00072   for (i=0; i<16; i++)
00073     rijndaelInput[i] ^= temp[i];
00074   
00075   RijndaelEncrypt( rijndaelInput, out1 );
00076   for (i=0; i<16; i++)
00077     out1[i] ^= op_c[i];
00078 
00079   for (i=0; i<8; i++)
00080     mac_a[i] = out1[i];
00081 
00082   return;
00083 } /* end of function f1 */
00084 
00085 
00086   
00087 /*-------------------------------------------------------------------
00088  *                            Algorithms f2-f5
00089  *-------------------------------------------------------------------
00090  *
00091  *  Takes key K and random challenge RAND, and returns response RES,
00092  *  confidentiality key CK, integrity key IK and anonymity key AK.
00093  *
00094  *-----------------------------------------------------------------*/
00095 
00096 void f2345 ( u8 k[16], u8 rand[16],
00097              u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6], u8 op[16] )
00098 {
00099   u8 op_c[16];
00100   u8 temp[16];
00101   u8 out[16];
00102   u8 rijndaelInput[16];
00103   u8 i;
00104 
00105   RijndaelKeySchedule( k );
00106 
00107   ComputeOPc( op_c, op );
00108 
00109   for (i=0; i<16; i++)
00110     rijndaelInput[i] = rand[i] ^ op_c[i];
00111   RijndaelEncrypt( rijndaelInput, temp );
00112 
00113   /* To obtain output block OUT2: XOR OPc and TEMP,    *
00114    * rotate by r2=0, and XOR on the constant c2 (which *
00115    * is all zeroes except that the last bit is 1).     */
00116 
00117   for (i=0; i<16; i++)
00118     rijndaelInput[i] = temp[i] ^ op_c[i];
00119   rijndaelInput[15] ^= 1;
00120 
00121   RijndaelEncrypt( rijndaelInput, out );
00122   for (i=0; i<16; i++)
00123     out[i] ^= op_c[i];
00124 
00125   for (i=0; i<8; i++)
00126     res[i] = out[i+8];
00127   for (i=0; i<6; i++)
00128     ak[i]  = out[i];
00129 
00130   /* To obtain output block OUT3: XOR OPc and TEMP,        *
00131    * rotate by r3=32, and XOR on the constant c3 (which    *
00132    * is all zeroes except that the next to last bit is 1). */
00133 
00134   for (i=0; i<16; i++)
00135     rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i];
00136   rijndaelInput[15] ^= 2;
00137 
00138   RijndaelEncrypt( rijndaelInput, out );
00139   for (i=0; i<16; i++)
00140     out[i] ^= op_c[i];
00141 
00142   for (i=0; i<16; i++)
00143     ck[i] = out[i];
00144 
00145   /* To obtain output block OUT4: XOR OPc and TEMP,         *
00146    * rotate by r4=64, and XOR on the constant c4 (which     *
00147    * is all zeroes except that the 2nd from last bit is 1). */
00148 
00149   for (i=0; i<16; i++)
00150     rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i];
00151   rijndaelInput[15] ^= 4;
00152 
00153   RijndaelEncrypt( rijndaelInput, out );
00154   for (i=0; i<16; i++)
00155     out[i] ^= op_c[i];
00156 
00157   for (i=0; i<16; i++)
00158     ik[i] = out[i];
00159 
00160   return;
00161 } /* end of function f2345 */
00162 
00163   
00164 /*-------------------------------------------------------------------
00165  *                            Algorithm f1*
00166  *-------------------------------------------------------------------
00167  *
00168  *  Computes resynch authentication code MAC-S from key K, random
00169  *  challenge RAND, sequence number SQN and authentication management
00170  *  field AMF.
00171  *
00172  *-----------------------------------------------------------------*/
00173 
00174 void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], 
00175              u8 mac_s[8], u8 op[16] )
00176 {
00177   u8 op_c[16];
00178   u8 temp[16];
00179   u8 in1[16];
00180   u8 out1[16];
00181   u8 rijndaelInput[16];
00182   u8 i;
00183 
00184   RijndaelKeySchedule( k );
00185 
00186   ComputeOPc( op_c, op );
00187 
00188   for (i=0; i<16; i++)
00189     rijndaelInput[i] = rand[i] ^ op_c[i];
00190   RijndaelEncrypt( rijndaelInput, temp );
00191 
00192   for (i=0; i<6; i++)
00193   {
00194     in1[i]    = sqn[i];
00195     in1[i+8]  = sqn[i];
00196   }
00197   for (i=0; i<2; i++)
00198   {
00199     in1[i+6]  = amf[i];
00200     in1[i+14] = amf[i];
00201   }
00202 
00203   /* XOR op_c and in1, rotate by r1=64, and XOR *
00204    * on the constant c1 (which is all zeroes)   */
00205 
00206   for (i=0; i<16; i++)
00207     rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i];
00208 
00209   /* XOR on the value temp computed before */
00210 
00211   for (i=0; i<16; i++)
00212     rijndaelInput[i] ^= temp[i];
00213   
00214   RijndaelEncrypt( rijndaelInput, out1 );
00215   for (i=0; i<16; i++)
00216     out1[i] ^= op_c[i];
00217 
00218   for (i=0; i<8; i++)
00219     mac_s[i] = out1[i+8];
00220 
00221   return;
00222 } /* end of function f1star */
00223 
00224   
00225 /*-------------------------------------------------------------------
00226  *                            Algorithm f5*
00227  *-------------------------------------------------------------------
00228  *
00229  *  Takes key K and random challenge RAND, and returns resynch
00230  *  anonymity key AK.
00231  *
00232  *-----------------------------------------------------------------*/
00233 
00234 void f5star( u8 k[16], u8 rand[16],
00235              u8 ak[6], u8 op[16] )
00236 {
00237   u8 op_c[16];
00238   u8 temp[16];
00239   u8 out[16];
00240   u8 rijndaelInput[16];
00241   u8 i;
00242 
00243   RijndaelKeySchedule( k );
00244 
00245   ComputeOPc( op_c, op );
00246 
00247   for (i=0; i<16; i++)
00248     rijndaelInput[i] = rand[i] ^ op_c[i];
00249   RijndaelEncrypt( rijndaelInput, temp );
00250 
00251   /* To obtain output block OUT5: XOR OPc and TEMP,         *
00252    * rotate by r5=96, and XOR on the constant c5 (which     *
00253    * is all zeroes except that the 3rd from last bit is 1). */
00254 
00255   for (i=0; i<16; i++)
00256     rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i];
00257   rijndaelInput[15] ^= 8;
00258 
00259   RijndaelEncrypt( rijndaelInput, out );
00260   for (i=0; i<16; i++)
00261     out[i] ^= op_c[i];
00262 
00263   for (i=0; i<6; i++)
00264     ak[i] = out[i];
00265 
00266   return;
00267 } /* end of function f5star */
00268 
00269   
00270 /*-------------------------------------------------------------------
00271  *  Function to compute OPc from OP and K.  Assumes key schedule has
00272     already been performed.
00273  *-----------------------------------------------------------------*/
00274 
00275 void ComputeOPc( u8 op_c[16], u8 op[16] )
00276 {
00277   u8 i;
00278   
00279   RijndaelEncrypt( op, op_c );
00280   for (i=0; i<16; i++)
00281     op_c[i] ^= op[i];
00282 
00283   return;
00284 } /* end of function ComputeOPc */

Generated on Wed Mar 7 14:57:54 2007 for Seagull by  doxygen 1.4.6