Với mong muốn được tìm hiểu về mã AES, nhóm thực hiện báo cáo với đề tài đề tài “Viết chương trình mã hóa và giải mã file dữ liệu bằng mật mã AES”.. Một dữ liệu đầu vào được mã hóa với m
Trang 1HỌC VIỆN KỸ THUẬT MẬT MÃ
KHOA CÔNG NGHỆ THÔNG TIN
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
BÀI TẬP MÔN HỌC CƠ SỞ AN TOÀN VÀ BẢO MẬT THÔNG TIN
VIẾT CHƯƠNG TRÌNH MÃ HÓA VÀ GIẢI MÃ FILE DỮ
Trang 2NHẬN XÉT VÀ CHO ĐIỂM CỦA GIÁO VIÊN
Trang 3
MỤC LỤ
Trang 4LỜI MỞ ĐẦU 1
CHƯƠNG 1 TỔNG QUAN ĐỀ TÀI 2
1.1 Giới thiệu về hệ mật mã AES 2
1.2 Thuật toán mã hóa AES 2
1.3 Mục tiêu đề tài 3
CHƯƠNG 2 XÂY DỰNG CHƯƠNG TRÌNH 4
2.1 Ý tưởng bài toán 4
2.2 Các hàm mã hóa 4
2.2.1 SubBytes 4
2.2.2 ShiftRows 5
2.2.3 MixColumns 7
2.2.4 AddRoundKey 9
2.3 Các hàm giải mã 10
2.3.1 InvSubBytes 10
2.3.2 InvShiftRowss 11
2.3.3 InvMixColumn 12
2.3.4 AddRoundKey 14
2.4 Chương trình thực hiện mã hóa và giải mã 15
2.4.1 Chương trình thực hiện mã hóa 15
2.4.2 Chương trình thực hiện giải mã 17
CHƯƠNG 3 KẾT QUẢ THỰC NGHIỆM 20
3.1 Thực nghiệm mã hóa với khóa 128 bit 20
3.2 Thực nghiệm mã hóa với khóa 192 bit 21
3.3 Thực nghiệm mã hóa với khóa 256 bit 22
PHỤ LỤC 24
Trang 6LỜI MỞ ĐẦU
Ngày nay, với sự phát triển mạnh mẽ của công nghệ thông tin, các nềntảng kỹ thuật số, áp dụng trong công việc học tập càng trở lên phổ biến, đặc biệtkhi đại dịch covid vẫn diễn ra phức tạp trên khắp thế giới, nhiều địa phương đưa
ra các lệnh giãn cách Việc sử dụng các phương tiện truyền thông của người dùngcàng đòi hỏi yêu cầu cao hơn về độ an toàn bảo mật thông tin
Nhiều hệ mã đã được tạo ra nhằm che giấu thông tin, bảo mật thông tin ngườidùng Mã hóa AES (Advanced Encryption Standard) tuy được phát triển từ cuốinhững năm 90s nhưng AES vẫn thực hiện tốt chức năng mã hóa, được áp dụnglàm tiêu chuẩn mã hóa
Với mong muốn được tìm hiểu về mã AES, nhóm thực hiện báo cáo với
đề tài đề tài “Viết chương trình mã hóa và giải mã file dữ liệu bằng mật mã AES” Với mục tiêu trên, báo cáo sẽ được trình bày gồm các chương và bố cục
sau:
Chương 1: Tổng quan về đề tài
Chương 2: Xây dựng chương trình
Chương 3: Kết quả thực nghiệm
Tuy nhiên, do thời gian thực hiện báo cáo môn học có hạn và kiến thứccòn nhiều hạn chế, nên đề tài vẫn còn rất nhiều những thiếu sót, điểm bất cập vàcác vấn đề chưa thể xử lý triệt để Nhóm em rất mong nhận được sự góp ý củathầy và các bạn để báo cáo hoàn thiện hơn Nhóm em xin chân thành cảm ơn!
Trang 7CHƯƠ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êuchuẩ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ỳ ápdụ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
1.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épbiế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
Trang 8thay đổ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ựchiệ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ôngqua 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ượcInvSubBytes, 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.
Hình 1 1 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 filekhác
Sử dụng ngôn ngữ lập trình java
Trang 9 Thực hiện mã hóa và giải mã với 3 khóa có độ dài 128 bit, 192 bit và 256bit.
Xác định thời gian mã hóa và giải mã
Trang 10CHƯƠNG 2 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 ghisau 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ủachương trình Dữ liệu được mã hóa (giải mã) sẽ được lưu ra file người dùng lựachọn
2.2 Các hàm mã hóa
2.2.1 SubBytes
Nhiều mật mã khối khác nhau sử dụng một phép thay thế đặc biệt đượcgọ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ănbả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 trongcá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ácbyte được thay đổi thành byte tương tự
Trang 11Hình 1 2 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++) {
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àngtrê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í
Trang 12 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ình 1 3 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];
Trang 13Thự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
2.2.3 MixColumns
Trong bước MixColumns, bốn byte của mỗi cột của trạng thái được kếthợ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
Trang 14và 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 trongstate)
Hình 1 4 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]]);
Trang 15tmp[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++) {
Trang 16tớ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ộtphé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 5 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++) {
Trang 17void InvSubBytes(char[] state) {
for (int i = 0; i < 16; i++) {
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
Trang 18Hà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]]);
Trang 19tmp[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]]);
Trang 20tmp[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++) {
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];
}
Trang 21}
2.4 Chương trình thực hiện mã hóa và giải mã
2.4.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àmKeyExpansion() 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 Mỗi khóa có độ dài khác nhau có số vòng lặpthực hiện là khác nhau Khóa 128 bit thực hiện 10 vòng lặp, khóa 192 thực hiện
12 vòng lặp và khóa 256 thực hiện 14 vòng lặp
char[] AES_Encrypt(char[] message, char[] key, int lengthKey) {
char[] state = new char[16];
for (int i = 0; i < 16; i++) {
state[i] = (char) message[i];
}
int numberOfRounds = 0;
switch (lengthKey) {
case 128:
Trang 22char[] expandedKey = new char[(numberOfRounds + 2) * 16];
KeyExpansion(key, expandedKey, lengthKey);
Trang 232.4.2 Chương trình thực hiện giải mã
Chương trình thực hiện giải mã đọc dữ liệu đã được mã hóa từ file dữ liệucùng với khóa được nhập từ người dùng để giải mã ra bản dữ liệu ban đầu.Chương trình thực hiện giải mã là hàm ngược của chương trình thực hiện mã hóa char[] AES_Decrypt(char[] cipher, char[] key, int lengthKey) {
char[] state = new char[16];
for (int i = 0; i < 16; i++) {
state[i] = (char) cipher[i];
Trang 24// System.out.println("So vong :" + numberOfRounds);
char[] expandedKey = new char[(numberOfRounds + 2) * 16];
KeyExpansion(key, expandedKey, lengthKey);
InvMixColumns(state);
}
//final round
Trang 25InvShiftRows(state);
InvSubBytes(state);
AddRoundKey(state, Arrays.copyOfRange(expandedKey, 0, 16)); for (int i = 0; i < 16; i++) {
cipher[i] = state[i];
}
return cipher;
}
Trang 26CHƯƠNG 3 KẾT QUẢ THỰC NGHIỆM
3.1 Thực nghiệm mã hóa với khóa 128 bit
Thực hiện mã hóa file Plain.txt có nội dung: “Nhom 23 su dung giai thuatAES de ma hoa”
Hình 3 1 File mã hóa với khóa 128 bit
Thực hiện với khóa 128 bit: 0102030405060708090a0b0c0d0e0f10 và lựa chọn lưu ra file Cipher.txt
Trang 27Hình 3 2 Giao diện mã hóa khóa 128 bit
Sau khi mã hóa dữ liệu được mã hóa lưu ra file Cipher.txt dưới dạng mã hex
Hình 3 3 File lưu dữ liệu sau khi mã hóa khóa 128 bit
Trang 28 Giải mã
Thực hiện giải mã với file Cipher.txt với khóa 128 bit:
0102030405060708090a0b0c0d0e0f10 và lưu dữ liệu sau khi giải mã ra file PlainTest.txt
Hình 3 4 Giao diện giải mã khóa 128 bit
Dữ liệu sau khi được giải mã được lưu ở file PlainTest.txt trùng với dữ liệu ban đầu ở file Plain.txt
Trang 29Hình 3 5 File lưu dữ liệu sau khi giải mã khóa 128 bit
3.2 Thực nghiệm mã hóa với khóa 192 bit
Thực hiện mã hóa file Plain.txt có nội dung: “Nhom 23 su dung giai thuat AES de
ma hoa”
Hình 3 6 File mã hóa với khóa 192 bit
Thực hiện với khóa 192 bit:
0102030405060708090a0b0c0d0e0f101111111111111111 và lựa chọn lưu ra file Cipher.txt:
Trang 30Hình 3 7 Giao diện mã hóa khóa 192 bit
Sau khi mã hóa dữ liệu được mã hóa lưu ra file Cipher.txt dưới dạng mã hex:
Trang 31Hình 3 8 File lưu dữ liệu sau khi mã hóa khóa 192 bit
Giải mã
Thực hiện giải mã với file Cipher.txt với khóa 192 bit:
0102030405060708090a0b0c0d0e0f101111111111111111 và lưu dữ liệu sau khi giải mã ra file PlainTest.txt
Trang 32Hình 3 9 Giao diện giải mã khóa 192 bit
Dữ liệu sau khi được giải mã được lưu ở file PlainTest.txt trùng với dữ liệu banđầu ở file Plain.txt
Trang 33Hình 3 10 File lưu dữ liệu sau khi giải mã khóa 192 bit
3.3 Thực nghiệm mã hóa với khóa 256 bit
Thực hiện mã hóa file Plain.txt có nội dung: “Nhom 23 su dung giai thuat AES de
ma hoa”
Hình 3 11 File mã hóa với khóa 256 bit
Thực hiện với khóa 256 bit:
0102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f10 và lựa chọn lưu ra file Cipher.txt:
Trang 34Hình 3 12 Giao diện mã hóa khóa 256 bit
Sau khi mã hóa dữ liệu được mã hóa lưu ra file Cipher.txt dưới dạng mã hex:
Trang 35Hình 3 13 File lưu dữ liệu sau khi mã hóa khóa 256 bit
Giải mã
Thực hiện giải mã với file Cipher.txt với khóa 256 bit:
0102030405060708090a0b0c0d0e0f100102030405060708090a0b0c0d0e0f10 và lưu dữ liệu sau khi giải mã ra file PlainTest.txt
Trang 36Hình 3 14 Giao diện giải mã khóa 256 bit
Dữ liệu sau khi được giải mã được lưu ở file PlainTest.txt trùng với dữ liệu ban đầu ở file Plain.txt
Trang 37Hình 3 15 File lưu dữ liệu sau khi giải mã khóa 256 bit
Trang 38PHỤ LỤC Chương trình mã hóa AES
public class EncryptMerge {
char[] sbox = {//256 phan tu
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
Trang 390x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
char[] mul2 = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
Trang 400x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8,0xfa, 0xfc, 0xfe,
0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,