CHƯƠNG 1. TỔNG QUAN ĐỀ TÀI 1.1 Giới thiệu về hệ mật mã AES AES (viết tắt của từ tiếng anh: Advanced Encryption Standard, hay Tiêu chuẩn mã hóa nâng cao) là một thuật toán mã hóa khối được chính phủ Hoa Kỳ áp dụng làm tiêu chuẩn mã hóa. Thuật toán được xây dựng dựa trên Rijndael Cipher phát triển bởi 2 nhà mật mã học người Bỉ: Joan Daemen và Vincent Rijmen. AES làm việc với các khối dữ liệu 128bit và độ dài khóa 128bit, 192bit hoặc 256bit.
Các khóa mở rộng sử dụng trong chu trình được tạo ra bởi thủ tục sinh khóa Rijndael. Hầu hết các phép toán trong thuật toán AES đều thực hiện trong một trường hữu hạn của các byte. Mỗi khối dữ liệu 128 bit đầu vào được chia thành 16byte, có thể xếp thành 4 cột, mỗi cột 4 phần tử hay một ma trận 4x4 của các byte, gọi là ma trận State. Tùy thuộc vào độ dài của khóa khi sử dụng 128bit, 192bit hay 256bit mà thuật toán được thực hiện với số lần lặp khác nhau.2 Thuật toán mã hóa AES Tiêu chuẩn mã hóa nâng cao (AES-Advanced Encryption Standard) là mật mã khóa đối xứng và nó là mật mã khối lặp đi lặp lại với kích thước khối cố định là 128 bit và độ dài khóa thay đổi, tức là có thể là 128, 192 hoặc 256 bit.
Các phép biến đổi khác nhau hoạt động dựa trên các kết quả trung gian, được gọi là State. State là một mảng hình chữ nhật gồm các byte và vì kích thước khối là 128 bit, tức là 16 byte, nên mảng có kích thước 4x4. Khóa mật mã được mô tả tương tự như một mảng hình chữ nhật có bốn hàng. Số cột của khóa mật mã AES được 2 thay đổi theo độ dài khóa, với khóa 128 bit có số cột là 4, khóa 192 bit có 6 cột và khóa 256 bit có 8 cột.
Khóa sẽ thực hiện mở rộng khóa để tạo các khóa vòng, khóa có kích thước 128 bit có 10 vòng, khóa 192 có 12 vòng và khóa 256 thực hiện 14 vòng. Một dữ liệu đầu vào được mã hóa với một khóa cho trước thông qua các phép toán SubBytes, ShiftRows, MixColumns và AddRound Key tương ứng để tạo ra bản mã. Bản mã này cũng thực hiện các phép toán ngược InvSubBytes, InvShiftRows, InvMixColumn và AddRound Key để được bản dữ liệu ban đầu. Hình dưới đây mô tả cấu trúc của thuật toán AES.
Cấu trúc thuật toán mã AES 1.3 Mục tiêu đề tài Thực hiện mã hóa và giải mã một file dữ liệu sử dụng mật mã AES. Dữ liệu sau khi được thực hiện giải mã và mã hóa sẽ được lưu ra một file khác. Sử dụng ngôn ngữ lập trình java. 3 Thực hiện mã hóa và giải mã với 3 khóa có độ dài 128 bit, 192 bit và 256 bit.
Xác định thời gian mã hóa và giải mã. XÂY DỰNG CHƯƠNG TRÌNH 2.1 Ý tưởng bài toán Chương trình thực hiện đọc file dữ liệu, tiếp đó sử dụng thuật toán AES để mã hóa dữ liệu. Chương trình cho phép người dùng chọn file mã hóa, file ghi sau khi mã hóa, nhập khóa từ bàn phím và tính toán thời gian hoạt động của chương trình. Dữ liệu được mã hóa (giải mã) sẽ được lưu ra file người dùng lựa chọn.1 SubBytes Nhiều mật mã khối khác nhau sử dụng một phép thay thế đặc biệt được gọi là "S-box".
AES cũng có bảng S-box này, nó gọi là "Chuyển đổi SubBytes". Bảng S-box cung cấp một phép biến đổi có thể đảo ngược các phân đoạn của văn bản rõ trong quá trình mã hóa, với phép chuyển ngược lại trong quá trình giải mã. Với AES, nó là một hàm đơn giản được áp dụng lặp đi lặp lại cho mỗi byte trong các giai đoạn mã hóa, trả về một byte. Mỗi giá trị trong số 256 byte có thể có được chuyển đổi thành giá trị byte khác với phép biến đổi SubBytes, là một hoán vị đầy đủ, có nghĩa là mọi phần tử đều được thay đổi và tất cả 256 phần tử có thể được biểu diễn là kết quả của một sự thay đổi, sao cho không có hai phần tử khác byte được thay đổi thành byte tương tự.
Thực hiện SubBytes Chương trình thực hiện SubBytes: void SubBytes(char[] state) { for (int i = 0; i < 16; i++) { state[i] = sbox[state[i]]; } } Thực hiện SubBytes cho từng phần tử của mảng state qua bảng sbox ta được một mảng 4x4 mới.2 ShiftRows Trong hoạt động này, mỗi hàng của trạng thái được dịch chuyển theo chu kỳ sang trái, tùy thuộc vào chỉ số hàng là một hoán vị được thực hiện từng hàng trên mảng State, độc lập với khóa. Hàng thứ nhất được dịch sang trái 0 vị trí. 6 Hàng thứ 2 được dịch sang trái 1 vị trí. Hàng thứ 3 được dịch sang trái 2 vị trí.
Hàng thứ 4 được dịch sang trái 3 vị trí. Hàm ShiftRows Chương trình thực hiện của hàm ShiftRows void ShiftRows(char[] state) { char tmp[] = new char[16]; tmp[0] = state[0];//tmp theo cot tmp[1] = state[5]; tmp[2] = state[10]; tmp[3] = state[15]; tmp[4] = state[4]; 7 tmp[5] = state[9]; tmp[6] = state[14]; tmp[7] = state[3]; tmp[8] = state[8]; tmp[9] = state[13]; tmp[10] = state[2]; tmp[11] = state[7]; tmp[12] = state[12]; tmp[13] = state[1]; tmp[14] = state[6]; tmp[15] = state[11]; for (int i = 0; i < 16; i++) { state[i] = tmp[i]; } } Thực hiện dịch trái hàng thứ 2 một byte, hàng thứ 3 hai byte, hàng thứ 4 ba byte ta được các vị trí so với mảng state ban đầu.3 MixColumns Trong bước MixColumns, bốn byte của mỗi cột của trạng thái được kết hợp bằng cách sử dụng sự biến đổi. Hàm MixColumns lấy bốn byte làm đầu vào 8 và xuất ra bốn byte, trong đó mỗi byte đầu vào ảnh hưởng đến cả bốn byte đầu ra. Cùng với ShiftRows, MixColumns cung cấp sự khuếch tán trong mật mã.
Trong quá trình hoạt động này, mỗi cột được chuyển đổi bằng cách sử dụng một ma trận cố định (ma trận nhân với cột cho giá trị mới của cột trong state) Hình 1. Hàm MixColumns Chương trình thực hiện của hàm MixColumns void MixColumns(char[] state) { char[] tmp = new char[16]; tmp[0] = (char) (mul2[state[0]] ^ mul3[state[1]] ^ state[2] ^ state[3]); tmp[1] = (char) (state[0] ^ mul2[state[1]] ^ mul3[state[2]] ^ state[3]); tmp[2] = (char) (state[0] ^ state[1] ^ mul2[state[2]] ^ mul3[state[3]]); tmp[3] = (char) (mul3[state[0]] ^ state[1] ^ state[2] ^ mul2[state[3]]); 9 tmp[4] = (char) (mul2[state[4]] ^ mul3[state[5]] ^ state[6] ^ state[7]); tmp[5] = (char) (state[4] ^ mul2[state[5]] ^ mul3[state[6]] ^ state[7]); tmp[6] = (char) (state[4] ^ state[5] ^ mul2[state[6]] ^ mul3[state[7]]); tmp[7] = (char) (mul3[state[4]] ^ state[5] ^ state[6] ^ mul2[state[7]]); tmp[8] = (char) (mul2[state[8]] ^ mul3[state[9]] ^ state[10] ^ state[11]); tmp[9] = (char) (state[8] ^ mul2[state[9]] ^ mul3[state[10]] ^ state[11]); tmp[10] = (char) (state[8] ^ state[9] ^ mul2[state[10]] ^ mul3[state[11]]); tmp[11] = (char) (mul3[state[8]] ^ state[9] ^ state[10] ^ mul2[state[11]]); tmp[12] = (char) (mul2[state[12]] ^ mul3[state[13]] ^ state[14] ^ state[15]); tmp[13] = (char) (state[12] ^ mul2[state[13]] ^ mul3[state[14]] ^ state[15]); tmp[14] = (char) (state[12] ^ state[13] ^ mul2[state[14]] ^ mul3[state[15]]); tmp[15] = (char) (mul3[state[12]] ^ state[13] ^ state[14] ^ mul2[state[15]]); for (int i = 0; i < 16; i++) { state[i] = tmp[i]; } } 2.4 AddRoundKey Đối với khóa 128 bit hàm AddRoundKey được áp dụng từ vòng lặp thứ nhất tới vòng lặp thứ 10. Đối với khóa 192 bit hàm thực hiện từ vòng lặp thứ nhất 10 tới thứ 12. Còn đối với khóa 256 bit hàm thực hiện từ vòng lặp thứ nhất tới thứ 14.
Trong biến AddRoundKey(), một khóa vòng được cộng với state bằng một phép XOR theo từng bit đơn giản. Mỗi khóa vòng gồm có 4 từ (128 bit) được lấy từ lịch trình khóa. Bốn từ đó được cộng vào mỗi cột của state sao cho Hình 1. Hàm AddRoundKey Chương trình thực hiện của hàm AddRoundKey void AddRoundKey(char[] state, char[] roundKey) { for (int i = 0; i < 16; i++) { state[i] ^= roundKey[i]; } } 2.3 Các hàm giải mã Giải mã AES được thực hiện bằng cách sử dụng đảo ngược của các phép biến đổi, trong thứ tự thích hợp.1 InvSubBytes Hàm InvSubBytes là hàm ngược so với hàm SubByte.
Hàm này sử dụng bảng rsbox để chuyển đổi trạng thái. Chương trình thực hiện của hàm InvSubByte 11 void InvSubBytes(char[] state) { for (int i = 0; i < 16; i++) { state[i] = rsbox[state[i]]; } } 2.2 InvShiftRows Hàm InvShiftRow là hàm ngược của hàm ShiftRows. Hàng đầu tiên của state được giữ nguyên, các hàng 2, 3, 4 của state được lần lượt dịch trái 3 byte, 2 byte và 1 byte. Chương trình thực hiện của hàm InvShiftRows void InvShiftRows(char[] state) { char tmp[] = new char[16]; tmp[0] = state[0];//tmp theo cot tmp[1] = state[13]; tmp[2] = state[10]; tmp[3] = state[7]; tmp[4] = state[4]; tmp[5] = state[1]; tmp[6] = state[14]; tmp[7] = state[11]; 12 tmp[8] = state[8]; tmp[9] = state[5]; tmp[10] = state[2]; tmp[11] = state[15]; tmp[12] = state[12]; tmp[13] = state[9]; tmp[14] = state[6]; tmp[15] = state[3]; for (int i = 0; i < 16; i++) { state[i] = tmp[i]; } } 2.3 InvMixColumns Hàm InvMixColumns là hàm ngược của hàm MixColumns.
Chương trình thực hiện của hàm InvMixColumns void InvMixColumns(char[] state) { char[] tmp = new char[16]; tmp[0] = (char) (mulE[state[0]] ^ mulB[state[1]] ^ mulD[state[2]] ^ mul9[state[3]]); 13 tmp[1] = (char) (mul9[state[0]] ^ mulE[state[1]] ^ mulB[state[2]] ^ mulD[state[3]]); tmp[2] = (char) (mulD[state[0]] ^ mul9[state[1]] ^ mulE[state[2]] ^ mulB[state[3]]); tmp[3] = (char) (mulB[state[0]] ^ mulD[state[1]] ^ mul9[state[2]] ^ mulE[state[3]]); tmp[4] = (char) (mulE[state[4]] ^ mulB[state[5]] ^ mulD[state[6]] ^ mul9[state[7]]); tmp[5] = (char) (mul9[state[4]] ^ mulE[state[5]] ^ mulB[state[6]] ^ mulD[state[7]]); tmp[6] = (char) (mulD[state[4]] ^ mul9[state[5]] ^ mulE[state[6]] ^ mulB[state[7]]); tmp[7] = (char) (mulB[state[4]] ^ mulD[state[5]] ^ mul9[state[6]] ^ mulE[state[7]]); tmp[8] = (char) (mulE[state[8]] ^ mulB[state[9]] ^ mulD[state[10]] ^ mul9[state[11]]); tmp[9] = (char) (mul9[state[8]] ^ mulE[state[9]] ^ mulB[state[10]] ^ mulD[state[11]]); tmp[10] = (char) (mulD[state[8]] ^ mul9[state[9]] ^ mulE[state[10]] ^ mulB[state[11]]); 14 tmp[11] = (char) (mulB[state[8]] ^ mulD[state[9]] ^ mul9[state[10]] ^ mulE[state[11]]); tmp[12] = (char) (mulE[state[12]] ^ mulB[state[13]] ^ mulD[state[14]] ^ mul9[state[15]]); tmp[13] = (char) (mul9[state[12]] ^ mulE[state[13]] ^ mulB[state[14]] ^ mulD[state[15]]); tmp[14] = (char) (mulD[state[12]] ^ mul9[state[13]] ^ mulE[state[14]] ^ mulB[state[15]]); tmp[15] = (char) (mulB[state[12]] ^ mulD[state[13]] ^ mul9[state[14]] ^ mulE[state[15]]); for (int i = 0; i < 16; i++) { state[i] = tmp[i]; } } 2.4 AddRoundKey Hàm AddRoundKey do hàm này chỉ thực hiện hàm XOR nên bản thân nó cũng chính là đảo của chính nó. Chương trình thực hiện của hàm AddRoundKey void AddRoundKey(char[] state, char[] roundKey) { for (int i = 0; i < 16; i++) { state[i] ^= roundKey[i]; } 15 } 2.4 Chương trình thực hiện mã hóa và giải mã 2.1 Chương trình thực hiện mã hóa Trước tiên, chương trình thực hiện mở rộng khóa với hàm KeyExpansion(). Mảng expandedKey được dùng để lưu các khóa vòng được tạo ra từ hàm KeyExpansion(). Độ lớn của mảng phụ thuộc vào kích thước của khóa, đối với khóa 128 bit độ rộng của expandedKey là 176 byte, đối với khóa 192 bit là 208 byte, và khóa 256 bit là 240 byte.
Tiếp theo, chương trình thực hiện các hàm SubBytes, ShiftRows, MixColumns và AddRoundKey.