anubis.c

来自「在BOOTLOADR中增加当今最好AES加密技术,可用于客户远程更新应用程式」· C语言 代码 · 共 1,434 行 · 第 1/5 页

C
1,434
字号
    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 LTC_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 LTC_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
  @return CRYPT_OK if successful
*/
int 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);
   return CRYPT_OK;
}

/**

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?