📄 anubis.c
字号:
0xdca5f2aeU, 0xdda7f4a6U, 0xdea1febeU, 0xdfa3f8b6U,
0xe0dd7a53U, 0xe1df7c5bU, 0xe2d97643U, 0xe3db704bU,
0xe4d56273U, 0xe5d7647bU, 0xe6d16e63U, 0xe7d3686bU,
0xe8cd4a13U, 0xe9cf4c1bU, 0xeac94603U, 0xebcb400bU,
0xecc55233U, 0xedc7543bU, 0xeec15e23U, 0xefc3582bU,
0xf0fd1ad3U, 0xf1ff1cdbU, 0xf2f916c3U, 0xf3fb10cbU,
0xf4f502f3U, 0xf5f704fbU, 0xf6f10ee3U, 0xf7f308ebU,
0xf8ed2a93U, 0xf9ef2c9bU, 0xfae92683U, 0xfbeb208bU,
0xfce532b3U, 0xfde734bbU, 0xfee13ea3U, 0xffe338abU,
};
/**
* The round constants.
*/
static const ulong32 rc[] = {
0xa7d3e671U, 0xd0ac4d79U, 0x3ac991fcU, 0x1e4754bdU,
0x8ca57afbU, 0x63b8ddd4U, 0xe5b3c5beU, 0xa9880ca2U,
0x39df29daU, 0x2ba8cb4cU, 0x4b22aa24U, 0x4170a6f9U,
0x5ae2b036U, 0x7de433ffU, 0x6020088bU, 0x5eab7f78U,
0x7c2c57d2U, 0xdc6d7e0dU, 0x5394c328U,
};
#endif
/**
Initialize the Anubis block cipher
@param key The symmetric key you wish to pass
@param keylen The key length in bytes
@param num_rounds The number of rounds desired (0 for default)
@param skey The key in as scheduled by this function.
@return CRYPT_OK if successful
*/
#ifdef CLEAN_STACK
static int _anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
#else
int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
#endif
{
int N, R, i, pos, r;
ulong32 kappa[MAX_N];
ulong32 inter[MAX_N];
ulong32 v, K0, K1, K2, K3;
LTC_ARGCHK(key != NULL);
LTC_ARGCHK(skey != NULL);
/* Valid sizes (in bytes) are 16, 20, 24, 28, 32, 36, and 40. */
if ((keylen & 3) || (keylen < 16) || (keylen > 40)) {
return CRYPT_INVALID_KEYSIZE;
}
skey->anubis.keyBits = keylen*8;
/*
* determine the N length parameter:
* (N.B. it is assumed that the key length is valid!)
*/
N = skey->anubis.keyBits >> 5;
/*
* determine number of rounds from key size:
*/
skey->anubis.R = R = 8 + N;
if (num_rounds != 0 && num_rounds != skey->anubis.R) {
return CRYPT_INVALID_ROUNDS;
}
/*
* map cipher key to initial key state (mu):
*/
for (i = 0, pos = 0; i < N; i++, pos += 4) {
kappa[i] =
(key[pos ] << 24) ^
(key[pos + 1] << 16) ^
(key[pos + 2] << 8) ^
(key[pos + 3] );
}
/*
* generate R + 1 round keys:
*/
for (r = 0; r <= R; r++) {
/*
* generate r-th round key K^r:
*/
K0 = T4[(kappa[N - 1] >> 24) ];
K1 = T4[(kappa[N - 1] >> 16) & 0xff];
K2 = T4[(kappa[N - 1] >> 8) & 0xff];
K3 = T4[(kappa[N - 1] ) & 0xff];
for (i = N - 2; i >= 0; i--) {
K0 = T4[(kappa[i] >> 24) ] ^
(T5[(K0 >> 24) ] & 0xff000000U) ^
(T5[(K0 >> 16) & 0xff] & 0x00ff0000U) ^
(T5[(K0 >> 8) & 0xff] & 0x0000ff00U) ^
(T5[(K0 ) & 0xff] & 0x000000ffU);
K1 = T4[(kappa[i] >> 16) & 0xff] ^
(T5[(K1 >> 24) ] & 0xff000000U) ^
(T5[(K1 >> 16) & 0xff] & 0x00ff0000U) ^
(T5[(K1 >> 8) & 0xff] & 0x0000ff00U) ^
(T5[(K1 ) & 0xff] & 0x000000ffU);
K2 = T4[(kappa[i] >> 8) & 0xff] ^
(T5[(K2 >> 24) ] & 0xff000000U) ^
(T5[(K2 >> 16) & 0xff] & 0x00ff0000U) ^
(T5[(K2 >> 8) & 0xff] & 0x0000ff00U) ^
(T5[(K2 ) & 0xff] & 0x000000ffU);
K3 = T4[(kappa[i] ) & 0xff] ^
(T5[(K3 >> 24) ] & 0xff000000U) ^
(T5[(K3 >> 16) & 0xff] & 0x00ff0000U) ^
(T5[(K3 >> 8) & 0xff] & 0x0000ff00U) ^
(T5[(K3 ) & 0xff] & 0x000000ffU);
}
/*
-- this is the code to use with the large U tables:
K0 = K1 = K2 = K3 = 0;
for (i = 0; i < N; i++) {
K0 ^= U[i][(kappa[i] >> 24) ];
K1 ^= U[i][(kappa[i] >> 16) & 0xff];
K2 ^= U[i][(kappa[i] >> 8) & 0xff];
K3 ^= U[i][(kappa[i] ) & 0xff];
}
*/
skey->anubis.roundKeyEnc[r][0] = K0;
skey->anubis.roundKeyEnc[r][1] = K1;
skey->anubis.roundKeyEnc[r][2] = K2;
skey->anubis.roundKeyEnc[r][3] = K3;
/*
* compute kappa^{r+1} from kappa^r:
*/
if (r == R) {
break;
}
for (i = 0; i < N; i++) {
int j = i;
inter[i] = T0[(kappa[j--] >> 24) ]; if (j < 0) j = N - 1;
inter[i] ^= T1[(kappa[j--] >> 16) & 0xff]; if (j < 0) j = N - 1;
inter[i] ^= T2[(kappa[j--] >> 8) & 0xff]; if (j < 0) j = N - 1;
inter[i] ^= T3[(kappa[j ] ) & 0xff];
}
kappa[0] = inter[0] ^ rc[r];
for (i = 1; i < N; i++) {
kappa[i] = inter[i];
}
}
/*
* generate inverse key schedule: K'^0 = K^R, K'^R = K^0, K'^r = theta(K^{R-r}):
*/
for (i = 0; i < 4; i++) {
skey->anubis.roundKeyDec[0][i] = skey->anubis.roundKeyEnc[R][i];
skey->anubis.roundKeyDec[R][i] = skey->anubis.roundKeyEnc[0][i];
}
for (r = 1; r < R; r++) {
for (i = 0; i < 4; i++) {
v = skey->anubis.roundKeyEnc[R - r][i];
skey->anubis.roundKeyDec[r][i] =
T0[T4[(v >> 24) ] & 0xff] ^
T1[T4[(v >> 16) & 0xff] & 0xff] ^
T2[T4[(v >> 8) & 0xff] & 0xff] ^
T3[T4[(v ) & 0xff] & 0xff];
}
}
return CRYPT_OK;
}
#ifdef CLEAN_STACK
int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
{
int err;
err = _anubis_setup(key, keylen, num_rounds, skey);
burn_stack(sizeof(int) * 5 + sizeof(ulong32) * (MAX_N + MAX_N + 5));
return err;
}
#endif
static void anubis_crypt(const unsigned char *plaintext, unsigned char *ciphertext,
ulong32 roundKey[18 + 1][4], int R) {
int i, pos, r;
ulong32 state[4];
ulong32 inter[4];
/*
* map plaintext block to cipher state (mu)
* and add initial round key (sigma[K^0]):
*/
for (i = 0, pos = 0; i < 4; i++, pos += 4) {
state[i] =
(plaintext[pos ] << 24) ^
(plaintext[pos + 1] << 16) ^
(plaintext[pos + 2] << 8) ^
(plaintext[pos + 3] ) ^
roundKey[0][i];
}
/*
* R - 1 full rounds:
*/
for (r = 1; r < R; r++) {
inter[0] =
T0[(state[0] >> 24) ] ^
T1[(state[1] >> 24) ] ^
T2[(state[2] >> 24) ] ^
T3[(state[3] >> 24) ] ^
roundKey[r][0];
inter[1] =
T0[(state[0] >> 16) & 0xff] ^
T1[(state[1] >> 16) & 0xff] ^
T2[(state[2] >> 16) & 0xff] ^
T3[(state[3] >> 16) & 0xff] ^
roundKey[r][1];
inter[2] =
T0[(state[0] >> 8) & 0xff] ^
T1[(state[1] >> 8) & 0xff] ^
T2[(state[2] >> 8) & 0xff] ^
T3[(state[3] >> 8) & 0xff] ^
roundKey[r][2];
inter[3] =
T0[(state[0] ) & 0xff] ^
T1[(state[1] ) & 0xff] ^
T2[(state[2] ) & 0xff] ^
T3[(state[3] ) & 0xff] ^
roundKey[r][3];
state[0] = inter[0];
state[1] = inter[1];
state[2] = inter[2];
state[3] = inter[3];
}
/*
* last round:
*/
inter[0] =
(T0[(state[0] >> 24) ] & 0xff000000U) ^
(T1[(state[1] >> 24) ] & 0x00ff0000U) ^
(T2[(state[2] >> 24) ] & 0x0000ff00U) ^
(T3[(state[3] >> 24) ] & 0x000000ffU) ^
roundKey[R][0];
inter[1] =
(T0[(state[0] >> 16) & 0xff] & 0xff000000U) ^
(T1[(state[1] >> 16) & 0xff] & 0x00ff0000U) ^
(T2[(state[2] >> 16) & 0xff] & 0x0000ff00U) ^
(T3[(state[3] >> 16) & 0xff] & 0x000000ffU) ^
roundKey[R][1];
inter[2] =
(T0[(state[0] >> 8) & 0xff] & 0xff000000U) ^
(T1[(state[1] >> 8) & 0xff] & 0x00ff0000U) ^
(T2[(state[2] >> 8) & 0xff] & 0x0000ff00U) ^
(T3[(state[3] >> 8) & 0xff] & 0x000000ffU) ^
roundKey[R][2];
inter[3] =
(T0[(state[0] ) & 0xff] & 0xff000000U) ^
(T1[(state[1] ) & 0xff] & 0x00ff0000U) ^
(T2[(state[2] ) & 0xff] & 0x0000ff00U) ^
(T3[(state[3] ) & 0xff] & 0x000000ffU) ^
roundKey[R][3];
/*
* map cipher state to ciphertext block (mu^{-1}):
*/
for (i = 0, pos = 0; i < 4; i++, pos += 4) {
ulong32 w = inter[i];
ciphertext[pos ] = (unsigned char)(w >> 24);
ciphertext[pos + 1] = (unsigned char)(w >> 16);
ciphertext[pos + 2] = (unsigned char)(w >> 8);
ciphertext[pos + 3] = (unsigned char)(w );
}
}
/**
Encrypts a block of text with Anubis
@param pt The input plaintext (16 bytes)
@param ct The output ciphertext (16 bytes)
@param skey The key as scheduled
*/
void anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
{
LTC_ARGCHK(pt != NULL);
LTC_ARGCHK(ct != NULL);
LTC_ARGCHK(skey != NULL);
anubis_crypt(pt, ct, skey->anubis.roundKeyEnc, skey->anubis.R);
}
/**
Decrypts a block of text with Anubis
@param ct The input ciphertext (16 bytes)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -