Ngôn ngữ: Tiếng Việt

tools / aes

aes/

Mã hóa và giải mã đối xứng AES. Bạn có thể chọn chế độ, padding, định dạng khóa và IV, cũng như bộ ký tự; kết quả khớp với Java và CryptoJS, khóa không rời khỏi trình duyệt.

Bản rõ

Bản mã

Lịch sử

Mỗi lần mã hóa hoặc giải mã thành công sẽ tự động ghi lại một mục, giữ 20 mục gần nhất và chỉ lưu trong trình duyệt của thiết bị này. Khóa không được lưu, nhưng IV và bản rõ sau khi giải mã thì có, nên hãy xóa lịch sử sau khi dùng trên máy tính dùng chung.

AES, DES và RSA là gì, khác nhau thế nào

AES và DES là mã hóa đối xứng: mã hóa và giải mã dùng chung một khóa, giống như một chiếc chìa vừa khóa cửa vừa mở cửa. Chúng chạy nhanh, phù hợp để mã hóa lượng dữ liệu lớn; khó khăn nằm ở chỗ làm sao gửi khóa này cho đối phương một cách an toàn.

DES là chuẩn cũ từ thập niên 1970, khóa hiệu dụng chỉ có 56 bit, ngày nay phần cứng chuyên dụng hoặc cụm máy tính có thể dò vét cạn để phá, nên chỉ dùng khi cần kết nối với những hệ thống cũ vẫn còn dùng nó. AES là chuẩn mới thay thế DES, khóa 128, 192 hoặc 256 bit, hiện chưa có cách phá khả thi và là lựa chọn hàng đầu để mã hóa dữ liệu.

RSA là mã hóa bất đối xứng: có một cặp khóa. Khóa công khai có thể đưa cho bất kỳ ai và dùng để mã hóa; khóa riêng do bạn tự giữ và dùng để giải mã. Giống như một hòm thư ai cũng bỏ thư vào được nhưng chỉ bạn có chìa để mở. Ưu điểm là không cần thống nhất khóa từ trước, nhược điểm là rất chậm và mỗi lần chỉ mã hóa được vài trăm byte. Hệ thống thực tế thường kết hợp cả hai: dùng RSA mã hóa một khóa AES sinh ngẫu nhiên rồi gửi cho đối phương, sau đó dùng AES mã hóa dữ liệu thật.

Chế độ mã hóa là gì, nên chọn chế độ nào

AES mỗi lần chỉ mã hóa được 16 byte; chế độ quyết định cách chia dữ liệu dài thành các khối và cách các khối liên kết với nhau. ECB mã hóa từng khối riêng lẻ, nên nội dung giống nhau sẽ cho bản mã giống nhau và làm lộ quy luật của dữ liệu, không nên dùng. CBC trộn mỗi khối với khối bản mã trước đó rồi mới mã hóa, khối đầu tiên trộn với IV, là lựa chọn phổ biến nhất. CFB, OFB, CTR biến AES thành một dòng khóa (keystream) rồi XOR với dữ liệu từng byte, nên không cần padding. GCM tính thêm một thẻ xác thực (Tag) trên nền CTR, bản mã bị sửa thì giải mã sẽ thất bại, hiện là chế độ được khuyên dùng nhất.

IV và padding dùng để làm gì

IV (vectơ khởi tạo) giúp cùng một nội dung mỗi lần mã hóa cho ra kết quả khác nhau. IV không cần giữ bí mật, có thể gửi kèm bản mã, nhưng không nên dùng lại với cùng một khóa, đặc biệt là với GCM. Trừ ECB, các chế độ còn lại đều cần IV: GCM nên dùng 12 byte, các chế độ khác bắt buộc phải là 16 byte.

