5G 3GPP USIM Tuak算法code
每个函数的功能如下图:
废话不说直接上code:
/* -------------------------------------------------------------
Constants and Typedefs
-------------------------------------------------------------
*/
typedef unsigned char uint8;
static const uint8 ALGONAME[] = "TUAK1.0";
uint8 TOP[32]; /* Operator's Configuration */
uint8 KEY_sz; /* = 16/32 bytes */
uint8 RES_sz; /* = 4/8/16/32 bytes */
uint8 CK_sz; /* = 16/32 bytes */
uint8 IK_sz; /* = 16/32 bytes */
uint8 MAC_sz; /* = 8/16/32 bytes */
uint8 KeccakIterations; /* >=1, number of iterations */
/* -------------------------------------------------------------
TUAK API Declaration
-------------------------------------------------------------
*/
void TUAK_ComputeTOPC( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *TOPC /* out, uint8[32] */
);
void TUAK_f1 ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *sqn, /* in, uint8[6] */
uint8 *amf, /* in, uint8[2] */
uint8 *mac /* out, uint8[MAC_sz] */
);
void TUAK_f2345 ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *res, /* out, uint8[RES_sz] */
uint8 *ck, /* out, uint8[CK_sz] */
uint8 *ik, /* out, uint8[IK_sz] */
uint8 *ak /* out, uint8[6] */
);
void TUAK_f1s ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *sqn, /* in, uint8[6] */
uint8 *amf, /* in, uint8[2] */
uint8 *mac /* out, uint8[MAC_sz] */
);
void TUAK_f5s ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *ak /* out, uint8[6] */
);
/* This code may be freely used or adapted.
This implementation of TUAK is endianness-free.
It supports 64-bit, 32-bit and 8-bit environments.
*/
/* ---------------------------------------------------------------------
Constants, typedefs, macros, compilation settings
---------------------------------------------------------------------
*/
/* This macro selects Keccak_f implementation instance – 8/32/64-bit version */
#define KECCAK_VERSION_BITS 32
/* Depending on the version of Keccak we do:
- map KECCAK_F macro to relevant Keccak_f (8/32/64-bit) instance
- declare Keccak’s state INOUT[] as global, for simplicity
- define method for TUAK padding TUAK_ADD_PADDING()
*/
#if KECCAK_VERSION_BITS==64
static uint64 INOUT[25]; /* state to Keccak_f for 64-bit version */
extern void Keccak_f_64(uint64 *s);
# define KECCAK_F Keccak_f_64
# define TUAK_ADD_PADDING() INOUT[12] = 0x1FULL, INOUT[16] = (0x01ULL<<63)
#elif KECCAK_VERSION_BITS==32
static uint32 INOUT[50]; /* state to Keccak_f for 32-bit version */
extern void Keccak_f_32(uint32 *s);
# define KECCAK_F Keccak_f_32
# define TUAK_ADD_PADDING() INOUT[24] = 0x1FUL, INOUT[33] = 0x80000000
#elif KECCAK_VERSION_BITS==8
static uint8 INOUT[200]; /* state to Keccak_f for 8-bit version */
extern void Keccak_f_8(uint8 s[200]);
# define KECCAK_F Keccak_f_8
# define TUAK_ADD_PADDING() INOUT[96] = 0x1F, INOUT[135] = 0x80
#else
# error The requested version of Keccak_f is not implemented!
#endif
static const uint8 ALGONAME[] = "TUAK1.0";
void TUAK_ComputeTOPC(uint8*, uint8*);
/* ---------------------------------------------------------------------
TUAK Instance Configuration
if dynamic => can be set/modified on run-time
if constants => fixed instance of the algorithm
---------------------------------------------------------------------
*/
uint8 TOP[32]; /* Operator's Configuration */
uint8 KEY_sz = 16; /* = 16/32 bytes */
uint8 RES_sz = 8; /* = 4/8/16/32 bytes */
uint8 CK_sz = 32; /* = 16/32 bytes */
uint8 IK_sz = 32; /* = 16/32 bytes */
uint8 MAC_sz = 16; /* = 8/16/32 bytes */
uint8 KeccakIterations = 1; /* >=1, number of Keccak_f iterations */
/* ---------------------------------------------------------------------
PUSH_DATA / PULL_DATA, TUAK_Main()
---------------------------------------------------------------------
*/
void PUSH_DATA(const uint8 * data, uint8 n, uint8 location)
{
while(n--)
#if KECCAK_VERSION_BITS==64
INOUT[location>>3] |= ((uint64)data[n]) << ((location++ & 7)<<3);
#elif KECCAK_VERSION_BITS==32
INOUT[location>>2] |= ((uint32)data[n]) << ((location++ & 3)<<3);
#elif KECCAK_VERSION_BITS==8
INOUT[location++] = data[n]; /* Note: reversed order of bytes */
#endif
}
void PULL_DATA(uint8 * data, uint8 n, uint8 location)
{
while(n--)
#if KECCAK_VERSION_BITS==64
data[n] = (uint8)(INOUT[location>>3] >> ((location++ & 7)<<3));
#elif KECCAK_VERSION_BITS==32
data[n] = (uint8)(INOUT[location>>2] >> ((location++ & 3)<<3));
#elif KECCAK_VERSION_BITS==8
data[n] = INOUT[location++]; /* Note: reversed order of bytes */
#endif
}
/* Universal function used by TUAK API functions */
void TUAK_Main ( uint8 instance, /* in, uint8 */
uint8 *rand, /* in, uint8[16] */
uint8 *amf, /* in, uint8[2] */
uint8 *sqn, /* in, uint8[6] */
uint8 *key /* in, uint8[16/32] */
)
{
uint8 i, TOPC[32];
TUAK_ComputeTOPC(key, TOPC); /* compute TOPC */
memset((uint8*)INOUT , 0, 200); /* clean INOUT */
PUSH_DATA(TOPC , 32, 0); /* TOPC */
PUSH_DATA(&instance , 1 , 32); /* INSTANCE */
PUSH_DATA(ALGONAME , 7 , 33); /* ALGONAME */
PUSH_DATA(rand , 16, 40); /* RAND */
if(amf) PUSH_DATA(amf, 2 , 56); /* AMF , if !=NULL */
if(sqn) PUSH_DATA(sqn, 6 , 58); /* SQN , if !=NULL */
PUSH_DATA(key, (instance & 1)?32:16, 64); /* KEY-128/256 bits */
TUAK_ADD_PADDING(); /* Padding bits 768-1087 */
for(i=0; i<KeccakIterations; ++i)
KECCAK_F(INOUT);
}
/* ---------------------------------------------------------------------
TUAK API Definition
---------------------------------------------------------------------
*/
void TUAK_ComputeTOPC( uint8 *key, /* in, uint8[16/32] */
uint8 *TOPC /* out, uint8[32] */
)
{
uint8 i, inst = KEY_sz>>5;
memset(INOUT, 0, 200);
PUSH_DATA(TOP , 32, 0 ); /* TOP */
PUSH_DATA(&inst , 1 , 32); /* INSTANCE for TOPC */
PUSH_DATA(ALGONAME , 7 , 33); /* ALGONAME */
PUSH_DATA(key , KEY_sz, 64); /* KEY-128/256 */
TUAK_ADD_PADDING(); /* Padding bits 768-1087 */
for(i=0; i<KeccakIterations; ++i)
KECCAK_F(INOUT);
PULL_DATA(TOPC, 32, 0); /* get the result */
}
void TUAK_f1 ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *sqn, /* in, uint8[6] */
uint8 *amf, /* in, uint8[2] */
uint8 *mac /* out, uint8[MAC_sz] */
)
{
TUAK_Main( (KEY_sz>>5) | MAC_sz, rand, amf, sqn, key);
PULL_DATA(mac, MAC_sz, 0);
}
void TUAK_f2345 ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *res, /* out, uint8[RES_sz] */
uint8 *ck, /* out, uint8[CK_sz] */
uint8 *ik, /* out, uint8[IK_sz] */
uint8 *ak /* out, uint8[6] */
)
{
TUAK_Main( (KEY_sz>>5) | ((IK_sz>>4)&0x02) | ((CK_sz>>3)&0x04)
| (RES_sz&0x38) | 0x40, rand, 0, 0, key);
PULL_DATA(res, RES_sz, 0 );
PULL_DATA(ck , CK_sz , 32);
PULL_DATA(ik , IK_sz , 64);
PULL_DATA(ak , 6 , 96);
}
void TUAK_f1s ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *sqn, /* in, uint8[6] */
uint8 *amf, /* in, uint8[2] */
uint8 *mac /* out, uint8[MAC_sz] */
)
{
TUAK_Main( (KEY_sz>>5) | MAC_sz | 0x80, rand, amf, sqn, key);
PULL_DATA(mac, MAC_sz, 0);
}
void TUAK_f5s ( uint8 *key, /* in, uint8[KEY_sz] */
uint8 *rand, /* in, uint8[16] */
uint8 *ak /* out, uint8[6] */
)
{
TUAK_Main( (KEY_sz>>5) | 0xc0, rand, 0, 0, key);
PULL_DATA(ak, 6, 96);
}
/* This code may be freely used or adapted.
*/
typedef unsigned char uint8;
typedef unsigned long uint32;
typedef unsigned long long uint64;
const uint8 Rho[25] = {
0,1,62,28,27,36,44,6,55,20,3,10,43,25,39,41,45,
15,21,8,18,2,61,56,14};
const uint8 Pi[25] = {
0,6,12,18,24,3,9,10,16,22,1,7,13,19,20,4,5,11,17,
23,2,8,14,15,21};
const uint8 Iota[24] = {
1,146,218,112,155,33,241,89,138,136,57,42,187,203,
217,83,82,192,26,106,241,208,33,120};
#define ROTATE64(value, n) \
((((uint64)(value))<<(n)) | (((uint64)(value))>>(64-(n))))
/* ---------------------------------------------------------------------
64-bit version of Keccak_f(1600)
---------------------------------------------------------------------
*/
void Keccak_f_64(uint64 *s)
{
uint64 t[5];
uint8 i, j, round;
for(round=0; round<24; ++round)
{
/* Theta function */
for(i=0; i<5; ++i)
t[i] = s[i] ^ s[5+i] ^ s[10+i] ^ s[15+i] ^ s[20+i];
for(i=0; i<5; ++i, s+=5)
{
s[0] ^= t[4] ^ ROTATE64(t[1], 1);
s[1] ^= t[0] ^ ROTATE64(t[2], 1);
s[2] ^= t[1] ^ ROTATE64(t[3], 1);
s[3] ^= t[2] ^ ROTATE64(t[4], 1);
s[4] ^= t[3] ^ ROTATE64(t[0], 1);
}
s -= 25;
/* Rho function */
for(i=1; i<25; ++i)
s[i] = ROTATE64(s[i], Rho[i]);
/* Pi function */
for(t[1] = s[i=1]; (j=Pi[i]) > 1; s[i]=s[j], i=j);
s[i] = t[1];
/* Chi function */
for(i=0; i<5; ++i, s += 5)
{
t[0] = (~s[1]) & s[2];
t[1] = (~s[2]) & s[3];
t[2] = (~s[3]) & s[4];
t[3] = (~s[4]) & s[0];
t[4] = (~s[0]) & s[1];
for(j=0; j<5; ++j) s[j] ^= t[j];
}
s -= 25;
/* Iota function */
t[0] = Iota[round];
*s ^= (t[0] | (t[0]<<11) | (t[0]<<26) | (t[0]<<57))
& 0x800000008000808BULL; /* set & mask bits 0,1,3,7,15,31,63 */
}
}
/* ---------------------------------------------------------------------
8-bit version of Keccak_f(1600)
---------------------------------------------------------------------
*/
void Keccak_f_8(uint8 s[200])
{
uint8 t[40], i, j, k, round;
for(round=0; round<24; ++round)
{
/* Theta function */
for(i=0; i<40; ++i)
t[i]=s[i]^s[40+i]^s[80+i]^s[120+i]^s[160+i];
for(i=0; i<200; i+=8)
for(j = (i+32)%40, k=0; k<8; ++k)
s[i+k] ^= t[j+k];
for(i=0; i<40; t[i] = (t[i]<<1)|j, i+=8)
for(j = t[i+7]>>7, k=7; k; --k)
t[i+k] = (t[i+k]<<1)|(t[i+k-1]>>7);
for(i=0; i<200; i+=8)
for(j = (i+8)%40, k=0; k<8; ++k)
s[i+k] ^= t[j+k];
/* Rho function */
for(i=8; i<200; i+=8)
{
for(j = Rho[i>>3]>>3, k=0; k<8; ++k) /* j:=bytes to shift, s->t */
t[(k+j)&7] = s[i+k];
for(j = Rho[i>>3]&7, k=7; k; --k) /* j:=bits to shift, t->s */
s[i+k] = (t[k]<<j) | (t[k-1]>>(8-j));
s[i] = (t[0]<<j) | (t[7]>>(8-j));
}
/* Pi function */
for(k=8; k<16; ++k) t[k] = s[k]; /* =memcpy(t+8, s+8, 8) */
for(i=1; (j=Pi[i])>1; i=j)
for(k=0; k<8; ++k) /* =memcpy(s+(i<<3), s+(j<<3), 8) */
s[(i<<3)|k] = s[(j<<3)|k];
for(k=0; k<8; ++k) /* =memcpy(s+(i<<3), t+8, 8) */
s[(i<<3)|k] = t[k+8];
/* Chi function */
for(i=0; i<200; i+=40)
{
for(j=0; j<40; ++j)
t[j]=(~s[i+(j+8)%40]) & s[i+(j+16)%40];
for(j=0; j<40; ++j) s[i+j]^=t[j];
}
/* Iota function */
k = Iota[round];
s[0] ^= k & 0x8B; /* bits 0, 1, 3, 7 */
s[1] ^= (k<<3)&0x80; /* bit 15 */
s[3] ^= (k<<2)&0x80; /* bit 31 */
s[7] ^= (k<<1)&0x80; /* bit 63 */
}
}
/* ---------------------------------------------------------------------
32-bit version of Keccak_f(1600)
---------------------------------------------------------------------
*/
void Keccak_f_32(uint32 *s)
{
uint32 t[10];
uint8 i, j, round, k;
for(round=0; round<24; ++round)
{
/* Theta function */
for(i=0; i<10; ++i)
t[i] = s[i] ^ s[10+i] ^ s[20+i] ^ s[30+i] ^ s[40+i];
for(i=0; i<5; ++i)
for(j=8, k=2; ; j%=10, k=(k+2)%10)
{
*s++ ^= t[j++] ^ ((t[k]<<1)|(t[k+1]>>31));
*s++ ^= t[j++] ^ ((t[k+1]<<1)|(t[k]>>31));
if(j==8) break;
}
s -= 50;
/* Rho function */
for(i=2; i<50; i+=2)
{
k = Rho[i>>1] & 0x1f;
t[0] = (s[i+1] << k) | (s[i] >> (32-k));
t[1] = (s[i] << k) | (s[i+1] >> (32-k));
k = Rho[i>>1] >> 5;
s[i] = t[1-k], s[i+1] = t[k];
}
/* Pi function */
for(i=2, t[0]=s[2], t[1]=s[3]; (j=(Pi[i>>1]<<1))>2; i=j)
s[i]=s[j], s[i+1]=s[j+1];
s[i]=t[0], s[i+1]=t[1];
/* Chi function */
for(i=0; i<5; ++i, s+=10)
{
for(j=0; j<10; ++j)
t[j] = (~s[(j+2)%10]) & s[(j+4)%10];
for(j=0; j<10; ++j)
s[j] ^= t[j];
}
s -= 50;
/* Iota function */
t[0] = Iota[round];
s[0] ^= (t[0] | (t[0]<<11) | (t[0]<<26)) & 0x8000808B;
s[1] ^= (t[0]<<25) & 0x80000000;
}
}
算法原理参考3GPP文档(传送门)