Verilog入门——AES实现


AES加密流程介绍

参考:https://blog.csdn.net/qq_28205153/article/details/55798628

AES加密基本背景

AES为分组密码,即将待加密明文分为长度相等的组(AES中分组只能为128位,即16字节),每次加密一组数据直至全部加密完成。加密密钥长度可以为128位、192位、256位,密钥长度不同加密轮数不同。

AES 密钥长度 分组长度 加密轮数
AES-128 4 4 10
AES-196 6 4 12
AES-256 8 4 14

本文讨论的是AES-128,密钥长度128位,加密轮数10。

AES加密的单位是字节,128位明文输入和128位密钥K均被分为16个字节,记为P=P0P1…P14P15,K=K0K1…K14K15。

明文分组排列位4×4的状态矩阵,作为第一轮加密的输入,时候每一轮加密的输出作为下一轮加密的输入,最后一轮输出的状态矩阵作为密文。

P0 P4 P8 P12
P1 P5 P9 P13
P2 P6 P10 P14
P3 P7 P11 P15

密钥同样排列为4×4矩阵

K0 K4 k8 k12
K1 K5 k9 K13
K2 K6 K10 K14
K3 K7 K11 K15

每一列都可以看作一个32位字,记为W[0],W[1],W[2],W[3]。
密钥最终需要被扩展为44个字组成的序列,W[0],W[1],…,W[43]。后面的密钥由原始密钥扩展得到,后面在详细描述密钥扩展算法。

加解密流程

AES加密流程为:

  1. 明文进行轮密钥加(密钥为W[0,3])
  2. 9轮加密,每一轮包括:字节代换、行移位、列混合、轮密钥加(密钥依次为W[4,7],…,W[36,39])
  3. 第10轮加密,包括:字节代换、行移位、轮密钥加(密钥为W[40,43])

AES解密流程为:

  1. 密文进行轮密钥加(密钥为W[40,43])
  2. 9轮解密,每一轮包括:逆行移位、逆字节代换、轮密钥加(密钥依次为W[36,39],…,W[4,7])、逆列混合
  3. 第10轮解密,包括逆行移位、逆字节代换、 轮密钥加(密钥为W[0,3])

下面对加解密过程中涉及到的字节代换、行移位、列混合、轮密钥加操作进行讲解。

具体实现

01 字节代换与逆字节代换

AES字节代换是一个简单的查表操作。AES定义了一个S盒与逆S盒(百度可查,不作展示),均为15×15的表格,表格中元素为1字节。字节代换通过S盒映射,逆字节代换通过逆S盒映射。
将状态矩阵中的元素(元素大小为1字节=8位)高4位作为行值,低4位作为列值,查找对应位置元素进行替换。

02 行移位与逆行移位

行移位:将状态矩阵中的第 i 行循环左移 i 字节。
逆行移位:将状态矩阵中的第 i 行循环右移 i 字节。

03 列混合与逆列混合

列混合通过矩阵相乘实现:新的状态矩阵=列混合矩阵×原本的状态矩阵。
逆列混合通过矩阵相乘实现:新的状态矩阵=逆列混合矩阵×原本的状态矩阵。
(其中逆列混合矩阵与列混合矩阵相乘恰好为单位矩阵。)

注:这里提到的乘法与加法都是定义在基于GF(2^8)上的二元运算,这里不作赘述。

04 轮密钥加

将128位轮密钥Ki=W[4i],W[4i+1],W[4i+2],W[4i+3]与状态矩阵中的每一列数据进行逐位异或,如下图:
Verilog入门——AES实现_第1张图片

05 密钥扩展

原始密钥为W[0],W[1],W[2],W[4],扩展至W[43]共11组密钥。W[i]扩展方法如下:

  1. 如果i是4的倍数,那么第i列为:W[i]=W[i-4]⨁T(W[i-1])
  2. 如果i不是4的倍数,那么第i列为:W[i]=W[i-4]⨁W[i-1]

其中,T是一个有点复杂的函数,由3部分组成:字循环、字节代换和轮常量异或。
W[i]大小为一个32位字,即4字节,可记为[b0,b1,b2,b3]
a.字循环:将1个字中的4个字节循环左移 1 个字节。变换成[b1,b2,b3,b0]。
b.字节代换:对字循环的结果使用S盒进行字节代换。
c.轮常量异或:将前两步的结果同轮常量Rcon[j]进行按位异或,轮常量Rcon[j]是一个字,其中j表示轮数,j取值为1~10,因为要进行10轮扩展。

Rcon[j]取值依次为如下:
0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,
0x20000000,0x40000000,0x80000000,0x1b000000,0x36000000

Verilog源码分析

由于之前没有使用过Verilog语言,这里推荐一个Verilog语法0基础入门教程,讲解的蛮清楚的:
https://vlab.ustc.edu.cn/guide/doc_verilog.html

下面就来分析AES的Verilog实现与testbench的编写:
AES.v来源
http://www.aoki.ecei.tohoku.ac.jp/crypto/items/AES.v
AES_TB.v来源
http://www.aoki.ecei.tohoku.ac.jp/crypto/items/AES_TB.v

AES.v分析

此处仅展示加密部分(有一些时序理解上的错误,待修订…)

module SubBytes (x, y);//S盒字节代换
  input  [31:0] x;
  output [31:0] y;
  
  function [7:0] S;
  input    [7:0] x;
    case (x)
        0:S= 99;   1:S=124;   2:S=119;   3:S=123;   4:S=242;   5:S=107;   6:S=111;   7:S=197;
        8:S= 48;   9:S=  1;  10:S=103;  11:S= 43;  12:S=254;  13:S=215;  14:S=171;  15:S=118;
       16:S=202;  17:S=130;  18:S=201;  19:S=125;  20:S=250;  21:S= 89;  22:S= 71;  23:S=240;
       24:S=173;  25:S=212;  26:S=162;  27:S=175;  28:S=156;  29:S=164;  30:S=114;  31:S=192;
       32:S=183;  33:S=253;  34:S=147;  35:S= 38;  36:S= 54;  37:S= 63;  38:S=247;  39:S=204;
       40:S= 52;  41:S=165;  42:S=229;  43:S=241;  44:S=113;  45:S=216;  46:S= 49;  47:S= 21;
       48:S=  4;  49:S=199;  50:S= 35;  51:S=195;  52:S= 24;  53:S=150;  54:S=  5;  55:S=154;
       56:S=  7;  57:S= 18;  58:S=128;  59:S=226;  60:S=235;  61:S= 39;  62:S=178;  63:S=117;
       64:S=  9;  65:S=131;  66:S= 44;  67:S= 26;  68:S= 27;  69:S=110;  70:S= 90;  71:S=160;
       72:S= 82;  73:S= 59;  74:S=214;  75:S=179;  76:S= 41;  77:S=227;  78:S= 47;  79:S=132;
       80:S= 83;  81:S=209;  82:S=  0;  83:S=237;  84:S= 32;  85:S=252;  86:S=177;  87:S= 91;
       88:S=106;  89:S=203;  90:S=190;  91:S= 57;  92:S= 74;  93:S= 76;  94:S= 88;  95:S=207;
       96:S=208;  97:S=239;  98:S=170;  99:S=251; 100:S= 67; 101:S= 77; 102:S= 51; 103:S=133;
      104:S= 69; 105:S=249; 106:S=  2; 107:S=127; 108:S= 80; 109:S= 60; 110:S=159; 111:S=168;
      112:S= 81; 113:S=163; 114:S= 64; 115:S=143; 116:S=146; 117:S=157; 118:S= 56; 119:S=245;
      120:S=188; 121:S=182; 122:S=218; 123:S= 33; 124:S= 16; 125:S=255; 126:S=243; 127:S=210;
      128:S=205; 129:S= 12; 130:S= 19; 131:S=236; 132:S= 95; 133:S=151; 134:S= 68; 135:S= 23;
      136:S=196; 137:S=167; 138:S=126; 139:S= 61; 140:S=100; 141:S= 93; 142:S= 25; 143:S=115;
      144:S= 96; 145:S=129; 146:S= 79; 147:S=220; 148:S= 34; 149:S= 42; 150:S=144; 151:S=136;
      152:S= 70; 153:S=238; 154:S=184; 155:S= 20; 156:S=222; 157:S= 94; 158:S= 11; 159:S=219;
      160:S=224; 161:S= 50; 162:S= 58; 163:S= 10; 164:S= 73; 165:S=  6; 166:S= 36; 167:S= 92;
      168:S=194; 169:S=211; 170:S=172; 171:S= 98; 172:S=145; 173:S=149; 174:S=228; 175:S=121;
      176:S=231; 177:S=200; 178:S= 55; 179:S=109; 180:S=141; 181:S=213; 182:S= 78; 183:S=169;
      184:S=108; 185:S= 86; 186:S=244; 187:S=234; 188:S=101; 189:S=122; 190:S=174; 191:S=  8;
      192:S=186; 193:S=120; 194:S= 37; 195:S= 46; 196:S= 28; 197:S=166; 198:S=180; 199:S=198;
      200:S=232; 201:S=221; 202:S=116; 203:S= 31; 204:S= 75; 205:S=189; 206:S=139; 207:S=138;
      208:S=112; 209:S= 62; 210:S=181; 211:S=102; 212:S= 72; 213:S=  3; 214:S=246; 215:S= 14;
      216:S= 97; 217:S= 53; 218:S= 87; 219:S=185; 220:S=134; 221:S=193; 222:S= 29; 223:S=158;
      224:S=225; 225:S=248; 226:S=152; 227:S= 17; 228:S=105; 229:S=217; 230:S=142; 231:S=148;
      232:S=155; 233:S= 30; 234:S=135; 235:S=233; 236:S=206; 237:S= 85; 238:S= 40; 239:S=223;
      240:S=140; 241:S=161; 242:S=137; 243:S= 13; 244:S=191; 245:S=230; 246:S= 66; 247:S=104;
      248:S= 65; 249:S=153; 250:S= 45; 251:S= 15; 252:S=176; 253:S= 84; 254:S=187; 255:S= 22;
    endcase
  endfunction
  
  assign y = {S(x[31:24]), S(x[23:16]), S(x[15: 8]), S(x[ 7: 0])};