ECB và CBC yêu cầu độ dài dữ liệu là bội số của 16 byte, nếu thiếu sẽ được bù cho đủ theo kiểu padding đã chọn. PKCS5Padding và PKCS7Padding với AES hoàn toàn giống nhau và là hai kiểu dùng nhiều nhất. ZeroPadding bù bằng số 0, khi giải mã sẽ cắt bỏ mọi byte 0 ở cuối, nên nếu bản rõ vốn kết thúc bằng byte 0 thì các byte đó cũng bị cắt luôn; NoPadding không bù gì, bạn phải tự đảm bảo độ dài. GCM không dùng padding.

Đối chiếu với cách viết trong Java và CryptoJS

Cipher.getInstance("AES/CBC/PKCS5Padding") của Java nghĩa là chọn CBC và PKCS5Padding; chỉ viết "AES" thì mặc định là ECB và PKCS5Padding. Trong Java, CTR và GCM chỉ dùng được với NoPadding, và Tag của GCM chỉ hỗ trợ từ 96 đến 128 bit. CryptoJS.pad.Pkcs7 của CryptoJS tương ứng với PKCS7Padding; ZeroPadding, AnsiX923, Iso10126, Iso97971 trùng tên nhau. Khi truyền thẳng một chuỗi mật khẩu vào CryptoJS.AES.encrypt, thư viện sẽ tự sinh khóa và xuất ra kết quả bắt đầu bằng U2FsdGVkX1; cách dùng này không được hỗ trợ ở đây, hãy nhập khóa dài 16, 24 hoặc 32 byte kèm IV.

Tag và AAD của GCM là gì

Tag là giá trị kiểm tra do GCM tính ra; vài byte cuối của kết quả mã hóa chính là Tag (Tag 128 bit là 16 byte). AAD là dữ liệu xác thực bổ sung, ví dụ phần đầu của thông điệp: nó không được mã hóa nhưng vẫn tham gia kiểm tra, nên khi giải mã phải nhập đúng nội dung đó, nếu không sẽ báo kiểm tra không đạt.

Câu hỏi thường gặp

Làm gì khi báo "Khóa dài N byte" hoặc "IV dài N byte"

Trước hết hãy xem đã chọn đúng định dạng chưa: cùng 32 ký tự, chọn string là 32 byte, chọn hex mới là 16 byte. Khóa AES phải dài 16, 24 hoặc 32 byte; trừ ECB và GCM, IV phải dài đúng 16 byte. Công cụ này không tự bù số 0 hay cắt bớt, số byte hiện tại được hiển thị cạnh tiêu đề của ô Khóa và IV. Khi chọn string, số byte được tính theo bộ ký tự đã chọn, một chữ Hán trong UTF-8 chiếm 3 byte. Nếu backend xử lý mật khẩu trước, ví dụ bù số 0 hoặc băm, hãy tính ra các byte cuối cùng trước rồi nhập vào ở định dạng hex hoặc base64.

Làm gì khi giải mã báo "padding không hợp lệ"

Nghĩa là khối cuối cùng sau khi giải mã không khớp với quy tắc padding đã chọn. Thường là một trong các mục khóa, IV, chế độ hoặc kiểu padding không giống lúc mã hóa, cũng có thể do bản mã được sao chép chưa đầy đủ. Hãy đối chiếu từng tham số với bên mã hóa; chọn sai định dạng khóa hoặc định dạng bản mã (hex hay base64) cũng gây ra lỗi này. ZeroPadding và NoPadding không kiểm tra padding nên sẽ không báo lỗi này, nhưng nếu tham số sai thì kết quả sẽ là chuỗi ký tự lộn xộn.

Phần đầu kết quả giải mã bị loạn chữ, hoặc báo "không phải văn bản UTF-8 hợp lệ"

Hãy kiểm tra IV trước. Khi bản mã dài hơn một khối, nếu IV sai ở chế độ CBC và CFB thì chỉ khối 16 byte đầu tiên bị lỗi, phần phía sau vẫn bình thường và cũng không báo lỗi padding; biểu hiện là đầu văn bản bị loạn chữ còn phần sau đúng. Nếu có thông báo kết quả không phải văn bản hợp lệ, cũng có thể bộ ký tự không khớp với bên mã hóa, ví dụ bên kia dùng GBK. Đổi định dạng đầu ra sang hex để xác nhận trước xem bản thân các byte giải mã ra có đúng không.

