参考:https://blog.csdn.net/qq_28205153/article/details/55798628
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加密流程为:
AES解密流程为:
下面对加解密过程中涉及到的字节代换、行移位、列混合、轮密钥加操作进行讲解。
AES字节代换是一个简单的查表操作。AES定义了一个S盒与逆S盒(百度可查,不作展示),均为15×15的表格,表格中元素为1字节。字节代换通过S盒映射,逆字节代换通过逆S盒映射。
将状态矩阵中的元素(元素大小为1字节=8位)高4位作为行值,低4位作为列值,查找对应位置元素进行替换。
行移位:将状态矩阵中的第 i 行循环左移 i 字节。
逆行移位:将状态矩阵中的第 i 行循环右移 i 字节。
列混合通过矩阵相乘实现:新的状态矩阵=列混合矩阵×原本的状态矩阵。
逆列混合通过矩阵相乘实现:新的状态矩阵=逆列混合矩阵×原本的状态矩阵。
(其中逆列混合矩阵与列混合矩阵相乘恰好为单位矩阵。)
注:这里提到的乘法与加法都是定义在基于GF(2^8)上的二元运算,这里不作赘述。
将128位轮密钥Ki=W[4i],W[4i+1],W[4i+2],W[4i+3]与状态矩阵中的每一列数据进行逐位异或,如下图:
原始密钥为W[0],W[1],W[2],W[4],扩展至W[43]共11组密钥。W[i]扩展方法如下:
其中,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语法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
此处仅展示加密部分(有一些时序理解上的错误,待修订…)
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
在testbench.v文件中添加如下代码以生成波形仿真文件:
initial
begin
$dumpfile("wave.vcd"); //生成的vcd文件名称
$dumpvars(); //tb模块名称
end
在终端执行如下指令即可:
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即可查看):