源码是基于 FIPS PUB 197 标准开发的。关于FIPS PUB 197 标准详见《Federal InformationProcessing Standards Publication 197》文件,

1. 密钥扩展

如上文3.4章节介绍密钥扩展过程的代码如下:

/**
 * @brief    Key Expansion      
 * @param    *key 密钥
 * @param   *w   密钥编排结果    
 * @retval 
 */
void aes_key_expansion(uint8_t *key, uint8_t *w) 
{
  uint8_t tmp[4];
  uint8_t i;
  uint8_t len = Nb*(Nr+1);        //分组大小*(轮数+1)

  //1)将初始密钥以列为主,转化为4个32 bits的字,分别记为w[0…3]
  for (i = 0; i < Nk; i++) {
    w[4*i+0] = key[4*i+0];
    w[4*i+1] = key[4*i+1];
    w[4*i+2] = key[4*i+2];
    w[4*i+3] = key[4*i+3];
  }

  //2)依次求解w[i],其中j是整数并且属于[4,43];for (i = Nk; i < len; i++) {
    tmp[0] = w[4*(i-1)+0];
    tmp[1] = w[4*(i-1)+1];
    tmp[2] = w[4*(i-1)+2];
    tmp[3] = w[4*(i-1)+3];

    //3)若i%4=0,则w[i]=w[i-4]⊕g(w[i-1]),否则w[i]=w[i-4]⊕w[i-1];if (i%Nk == 0) {
      rot_word(tmp);      //4)将w循环左移一个字节;sub_word(tmp);      //5)分别对每个字节按S盒进行映射;coef_add(tmp, Rcon(i/Nk), tmp);    //6)与32 bits的常量(RC[j/4],0,0,0)进行异或
    } else if (Nk > 6 && i%Nk == 4) {
      sub_word(tmp);
    }

    w[4*i+0] = w[4*(i-Nk)+0]^tmp[0];
    w[4*i+1] = w[4*(i-Nk)+1]^tmp[1];
    w[4*i+2] = w[4*(i-Nk)+2]^tmp[2];
    w[4*i+3] = w[4*(i-Nk)+3]^tmp[3];
  }
}

2. 加密过程

1)先得到到扩展密钥 W
2) 把128bit字符放进状态矩阵
3)对状态矩阵进行混淆 S = AddRoundKey(S, W0),
4)在执行Nr轮加密 (字节替换、行移位变换、列混合变换、轮密钥加变换)

代码如下:
/**
 * @brief  Performs the AES cipher operation    
 * @param  *in    明文
 * @param  *out    加密后的密文
 * @param  *w 扩展后的密钥
 * @retval 
 */
void aes_cipher(uint8_t *in, uint8_t *out, uint8_t *w) 
{
  uint8_t state[4*Nb];
  uint8_t r, i, j;

  //STEP2: 把128bit字符放进状态矩阵
  for (i = 0; i < 4; i++) {
    for (j = 0; j < Nb; j++) {
      state[Nb*i+j] = in[i+4*j];
    }
  }

  //STEP3: 对状态矩阵进行混淆
  add_round_key(state, w, 0);    

  //STEP4: 在执行完Nr轮加密
  for (r = 1; r < Nr; r++) {
    sub_bytes(state);      //字节替换
    shift_rows(state);    //行移位变换
    mix_columns(state);    //列混合变换 
    add_round_key(state, w, r);  //轮密钥加变换
  }

  sub_bytes(state);
  shift_rows(state);
  add_round_key(state, w, Nr);

  for (i = 0; i < 4; i++) {
    for (j = 0; j < Nb; j++) {
      out[i+4*j] = state[Nb*i+j];
    }
  }
}

3. 解密过程

解密函数中调用的是各轮操作的逆函数。代码如下:

/**
 * @brief    Performs the AES inverse cipher operation      
 * @param  *in    密文
 * @param  *out    密文的逆
 * @param  *w 扩展后的密钥
 * @retval 
 */
void aes_inv_cipher(uint8_t *in, uint8_t *out, uint8_t *w) {

  uint8_t state[4*Nb];
  uint8_t r, i, j;

  for (i = 0; i < 4; i++) {
    for (j = 0; j < Nb; j++) {
      state[Nb*i+j] = in[i+4*j];
    }
  }

  add_round_key(state, w, Nr);

  for (r = Nr-1; r >= 1; r--) {
    inv_shift_rows(state);
    inv_sub_bytes(state);
    add_round_key(state, w, r);
    inv_mix_columns(state);
  }

  inv_shift_rows(state);
  inv_sub_bytes(state);
  add_round_key(state, w, 0);

  for (i = 0; i < 4; i++) {
    for (j = 0; j < Nb; j++) {
      out[i+4*j] = state[Nb*i+j];
    }
  }
}

4. API介绍

  • AddRoundKey()

加密和解密中使用的变换,将一个轮密钥异或到状态上。轮密钥的长度等于状态的大小(即对于 Nb=4, 轮密钥长度等于128bits/16bytes)

  • MixColumns()

加密中使用的变换,以状态的每一列作为输入,混合每一列的数据(彼此独立的)得到新的列。

  • Rcon[]

密钥扩展算法中用到的轮常数

  • RotWord()

密钥扩展算法中使用的函数,对 4-byte 字进行循环移位

  • ShiftRows()

加密中使用的变换, 将状态的最后 3 行循环移动不同的位移量

  • SubBytes()

加密中使用的变换,利用一个非线性字节替代表(S 盒),独立地对状态的每个字节进行操作

  • SubWord()

密钥扩展算法中使用的函数,它以 4-byte 字作为输入,对于 4 字节中的每一字节分别应用 S 盒,得到一个输出字

  • AddRoundKey()

加密和解密中使用的变换,将一个轮密钥异或到状态上。轮密钥的长度等于状态的大小(即对于 Nb=4, 轮密钥长度等于128bits/16bytes)

  • InvMixColumns()

解密中使用的变换, MixColumns()的逆变换

  • InvShiftRows()

解密中使用的变换, ShiftRows()的逆变换

  • InvSubBytes()

解密中使用的变换, SubBytes()的逆变换

更多详细介绍详见代码目录下我用Doxygen软件制作的 index.html 文件

基于 Cortex-M3 完整的程序代码