endmodule

module MixColumns(x, y);//列混合
  input  [31:0]  x;
  output [31:0]  y;
  
  wire [7:0] a3, a2, a1, a0, b3, b2, b1, b0;
  
  assign a3 = x[31:24];
  assign a2 = x[23:16];
  assign a1 = x[15: 8];
  assign a0 = x[ 7: 0];
  
  assign b3 = a3 ^ a2;
  assign b2 = a2 ^ a1;
  assign b1 = a1 ^ a0;
  assign b0 = a0 ^ a3;
  
  assign y = {a2[7] ^ b1[7] ^ b3[6],
              a2[6] ^ b1[6] ^ b3[5],
              a2[5] ^ b1[5] ^ b3[4],
              a2[4] ^ b1[4] ^ b3[3] ^ b3[7],
              a2[3] ^ b1[3] ^ b3[2] ^ b3[7],
              a2[2] ^ b1[2] ^ b3[1],
              a2[1] ^ b1[1] ^ b3[0] ^ b3[7],
              a2[0] ^ b1[0] ^ b3[7],
              a3[7] ^ b1[7] ^ b2[6],
              a3[6] ^ b1[6] ^ b2[5],
              a3[5] ^ b1[5] ^ b2[4],
              a3[4] ^ b1[4] ^ b2[3] ^ b2[7],
              a3[3] ^ b1[3] ^ b2[2] ^ b2[7],
              a3[2] ^ b1[2] ^ b2[1],
              a3[1] ^ b1[1] ^ b2[0] ^ b2[7],
              a3[0] ^ b1[0] ^ b2[7],
              a0[7] ^ b3[7] ^ b1[6],
              a0[6] ^ b3[6] ^ b1[5],
              a0[5] ^ b3[5] ^ b1[4],
              a0[4] ^ b3[4] ^ b1[3] ^ b1[7],
              a0[3] ^ b3[3] ^ b1[2] ^ b1[7],
              a0[2] ^ b3[2] ^ b1[1],
              a0[1] ^ b3[1] ^ b1[0] ^ b1[7],
              a0[0] ^ b3[0] ^ b1[7],
              a1[7] ^ b3[7] ^ b0[6],
              a1[6] ^ b3[6] ^ b0[5],
              a1[5] ^ b3[5] ^ b0[4],
              a1[4] ^ b3[4] ^ b0[3] ^ b0[7],
              a1[3] ^ b3[3] ^ b0[2] ^ b0[7],
              a1[2] ^ b3[2] ^ b0[1],
              a1[1] ^ b3[1] ^ b0[0] ^ b0[7],
              a1[0] ^ b3[0] ^ b0[7]};
