Rcon[ i ] là một word xác định bởi [ 2i-1 ‘00’ ‘00’ ‘00’ ] với i là thứ tự của vòng sinh khóa ( i = 1,2,3,… )
i = 1 : Rcon = 01000000 i = 2 : Rcon = 02000000
i = 3 : Rcon = 04000000 i = 4 : Rcon = 08000000 i = 5 : Rcon = 10000000 i = 6 : Rcon = 20000000 i = 7 : Rcon = 40000000 i = 8 : Rcon = 80000000 i = 9 : Rcon = 1b000000 i = 10 : Rcon = 36000000 2.5. Mã hóa
Bắt đầu mã hóa, đầu vào sẽ được chuyển thành State như công thức trên. Sau khi, tiến hành cộng với Round Key đầu tiên, thực hiện biến đổi State theo vòng, số vòng thực hiện là 10, 12 hoặc 14 phụ thuộc vào độ dài của Key. Riêng vòng cuối cùng có một sự khác biệt so với các vòng trên đó là không thực hiện MixColumns(). Quá trình mã hóa được mô tả bằng đoạn chương trình sau :
Cipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) begin
byte state[4,Nb] state = in
AddRoundKey(state, w[0, Nb-1]) for round = 1 step 1 to Nr-1 SubBytes(state) ShiftRos(state) MixColumns(state) AddRoundKey(state, w[round*Nb,(round+1)*Nb-1]) end for SubBytes(state)
ShiftRows(state)
AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) out = state
end ---
Trong đoạn chương trình trên ta có nhận xét là: Ở vòng đầu tiên (vòng 0 ),bộ mã hóa chỉ thực hiện AddRoundKey( ) với khóa đầu tiên sau đó thực hiện luôn vòng 1. Từ vòng 1 đến vòng Nr-1, bộ mã hóa thực hiện đầy đủ 4 phép biến đổi: SubBytes( ), ShiftRows( ), MixColumns( ) và AddRoundKey( ). Vòng cuối cùng, bộ mã hóa chỉ thực hiện SubBytes( ), ShiftRows( ) và AddRoundKey( ) mà không thực hiện MixColumns().
2.6. Giải mã ( Inverse Cipher )
Quá trình giải mã cũng bao gồm Nr vòng như qua trình mã hóa, song nó sử dụng các phép biến đổi ngược, đó là: InverseSubBytes( ), InverseShiftRows( ), InverseMixColumns( ) và AddRoundKey( ). Quá trình này được mô tả bằng đoạn code sau :
InvCipher(byte in[4*Nb], byte out[4*Nb], word w[Nb*(Nr+1)]) begin
byte state[4,Nb] state = in
AddRoundKey(state, w[Nr*Nb, (Nr+1)*Nb-1]) for round = Nr-1 step -1 downto 1
InvShiftRows(state) InvSubBytes(state)
AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]) InvMixColumns(state)
end for
InvSubBytes(state)
AddRoundKey(state, w[0, Nb-1]) out = state
end
Cách làm trên đây thực hiện hoàn toàn ngược lại so với qua trình mã hóa. Đây là một thuật toán dễ dàng nhận ra nhất tuy nhiên nó không tận dụng được các đặc điểm của AES đó là tính chất khả nghịch của các phép biến đổi. Điều này cho phép tạo ra một thuật toán giải mã mà quá trình tiến hành hoàn toàn tương tự như quá trình mã hóa: thứ tự các phép biến đổi trong một vòng, các phép biến đổi tương ứng trong vòng, chỉ khác ở chỗ thay phép biến đổi thuận bằng phép biến đổi ngược.
Các đặc điểm sau cho phép thực hiện phương pháp giải mã này :
- Hai phép biến đổi SubBytes() và ShiftRows() giao tiếp với nhau; ta thấy rằng phép biến đổi SubBytes() theo ngay sau ShiftRows() cũng tương đương với việc ShiftRows() theo ngay sau SubBytes() Điều này cũng đúng với phép biến đổi ngược của chúng là InvSubBytes() và InvShiftRows.
- Hai phép biến đổi MixColumns() và InvMixColumns() là các phép biến đổi tuyến tính có nghĩa là :
InvMixColumns(state XOR Round Key) =
InvMixColumns(state) XOR InvMixColumns(Round Key). Kết quả là ta sẽ có một cách giải mã khác như sau:
EqInvCipher(byte in[4*Nb], byte out[4*Nb], word dw[Nb*(Nr+1)]) begin
byte state[4,Nb] state = in
AddRoundKey(state, dw[Nr*Nb, (Nr+1)*Nb-1]) for round = Nr-1 step -1 downto 1
InvSubBytes(state) InvShiftRows(state) InvMixColumns(state)
AddRoundKey(state, dw[round*Nb, (round+1)*Nb-1]) end for InvSubBytes(state) InvShiftRows(state) AddRoundKey(state, dw[0, Nb-1]) out = state end ---
Đối với quá trình giải mã này, đoạn code sau được thêm vào cuối của quá trình Key Expansion routine :
for i = 0 step 1 to (Nr+1)*Nb-1 dw[i] = w[i]
end for
for round = 1 step 1 to Nr-1
InvMixColumns(dw[round*Nb, (round+1)*Nb-1]) // note change of type end for
---
Một điểm chú ý là: vì InvMixColumns hoạt động trên một mảng byte 2 chiều trong khi RoundKey lại hoạt động trên một mảng các từ nên lời gọi InvMixColumn trong đoạn code này liên quan đến việc chuyển đổi kiểu mảng các byte khi đầu vào là mảng một chiều.
CHƯƠNG 3:
MÃ HÓA AES TRÊN NỀN FPGA 3.1. Sơ đồ tổng quan của hệ thống AES
3.1.1. Mô tả lưu đồ tổng quát của bộ mã hóa và giải mã AES
Hình 3.1.Sơ đồ khối tổng quát hệ thống AES
Trên sơ đồ trên ta thấy hệ thống AES có thể chia làm ba khối lớn. Đó là: Khối KeyExpasion, khối Data và khối điều khiển trung tâm CPU.
1. Khối KeyExpansion: Có nhiệm vụ tạo ra các từ khóa phát sinh từ khóa gốc thông qua quá trình sinh khóa.Các từ khóa sinh ra được lưu vào trong khối Key Storage.
2. Khối Data là khối chịu trách nhiệm chính trong quá trình mã hóa (giải mã). Nó quay vòng Data và kết hợp với các từ khóa trong quá trình sinh khóa.
3. Khối CPU điều khiển hoạt động của hai khối Data và khối
3.1.2. Sơ đồ thuật toán khối Data của bộ mã hóa
Hình 3.2.Sơ đồ thuật toán Khối data của bộ mã hóa
Theo tính chất của chu trình mã hóa thì ở vòng quay đấu tiên,không thực hiện biến đổi dữ liệu qua các khối SubByte, ShiftRow và MixColumn mà dữ liệu được đưa thẳng vào khối AddRoundKey để kết hợp với từ khóa gốc O_key.
Từ vòng thứ hai tới vòng quay thứ 9, thực hiện biến đổi dữ liệu qua đầy đủ các khối biến đổi: SubByte, ShiftRow, MixColumn và AddRoundKey. Cuối mỗi vòng này dữ liệu lại kết hợp với một từ khóa phái sinh S_Key tương ứng với số thứ tự của vòng. Vòng quay cuối cùng, dữ liệu sau khi qua các phép biến đổi SubByte và ShiftRow thì được đưa thẳng vào khối AddRoundKey để kết hợp vói từ khóa cuối cùng
mà không qua khối MixColumn. Dữ liệu ra của vòng này chính là dữ liệu đã được mã hóa.
Hình 3.3.Sơ đồ thuật toán Khối KeyExpansion
Không giống khối Data, khối KeyExpansion của bộ mã hóa và giải mã là hoàn toàn giống nhau. Điều này lý giải là do bộ mã hóa và giải mã sử dụng chung một tập từ khóa.
Từ khóa trong khối KeyExpansion sẽ được xử lí theo các từ 32 bit. Đối với bộ giải mã 128 bit khóa bộ giải mã sẽ thực hiện việc biến đổi 40 lần, mỗi lần biến đổi tạo ra một từ khóa con có độ dài 32 bit (Wi ). Đối với quá trình sinh khóa có ba phép biến đổi chính: SubWord, Rotword, Rcon. Đối với các lần biến đổi chia hết cho 4, Wi thực hiện biến đổi lần lượt qua các khối: SubWord, Rotword, Xor với Rcon và Xor với Wi- 3. Đối với các lần biến đổi còn lại, Wi chỉ thực hiện phép Xor với Wi-3. Cuối mỗi chu trình biến đổi, các từ khóa con được lưu trong vào khối Key Storage.
3.1.4. Sơ đồ thuật toán khối CPU
Khối CPU có chức năng điều khiển quá trính Sinh khóa và quá trình quay vòng dữ liệu. CPU nhận yêu cầu từ thiết bị ngoại vi ( Nhận dữ liệu từ máy tính để xử lí). Nếu dữ liệu là một từ chìa khóa, CPU sẽ đưa chân ra “key” lên mức cao đồng thời đưa chân ra “data” xuống mức thấp và bộ đếm “req_key_in” để điều khiển các vòng quay của khối KeyExpansion. Nếu là dữ liệu cần mã hóa. CPU sẽ đưa chân “data” lên mức cao đồng thời chân “key” xuống mức thấp và tạo bộ đếm “req_key_out” để điều khiển quá trình quay vòng data và quá trình xuất Key của khối Key Storage. Trong sơ đồ thuật toán dưới đây, ta thấy rõ quá trình xử lí của CPU là một vòng liên tục.
3.1.5. Sơ đồ thuật toán khối Data của bộ giải mã AES
Do tính chất khả nghịch của các phép biến đổi SubByte, ShiftRow, MixColumn và AddRoundKey như đã nói ở chương trước, ta sẽ có hai cách xây dựng bộ giải mã. Dưới đây là sơ đồ thuật toán của cả hai phương pháp đó.
Hình 3.4.Sơ đồ thuật toán khối CPU
Theo hai sơ đồ này ta có thể dễ dàng nhận ra, sơ đồ thứ nhất có thiết kế phức tạp và cồng kềnh hơn nhiều so với sơ đồ thứ hai (có lợi dụng tính chất đặc biết của các phép biến đổi ). Ngoài ra sơ đồ thứ hai có thiết kế tương tự như so đồ thuật toán của bộ mã hóa chỉ khác ở chỗ có thêm khối InverseMixColumn biến đổi S_Key trước khối AddRoundKey. Điều này sẽ khiến cho việc thực thi bộ giải mã hết sức đơn giản. Vì ta chỉ cần thay các khối SubByte, ShiftRow và MixColumn bằng InverseSubByte, InverseShiftRow và InverseMixColumn đồng thời thêm khối InverseMixColumn vào sau khối Key Storage là hoàn thành bộ giải mã.
Nhược điểm lớn nhất của phương pháp này chính là việc phải thêm khối InverseMixColumn, điều này làm tăng dung lượng của hệ thống. Tuy nhiên nó giảm thiểu được độ phức tạp trong điều khiển và công sức thiết kế.
Hình 3.5.Sơ đồ thuật toán khối giải mã - Dạng 1
3.2. Thiết kế chi tiết các khối chức năng của bộ mã hóa.3.2.1. Khối AddRoundKey 3.2.1. Khối AddRoundKey
AddRoundKey thực chất là một cổng XOR hai đầu vào 128 bít của dữ liệu và từ khóa.
Hoạt động của khối AddRoundKey được mô tả bằng đoạn code VHDL sau: process (data, key)
begin
d_out <= data xor key ; end process;
Hình 3.7.Sơ đồ thuật toán khối giải mã - Dạng 2
3.2.2. Khối SubByte
Như đã đề cập ở chương 3, đầu ra của khối SubByte là ánh xạ của đầu vào qua bảng S-box.
Hình 3.8. Khối SubByte
S-box là một bảng gồm 16 hàng và 16 cột tương ứng với 256 trường hợp đầu vào. Hoạt động của khối SubByte được mô tả bởi đoan code VHDL sau :
process (in_put) begin case in_put is when “00000000” => out_put <= “01100011”; when “00000001” => out_put <= “01111100”; … -- (253 trường hợp ) when “11111111” => out_put <= “00010110”; end process; 3.2.3. Khối ShiftRow
Khối ShiftRow có đầu vào 128 bit (127 downto 0) và đầu ra 128 bit (127 downto0).
Đầu vào và đầu ra của khối này được bố trí thành một bảng 4x3. Khối Demux sẽ thực hiện chia đầu vào thành bảng đầu vào và khối Mux sẽ biến đổi bảng đầu ra thành đầu ra. Ta tiến hành đổi chỗ các ô của bảng đầu vào để thu được bảng đâu ra như đã nêu trong phần lí thuyết ở chương II.
Hình 3.9.Khối ShiftRow
Chú ý: Trên hình, các đầu ra và đầu vào cùng tên sẽ được nối với nhau. Đoạn code VHDL sau sẽ mô tả hoạt động của hai khối Demux và Mux :
--Khối Demux: begin S00 <= in_put(7 downto 0); S01 <= in_put(15 downto 8); S02 <= in_put(23 downto 16); S03 <= in_put(31 downto 24); S10 <= in_put(39 downto 32); S11 <= in_put(47 downto 40); S12 <= in_put(55 downto 48); S13 <= in_put(63 downto 56);
S20 <= in_put(71 downto 64); S21 <= in_put(79 downto 72); S22 <= in_put(87 downto 80); S23 <= in_put(95 downto 88); S30 <= in_put(103 downto 96); S31 <= in_put(111 downto 104); S32 <= in_put(119 downto 112); S33 <= in_put(127 downto 120); end behavior ; -- Khối Mux begin
out_put <= S32 & S21 & S10 & S03 & S31 & S20 & S13 & S02 & S30 & S23 & S12
& S01 & S33 & S22 & S22 & S00 ; end behavior;
3.2.4. Khối MixColumn
Đây là khối có cấu tạo phức tạp nhất trong các khối chức năng của hệ thống AES. Sơ đồ khối của MixColumn như sau :
Hai khối Demux_4 và Mux_4 thực hiện tương tự như khối Demux và Mux trong khối ShiftRow ở trên. Các khối SubMixColumn lần lượt biến đổi các byte trong các cột tương ứng.
Việc thực hiện khối SubMixColum dựa trên các khối XOR_8 và khối Xtime. Khối XOR_8 thực hiện phép XOR với hai đầu vào 8 bit. Khối Xtime thực hiện phép nhân với x như đã mô tả trong chương II.
Hình 3.11.Khối Xtime
Code VHDL: process (d_in) begin
if d_in(7)='0' then
d_out<=d_in(6 downto 0) & '0'; else
d_out<=(d_in(6 downto 0) & '0') xor "00011011"; end if;
end process;
Sau đây là sơ đồ khối của Mix_Column :
Byte b0 của đầu ra được tính toán theo phương trình : b0 = ‘02’•a0 ⊕ ‘03’•a1 ⊕ ‘01’ • a2 ⊕ ‘01’•a3
Hình 3.12.Phép biến đổi theo dòng
Với các đầu ra khác như b1, b2, b3 , thực hiện tương tự, chỉ cần thay đổi thứ tự đầu vào, ta được các phép biến đổi “dòng” :
b1 = ‘01’•a0 ⊕ ‘02’•a1 ⊕ ‘03’ • a2 ⊕ ‘01’•a3 b2 = ‘01’•a0 ⊕ ‘01’•a1 ⊕ ‘02’ • a2 ⊕ ‘03’•a3 b3 = ‘03’•a0 ⊕ ‘01’•a1 ⊕ ‘01’ • a2 ⊕ ‘02’•a3
Kết hợp các phép biến đổi “dòng” trên ta có khối SubMixColumn.
3.4. Thiết kế các khối chức năng của bộ giải mã
Các khối chức năng của bộ giải mã có thể thực hiện một cách hoàn toàn tương tự như bộ mã hóa. Tuy nhiên khối InverseMixColumn thì thực hiện phức tạp hơn rất nhiều do phải thực hiện các phép nhân với các chỉ số rất lớn: Nhân với 09h, 0Bh, 0Dh, 0Eh thay vì các phép nhân 01, 02, 03 ở bộ mã hóa.
Hình 3.13.Khối SubMixColumn
3.4.1. Nhân với 09h
Phép nhân với 09h ( 9 = 8 + 1) thực hiện như sau :
Hình 3.14.Khối nhân 09h
3.4.2. Phép nhân với 0Bh
Phép nhân với 0Bh ( B = 8 + 2 + 1)thực hiện như sau :
3.4.2. Phép nhân với 0Dh
Phép nhân với 0Dh ( D = 8 + 4 + 1) thực hiện như sau :
Hình 3.16.Khối nhân 0Dh
3.4.3. Phép nhân với 0Eh
Phép nhân với 0Eh ( E = 8 + 4 + 2 ) thực hiện như sau :
Hình 3.17. Phép nhân 0Eh
Thực hiện tương tự như bộ mã hóa với các phương trình sau :
0, 0, 1, 2, 3, 1, 0, 1, 2, 3, 2, 0, 1, 2, 3, 3, 0, 1, 2, 3, '0 ' '0 ' '0 ' '09 ' '09 ' '0 ' '0 ' '0 ' '0 ' '09 ' '0 ' '0 ' '0 ' '0 ' '09 ' '0 ' c c c c c c c c c c c c c c c c c c c c b e a b a d a a b a e a b a d a b d a a e a b a b b a d a a e a = • ⊕ • ⊕ • ⊕ • = • ⊕ • ⊕ • ⊕ • = • ⊕ • ⊕ • ⊕ • = • ⊕ • ⊕ • ⊕ •
Kết quả cuối cùng là khối InverseMixColumn có kết cấu tương tự như MixColumn của bộ mã hóa :
Hình 3.18. Khối InverseMixColumn 3.4. Thiết kế chi tiết cho khối KeyExpansion
Sơ đồ thiết kế khối KeyExpansion trên VHDL :
Hình 3.19.Sơ đồ khối KeyExPansion
Chi tiết các khối như sau :
3.4.1. Khối RotWord
Khối RotWord được thực hiện đơn giản theo đoạn code VHDL sau:
d_out(7 downto 0) <= d_in(15 downto 8) ;
d_out(15 downto 8) <= d_in(23 downto 16) ;
d_out(23 downto 16) <= d_in(31 downto 24) ;
d_out(31 downto 24) <= d_in(7 downto 0) ;
end behavior ;
Hình 3.20.Khối RotWord
3.4.2. Khối SubWord
Khối SubWord chính là bốn khối SubByte ghép lại với nhau
Hình 3.21. Khối SubWord
3.4.3. Khối Rcon
Đoạn code VHDL sau thực hiện chức năng của khối Rcon : process (req_key_in) begin case req_key_in is when “1” => rcon_out <= “01000000” ; when “2” => rcon_out <= “02000000” ; when “3” => rcon_out <= “04000000” ; when “4” => rcon_out <= “08000000” ; when “5” => rcon_out <= “10000000” ;
when “6” => rcon_out <= “20000000” ; when “7” => rcon_out <= “40000000” ; when “8” => rcon_out <= “80000000” ; when “9” => rcon_out <= “1b000000” ; when “10” => rcon_out <= “36000000” ; when others => null ;
end case; end process;
Hình 3.22.Khối Rcon
3.4.4. Khối KeyStorage
Khối KeyStorage có chức năng lưu trữ từ khóa gốc và các tứ khóa phái sinh tạo ra. Đồng thời nó cũng có nhiệm vụ đưa ra các từ khóa thích hợp theo yêu cầu của bộ mã hóa hay giải mã.
Hình 3.23.Khối KeyStorage
Đoạn chương trình sau mô tả hoạt động của khối KeyStorage : key_process: process(clk,req_key_in)
begin
if clk’event and clk=’1’ then key0 <= O_key;
case req_key_out is
when “0010” => key2 <= S_key; …
when “1010” => key10 <= S_key;
when others => null ; end case;
end if; end process;
data_process: process (clk, mode,req_key_out) begin
if mode = ‘0’ then --Ma hoa
if clk’event and clk =’1’ then case req_key_out is
when “0001” => key_out <= key1 ;
when “0010” => key_out <= key2 ;
…
when “1010” => key_out <= key10 ;
when others => null ; end case;
end if;
else --Giai ma
if clk’event and clk =’1’ then case req_key_out is
when “0001” => key_out <= key10 ;
when “0010” => key_out <= key9 ;
…
when “1010” => key_out <= key1 ;
when others => null ; end case;