Làm gì khi giải mã GCM báo "kiểm tra Tag không đạt"

Nghĩa là một trong các mục khóa, IV, AAD, độ dài Tag không giống lúc mã hóa, hoặc bản mã đã bị sửa. Công cụ này coi đoạn cuối của dữ liệu đầu vào là Tag, độ dài theo tùy chọn "Độ dài Tag" (mặc định 128 bit, tức 16 byte), nên bản mã và Tag phải được nhập liền nhau; nếu bên kia gửi Tag riêng thì hãy nối nó vào sau bản mã trước. Định dạng AAD mặc định là hex, khi nhập nội dung dạng string nhớ đổi định dạng; nếu lúc mã hóa không dùng AAD thì khi giải mã cũng phải để trống.

Kết quả mã hóa không khớp với backend Java, Python..., kiểm tra thế nào

Hãy đối chiếu theo thứ tự: chế độ và padding, định dạng và số byte của khóa và IV, bộ ký tự, định dạng đầu vào và đầu ra. Bản rõ ở định dạng string không bị cắt khoảng trắng đầu cuối, thừa một dấu xuống dòng ở cuối đã là dữ liệu khác. Ở đây CTR, CFB, OFB cũng được bù theo kiểu padding đã chọn, nên khi chọn PKCS5Padding thì bản mã dài hơn bản rõ; nếu backend dùng NoPadding thì ở đây cũng phải chọn NoPadding. CFB ở đây là phản hồi nguyên khối 128 bit, nên sẽ không khớp nếu bên kia dùng CFB8.

Bản mã nên chọn hex hay base64, chọn sai thì sao

Cứ theo định dạng đầu ra của bên kia: toàn ký tự 0-9, a-f là hex; có chữ hoa lẫn chữ thường, dấu +, / hoặc kết thúc bằng = là base64. Khi giải mã, chọn sai không phải lúc nào cũng báo lỗi ngay, vì mọi ký tự hex đều là ký tự base64 hợp lệ, chỉ là giải ra các byte sai, cuối cùng hiện thành lỗi "không phải bội số của 16" hoặc "padding không hợp lệ". Base64 dùng - và _ (dạng an toàn cho URL) hoặc thiếu dấu = vẫn nhận được; khoảng trắng, dấu hai chấm và tiền tố 0x trong hex sẽ bị bỏ qua.

Lịch sử lưu những gì, có bị tải lên không

Chỉ lưu trong localStorage của trình duyệt trên thiết bị này, không tải lên, mã nguồn trang không có bất kỳ yêu cầu mạng nào. Sau mỗi lần mã hóa hoặc giải mã thành công sẽ ghi một mục, giữ tối đa 20 mục; nếu đầu vào hoặc kết quả vượt quá 20.000 ký tự thì không ghi. Mỗi mục có tham số, IV, AAD, đầu vào và kết quả, cùng một dấu vân tay 8 ký tự tính từ khóa (chuỗi ký tự sau dấu # trong mục, dùng để phân biệt có phải cùng một khóa hay không), không lưu bản thân khóa, nên sau khi bấm "Điền lại" bạn phải nhập lại khóa. Có thể xóa riêng từng mục; trên máy tính dùng chung, dùng xong hãy bấm "Xóa lịch sử".

Có tự tạo khóa hoặc IV ngẫu nhiên được không

Không. Ở đây không có nút tạo, khóa và IV phải tự nhập. Cùng bản rõ, khóa, IV và tham số thì kết quả mã hóa lần nào cũng giống nhau, chỉ có padding ISO10126 trộn thêm byte ngẫu nhiên nên kết quả mới khác. Khi cần giá trị ngẫu nhiên, bạn có thể tự tạo, ví dụ lệnh openssl rand -hex 16 trên dòng lệnh sẽ in ra 16 byte, chọn định dạng hex rồi điền vào là được.