endmodule

//加密核
module EncCore(di, ki, Rrg, do, ko);//参数依次为128位明文、轮密钥、当前加密轮数、下一轮状态矩阵、下一轮轮密钥
  input  [127:0] di;//当前状态矩阵
  input  [127:0] ki;//当前轮密钥
  input  [9:0]   Rrg;//当前加密轮数
  output [127:0] do;//下一轮状态矩阵
  output [127:0] ko;//下一轮轮密钥
  
  wire   [127:0] sb, sr, mx;//中间值,依次保存状态矩阵字节代换、行移位、列混合后的结果
  wire   [31:0]  so;//中间值,保存密钥扩展中函数T行移位与字节代换后的结果
 
  //加密流程为:S和字节代换,行移位,列混合,轮密钥加
  SubBytes SB3 (di[127:96], sb[127:96]);
  SubBytes SB2 (di[ 95:64], sb[ 95:64]);
  SubBytes SB1 (di[ 63:32], sb[ 63:32]);
  SubBytes SB0 (di[ 31: 0], sb[ 31: 0]);//sb保存字节代换后的结果
  
  assign sr = {sb[127:120], sb[ 87: 80], sb[ 47: 40], sb[  7:  0],
               sb[ 95: 88], sb[ 55: 48], sb[ 15:  8], sb[103: 96],
               sb[ 63: 56], sb[ 23: 16], sb[111:104], sb[ 71: 64],
               sb[ 31: 24], sb[119:112], sb[ 79: 72], sb[ 39: 32]};//sr保存行移位后的结果
               
  MixColumns MX3 (sr[127:96], mx[127:96]);
  MixColumns MX2 (sr[ 95:64], mx[ 95:64]);
  MixColumns MX1 (sr[ 63:32], mx[ 63:32]);
  MixColumns MX0 (sr[ 31: 0], mx[ 31: 0]);//mx保存列混合后的结果
  
  assign do = ((Rrg[0] == 1)? sr: mx) ^ ki;//判断是否为第10轮,若是,则跳过列混合使用sr轮密钥加,否则使用mx轮密钥加
  //以上过程完成一轮加密获得下一轮状态矩阵do
  
  function [7:0] rcon;//生成密钥扩展中的T函数中的rcon[j]
  input [9:0] x;//x对应当前加密轮数
    casex (x)
      10'bxxxxxxxxx1: rcon = 8'h01;
      10'bxxxxxxxx1x: rcon = 8'h02;
      10'bxxxxxxx1xx: rcon = 8'h04;
      10'bxxxxxx1xxx: rcon = 8'h08;
      10'bxxxxx1xxxx: rcon = 8'h10;
      10'bxxxx1xxxxx: rcon = 8'h20;
      10'bxxx1xxxxxx: rcon = 8'h40;
      10'bxx1xxxxxxx: rcon = 8'h80;
      10'bx1xxxxxxxx: rcon = 8'h1b;
      10'b1xxxxxxxxx: rcon = 8'h36;
    endcase
  endfunction
  
  SubBytes SBK ({ki[23:16], ki[15:8], ki[7:0], ki[31:24]}, so);//字循环后S盒字节代换,结果保存在so中
  
  assign ko[127:96] = ki[127:96] ^ {so[31:24] ^ rcon(Rrg), so[23: 0]};//对于W[4i]的扩展
  assign ko[ 95:64] = ki[ 95:64] ^ ko[127:96];//W[4i+1],W[4i+2],w[4i+3]
  assign ko[ 63:32] = ki[ 63:32] ^ ko[ 95:64];
  assign ko[ 31: 0] = ki[ 31: 0] ^ ko[ 63:32];
  //以上过程生成下一轮加密的轮密钥
endmodule

