Bài báo này giới thiệu tập lệnh hợp ngữ trong một số dòng vi xử lý Intel thế hệ mới cho phép tăng đáng kể tốc độ mã hóa, giải mã với thuật toán AES. Các tác giả sẽ làm rõ những điểm đặc biệt khi sử dụng một trong số các lệnh đó để mở rộng khóa; đây là vấn đề chưa được trình bày trong các tài liệu về tập lệnh này. Mời các bạn cùng tham khảo!
Trang 1Hiệu Năng Mã Hóa Với Tập Lệnh AES-NI
Nguyễn Tuấn Anh#, Lương Thế Dũng#, Nguyễn Thị Trang*
#Khoa An toàn thông tin – Học viện Kỹ thuật mật mã
*Khoa Công nghệ thông tin – Học viện Công nghệ bưu chính viễn thông Email: tuananh1982act@gmail.com, thedungluong@gmail.com, trangmamcnttptit11@gmail.com
Abstract— Bài báo này giới thiệu tập lệnh hợp ngữ trong một số
dòng vi xử lý Intel thế hệ mới cho phép tăng đáng kể tốc độ mã
hóa, giải mã với thuật toán AES Các tác giả sẽ làm rõ những
điểm đặc biệt khi sử dụng một trong số các lệnh đó để mở rộng
khóa; đây là vấn đề chưa được trình bày trong các tài liệu về tập
lệnh này Đồng thời, bài báo cũng giới thiệu kết quả thực nghiệm
về tốc độ mã hóa, giải mã mà các tác giả đã đạt được khi nghiên
cứu tập lệnh nói trên Một trong những kết quả quan trọng mà
các tác giả thu được là sự chênh lệch không đáng kể về tốc độ mã
hóa, giải mã khi sử dụng tập lệnh nói trên để viết chương trình
cho nền tảng 32 bit và nền tảng 64 bit
Keywords- AES-NI, cứng hóa AES, tăng tốc mã hóa
I GIỚI THIỆU Như đã biết, mật mã là công cụ quan trọng hàng đầu trong
lĩnh vực an toàn thông tin Nếu xét riêng lĩnh vực công nghệ
thông tin và viễn thông thì nhiệm vụ đảm bảo an toàn thông tin
sẽ không thể đạt được nếu không có mật mã Tuy nhiên, việc
áp dụng các thao tác mật mã vào quá trình xử lý thông tin sẽ
làm chậm đáng kể quá trình này Do vậy, bên cạnh việc nghiên
cứu và xây dựng những hệ mật tốt thì việc nghiên cứu các giải
pháp cải thiện hiệu năng làm việc của các hệ mật cũng có ý
nghĩa to lớn trong an toàn thông tin
Vào ngày 02/01/1997, Viện tiêu chuẩn và kỹ thuật quốc gia
Mỹ (NIST) đã khởi động chương trình xây dựng chuẩn mật mã
mới để thay thế cho chuẩn mật mã lúc bấy giờ là DES [1]
Trong đó, NIST xác định việc xây dựng chuẩn mật mã mới sẽ
dựa vào công sức của cộng đồng quốc tế thông qua việc tổ
chức cuộc thi để tìm ra thuật toán mật mã tốt nhất Đồng thời,
NIST cũng đặt ra yêu cầu bắt buộc đối với các ứng viên là
thuật toán của họ sẽ được miễn phí cho mọi người dùng nếu
được chọn làm chuẩn Đến ngày 02/10/2000, NIST công bố
thuật toán Rijndael được chọn làm chuẩn mật mã mới, gọi là
AES (Advanced Encryption Standard); chuẩn này được ban
hành chính thức bởi NIST vào năm 2001 [2] Đến nay, AES đã
được hỗ trợ bởi hầu hết các sản phẩm có chức năng mật mã
Mặc dù AES được cho là có hiệu năng thực thi cao cả khi
cái đặt bằng phần mềm và phần cứng, nhưng dù sao thì tốc độ
mã hóa/giải mã bằng phần mềm còn kém nhiều so với các phần
cứng chuyên dụng Tuy vậy, phần cứng mật mã chuyên dụng
lại đắt đỏ và kém linh hoạt hơn hẳn so với phần mềm Vào năm
2008, hãng sản xuất vi xử lý Intel đã đưa ra giải pháp cho phép
dung hòa ưu, nhược điểm của cài đặt cứng và cài đặt mềm đối
với AES, đó là tập lệnh AES-NI (AES New Instructions) bao
gồm 6 lệnh hợp ngữ được hỗ trợ bởi một số dòng vi xử lý mới
của Intel và AMD Bằng việc sử dụng tập lệnh này, người ta có
thể viết những chương trình mã hóa/giải mã bằng AES với tốc
độ cao hơn hẳn so với cài đặt mềm thông thường Đến nay đã
có nhiều ứng dụng và thư viện mật mã có khả năng làm việc với tập lệnh này Danh sách cụ thể các ứng dụng và thư viện đó
có thể tham khảo tại [3]
II TẬP LỆNH AES-NI Tập lệnh AES-NI bao gồm 6 lệnh hợp ngữ, trong đó có 2 lệnh để mã hóa, 2 lệnh để giải mã và 2 lệnh để tạo khóa vòng Hai lệnh để mã hóa là AESENC và AESENCLAST Trong đó lệnh AESENCLAST là để mã hóa vòng cuối cùng, lệnh AESENC là để mã hóa một vòng đối với tất các vòng còn lại Tương tự, hai lệnh để giải mã là AESDEC và AESDECLAST Trong đó, lệnh AESDECLAST thực hiện giải mã vòng cuối cùng, còn lệnh AESDEC thực hiện giải mã một vòng đối với tất cả các vòng còn lại Hai lệnh để tạo khóa vòng là AESKEYGENASSIST và AESIMC Trong đó, AESKEYGENASSIST được sử dụng để tạo khóa vòng mã hóa, tức là để mở rộng khóa (key expansion), còn AESIMC được sử dụng để tạo khóa giải mã AES hỗ trợ hai phương án giải mã Phương án thứ nhất là trong từng vòng phải đảo trật tự các phép biến đổi SubBytes, ShiftRow, MixColumn, AddRoundKey Trong trường hợp này, khóa giải mã cũng chính là khóa giải mã (nhưng dùng với trật tự đảo ngược) Phương án thứ hai là giữ nguyên trật tự các phép biến đổi trên trong từng vòng, nhưng bên cạnh việc sử dụng khóa vòng với trật tự đảo ngược thì cần thực hiện biến đổi nhất định lên khóa vòng mã hóa để thu được khóa vòng giải mã Phép biến đổi khóa vòng này chính là được thực hiện bởi lệnh AESIMC Bên cạnh tập lệnh trên đây, Intel cũng đưa vào lệnh PCLMULQDQ (Carry-Less Multiplication) cho phép thực hiện phép nhân trên trường hữu hạn đối với các hạng tử 64 bit Lệnh này được sử dụng để cài đặt một cách hiệu quả thuật toán AES ở chế độ Galois Counter Mode (AES-GCM) [4]
Cú pháp cũng như chức năng của các lệnh AES-NI được trình bày trong tài liệu [5] của Intel Tuy nhiên nếu cách thức
sử dụng các lệnh mã hóa, giải mã là đơn giản, rõ ràng thì lệnh tạo khóa vòng AESKEYGENASSIST lại khá rối rắm, khó hiểu Có lẽ người lập trình sẽ mong đợi rằng mỗi lần gọi lệnh AESKEYGENASSIST thì sẽ thu được một khóa vòng, tức là
nó có tính trọn vẹn như các lệnh còn lại Tuy nhiên thực tế không như vậy Dù rằng kích thước giá trị đầu ra của lệnh trên
là 128 bit nhưng để tạo được một khóa vòng 128 bit thì cần gọi lệnh trên và sau đó là một loạt lệnh khác nữa Trong tài liệu [5], Intel chỉ đưa ra đoạn mã để thực hiện sinh khóa vòng mà hoàn toàn không giải thích bản chất của chúng; cũng như không đề cập đến việc có thể sử dụng một bộ lệnh khác (sau
Trang 2lệnh AESKEYGENASSIST) để đạt được cùng mục đích là
sinh khóa vòng Ví dụ, dựa trên mã nguồn của CyaSSL [6],
chúng tôi đã sử dụng một bộ 10 lệnh dưới đây để thay cho bộ
20 lệnh mà Intel đề xuất trong [5]:
aeskeygenassist xmm1, xmm2, 01h
pshufd xmm1, xmm1, 0FFh
movdqu xmm3, xmm2
pslldq xmm3, 4
pxor xmm2, xmm3
pslldq xmm3, 4
pxor xmm2, xmm3
pslldq xmm3, 4
pxor xmm2, xmm3
pxor xmm2, xmm1
Chức năng của lệnh AESKEYGENASSIST được Intel giải
thích trong [5] bằng đoạn giả mã như sau:
AESKEYGENASSIST xmm1, xmm2/m128, imm8
Tmp := xmm2/LOAD(m128)
X3[31-0] := Tmp[127-96];
X2[31-0] := Tmp[95-64];
X1[31-0] := Tmp[63-32];
X0[31-0] := Tmp[31-0];
RCON[7-0] := imm8;
xmm1 := [Rot (SubWord (X3)) RCON, SubWord
(X3), Rot (SubWord (X1)) RCON,
SubWord (X1)]
Theo đó, nếu biểu diễn 128 bit đầu vào (xmm2) dưới dạng
bộ 4 từ 32 bit (w0, w1, w2, w3) thì đầu ra (xmm1) sẽ có dạng
(w4, w5, w6, w7) Trong khi đó, theo yêu cầu của AES thì
khóa vòng tương ứng phải có dạng (w4w0, w4w0w1,
w4w0w1w2, w4w0w1w2w3) Như vậy, để thu
được khóa vòng cần thiết thì sau khi gọi lệnh
AESKEYGENASSIST cần phải thực hiện thêm các lệnh khác
để đưa đầu ra về dạng mong đợi
- Lệnh pshufd đưa xmm1 về dạng (w4, w4, w4, w4)
- Cặp lệnh (pslldq, pxor) thứ nhất đưa xmm2 về dạng (w0,
w0w1, w1w2, w2w3)
- Cặp lệnh (pslldq, pxor) thứ hai đưa xmm2 về dạng (w0,
w0w1, w0w1w2, w1w2w3)
- Cặp lệnh (pslldq, pxor) thứ ba đưa xmm2 về dạng (w0,
w0w1, w0w1w2, w0w1w2w3)
- Lệnh pxor cuối cùng đưa xmm2 về dạng (w4w0,
w4w0w1, w4w0w1w2, w4w0w1w2 w3) Và
đây chính là khóa vòng cần có
Câu hỏi đặt ra là tại sao Intel không thiết kế lệnh
AESKEYGENASSIST để nó thực hiện tất cả các thao tác trên
đây? Có lẽ là vì AES hỗ trợ 3 kích thước khóa khác nhau, và
thủ tục mở rộng khóa có sự khác nhau nhất định cho ba kích
thước khóa này Mặt khác, người ta chỉ phải thực hiện duy nhất
một lần mở rộng khóa cho mỗi phiên mã hóa/giải mã, do đó tốc
độ thực thi mở rộng khóa không thực sự quan trọng
III HIỆU NĂNG MÃ HÓA, GIẢI MÃ
Để đánh giá hiệu năng mã hóa, giải mã khi sử dụng tập lệnh AES-NI, chúng tôi viết chương trình mã hóa, giải mã sử dụng tập lệnh này với hai phiên bản khác nhau: một cho nền tảng 32 bit và một cho nền tảng 64 bit Cả hai phiên bản này đều thực hiện mã hóa, giải mã theo chế độ ECB với AES-128 Nguyên mẫu hàm mã hóa cho cả hai phiên bản có dạng:
void aes128_encrypt_ecb(unsigned char* buf, unsigned char *expanded_key, int block_num) Trong đó tham số buf trỏ đến vùng đệm chứa dữ liệu cần
mã hóa, bản mã sẽ được ghi lên chính vùng đệm này; tham số expanded _key trỏ đến các khóa vòng mã hóa; và tham số block_num cho biết kích thước dữ liệu tính theo khối (16 bytes) Hàm mã hóa cũng có cú pháp hoàn toàn tương tự
Sở dĩ cần viết chương trình với hai phiên bản 32 bit và 64 bit là vì lý do như sau Các lệnh AES-NI chủ yếu được thực hiện trên các thanh ghi XMM 128 bit Khi viết chương trình cho nền tảng 64 bit, người lập trình có thể sử dụng 16 thanh ghi như vậy (XMM0-XMM15) Trong trường hợp đó, có thể nạp sẵn tất cả các khóa vòng vào các thanh ghi này, sau đó các khối được mã hóa/giải mã bằng khóa đã chứa sẵn trong các thanh ghi; tức là cho dù có bao nhiêu khối dữ liệu trong vùng đệm đi nữa thì cũng chỉ phải thực hiện duy nhất một lần việc nạp khóa vòng từ bộ nhớ vào thanh ghi Điều này giúp giảm thiểu thời gian truy xuất khóa vòng Trong trường hợp viết chương trình cho nền tảng 32 bit, chỉ có 8 trong số 16 thanh ghi (XMM0-XMM7) là có thể sử dụng được Do đó, chỉ có thể nạp sẵn một phần khóa vòng; các khóa còn lại phải được nạp từ bộ nhớ mỗi khi cần sử dụng để mã hóa các khối
Trong phần này chúng tôi cũng sử dụng một chương trình cài đặt AES bằng ngôn ngữ C++ đã được tối ưu hóa và không
sử dụng AES-NI để so sánh hiệu năng với chương trình sử dụng AES-NI nói trên Việc thử nghiệm được tiến hành trên máy có cấu hình: Intel Core i5-3210M 2,5GHz, RAM 4GB, Windows 7 64-bit.Kết quả thử nghiệm mã hóa 10 GB dữ liệu với các kích thước vùng đệm khác nhau được thể hiện trên Hình 1 Trong đó, trục hoành là kích thước của vùng đệm tính bằng số khối, mỗi khối 16 bytes; trục tung là tốc độ mã hóa tính bằng MB/s
Hình 1 Tốc độ mã hóa bằng AES
Có thể dễ dàng nhận thấy chương trình mã hóa sử dụng tập lệnh AES-NI cho tốc độ cao hơn hẳn so với chương trình mã hóa không sử dụng tập lệnh này Cụ thể, chương trình mã hóa không sử dụng tập lệnh AES-NI đạt được tốc độ 155 MB/s,
Trang 3trong khi chương trình mã hóa sử dụng tập lệnh AES-NI đạt
được tốc độ 2040 MB/s cho phiên bản 32 bit và tốc độ 2120
MB/s cho phiên bản 64 bit
Mặt khác, kết quả thử nghiệm cho thấy sự chênh lệch tốc
độ mã hóa giữa phiên bản 32 bit và phiên bản 64 bit không
như dự kiến Trước khi thử nghiệm, chúng tôi dự kiến rằng, vì
trong phiên bản 64 bit chỉ phải nạp khóa vòng từ bộ nhớ một
lần duy nhất, trong khi đối với phiên bản 32 bit thì một số khóa
vòng sẽ phải được nạp từ bộ nhớ khi mã hóa mỗi khối, do đó
tốc độ của phiên bản 64 bit phải lớn hơn đáng kể so với phiên
bản 32 bit Tuy nhiên, như có thể thấy trên Hình 1, chênh lệch
về tốc độ giữa hai phiên bản này là không nhiều Điều này có
thể được giải thích bởi cơ chế bộ nhớ đệm (cache) trong các vi
xử lý hiện đại của Intel Theo đó, có những khóa vòng tuy
không được nạp vào thanh ghi nhưng được lưu sẵn trong bộ
nhớ cache, việc nạp khóa vòng được thực hiện từ bộ nhớ cache
chứ không phải từ RAM, do đó sự chênh lệch tốc độ giữa hai
phiên bản là không nhiều
Tương tự như trên, chúng tôi thử nghiệm việc giải mã và
thu được kết quả như trên Hình 2
Hình 2 Tốc độ giải mã bằng AES
Trong trường hợp này, tốc độ giải mã của chương trình có
sử dụng tập lệnh AES-NI cũng cao hơn hẳn so với chương
trình không sử dụng tập lệnh này Cụ thể, chương trình không
sử dụng tập lệnh AES-NI đạt được tốc độ 146 MB/s trong khi
chương trình có sử dụng tập lệnh đó đạt được tốc độ 1880
MB/s (đối với phiên bản 32 bit) và 1950 MB/s (đối với phiên
bản 64 bit) Điều này cũng cho thấy rằng sự chênh lệnh tốc độ
giữa phiên bản 32 bit và phiên bản 64 bit là không nhiều
Cũng từ Hình 1 và Hình 2 có thể thấy được tốc độ mã hóa
và giải mã khi sử dụng tập lệnh AES-NI phụ thuộc rõ rệt vào
kích thước vùng đệm Nếu kích thước vùng đệm là 1 khối,
tương đương 16 byte, thì tốc độ mã hóa và giải mã chỉ đạt
khoảng 500 KB/s Nếu tăng kích thước vùng đệm thì tốc độ mã
hóa, giải mã cũng tăng theo; tốc độ cực đại đạt được khi kích
thước vùng đệm vào khoảng 60 khối, tức là 960 byte Như vậy,
để đạt được tốc độ mã hóa, giải mã cao nhất, nên sử dụng vùng đệm có kích thước tối thiểu 1 KB Đây là giá trị rất nhỏ so với kích thước vùng đệm được sử dụng trong thực tế
IV KẾT LUẬN Tập lệnh AES-NI trong các dòng vi xử lý đời mới của Intel
và AMD cho phép đạt được tốc độ mã hóa và giải mã bằng AES cao hơn hẳn so với khi cài đặt thuật toán này sử dụng các lệnh tính toán đa dụng Cụ thể, trên máy tính có CPU Intel Core i5-3210M 2,5 GHz, RAM 4GB và Windows 7 64-bit, chúng tôi đạt được tốc độ mã hóa là 2120 MB/s và tốc độ giải
mã là 1950 MB/s Để đạt được tốc độ mã hóa và giả mã cao nhất, cần sử dụng vùng đệm có kích thước tối thiểu là 1 KB
Phần mềm viết cho nền tảng 64 bit có lợi thế so với phần mềm viết cho nền tảng 32 bit về số lượng thanh ghi XMM để nạp trước các khóa vòng; tuy nhiên lợi thế đó không mang lại
sự khác biệt về tốc độ Do vậy, khi phát triển phần mềm có chức năng mật mã (và có sử dụng AES-NI) thì không cần phải xây dựng hai phiên bản 32 bit và 64 bit nếu chỉ vì muốn đạt được tốc độ mã hóa/giải mã cao hơn trong nền tảng 64 bit; thay vào đó, chỉ cần xây dựng phiên bản 32 bit là đủ
TÀI LIỆU THAM KHẢO [1] Mitchell C Richards, "AES: The Making of a New Encryption Standard, SANS Institute," Tech Rep 2001
[2] Advanced Encryption Standard (AES), NIST std FIPS PUB 197, 2001 [3] AES Instruction Set [Online] Available: https://en.wikipedia.org/wiki/AES_instruction_set#Libraries
[4] Shay Gueron , Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode - Rev 2.02 [Online] Available: https://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/
[5] Intel Advanced Encryption Standard (AES) New Instructions Set, Intel,
2012
[6] AES Implementation in CYASSL [Online] Available: https://github.com/cyassl/cyassl/blob/master/ctaocrypt/src/aes_asm.s
[7] Manley, Raymond, and David Gregg, "A program generator for intel
AES-NI instructions," Progress in Cryptology-INDOCRYPT 2010
Springer Berlin Heidelberg, 2010, pp.311-327
[8] Bharata Rao Inline assembly for x86 in Linux [Online] Available: http://www.ibm.com/developerworks/library/l-ia/
[9] Reducing the Impact of Misaligned Memory Accesses [Online] Available: https://software.intel.com/en-us/articles/reducing-the-impact-of-misaligned-memory-accesses