//AES加密
module AES_ENC(Din, Key, Dout, Drdy, Krdy, RSTn, EN, CLK, BSY, Dvld);
  input  [127:0] Din;  // Data input,128位明文
  input  [127:0] Key;  // Key input,128位密钥
  output [127:0] Dout; // Data output,128位密文
  
  input  Drdy;         // Data input ready
  input  Krdy;         // Key input ready
  input  RSTn;         // Reset (Low active)
  input  EN;           // AES circuit enable
  input  CLK;          // System clock
  output BSY;          // Busy signal
  output Dvld;         // Data output valid
  
  reg  [127:0] Drg;    // Data register,当前状态矩阵
  reg  [127:0] Krg;    // Key register
  reg  [127:0] KrgX;   // Temporary key Register,当前轮密钥
  reg  [9:0]   Rrg;    // Round counter,当前加密轮数,10位表示10轮加密
  reg  Dvldrg, BSYrg;
  wire [127:0] Dnext, Knext;//下一轮状态矩阵,下一轮轮密钥
  
  EncCore EC (Drg, KrgX, Rrg, Dnext, Knext);//参数依次当前状态矩阵、当前轮密钥、当前加密轮数、下一轮状态矩阵、下一轮轮密钥
  
  assign Dvld = Dvldrg;
  assign Dout = Drg;
  assign BSY  = BSYrg;
  
  always @(posedge CLK) begin//CLK上升沿触发
    if (RSTn == 0) begin//初始化
      Rrg    <= 10'b0000000001;//轮数为1
      Dvldrg <= 0;//无最终输出
      BSYrg  <= 0;//标志轮加密是否开始
    end//if (RSTn == 0)
    
    else if (EN == 1) begin
    
       //还未开始10轮加密的准备
       if (BSYrg == 0) begin
        //key input ready=1
        if (Krdy == 1) begin
          Krg    <= Key;//key register=初始密钥
          KrgX   <= Key;//初始轮密钥
          Dvldrg <= 0;//无最终输出
        end//if (Krdy == 1)
        //data input valid
        else if (Drdy == 1) begin
          Rrg    <= {Rrg[8:0], Rrg[9]};//轮数+1
          KrgX   <= Knext;
          Drg    <= Din ^ Krg;//初始时进行轮密钥加
          Dvldrg <= 0;
          BSYrg  <= 1;//置1,类似于flag,标志10轮加密开始
        end//else if (Drdy == 1)
      end//if (BSYrg == 0)
      
      //开始10轮加密
      else begin
        Drg <= Dnext;//输出的状态矩阵作为下一轮的输入
        if (Rrg[0] == 1) begin//如果是第10轮
          KrgX   <= Krg;//轮密钥变为初始密钥
          Dvldrg <= 1;//有最终输出,Dvld = Dvldrg,data output valid
          BSYrg  <= 0;//加密结束flag重置为0
        end//if (Rrg[0] == 1)
        else begin//第1~9轮
          Rrg    <= {Rrg[8:0], Rrg[9]};//轮数+1
          KrgX   <= Knext;//输出轮密钥作为下一轮的输入
        end
      end
      
    end//else if (EN == 1)
    
  end//always @(posedge CLK) begin
endmodule

AES_tb.v分析

在testbench.v文件中添加如下代码以生成波形仿真文件:

initial
begin            
    $dumpfile("wave.vcd");        //生成的vcd文件名称
    $dumpvars();    //tb模块名称
end 

iverilog与gtkwave仿真

ubuntu 16.04安装iverilog与gtkwave

在终端执行如下指令即可:

sudo apt-get install iverilog
sudo apt-get install gtkwave

编译与仿真

将AES.v与AES_tb.v置于同一目录下,在该目录下打开终端,依此执行下述指令:

iverilog AES.v AES_tb.v //在当前路径下编译生成生成a.out文件
./a.out //在当前路径下生成wave.vcd文件
gtkwave wave.vcd //使用gtkwave打开仿真波形

仿真波形如下(选中波形点击下方insert即可查看):

加密(so为密钥扩展中间值,sb为轮加密过程中S变换)
Verilog入门——AES实现_第2张图片

解密
Verilog入门——AES实现_第3张图片

你可能感兴趣的:(实验,硬件基础,verilog,密码学)