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

tools / des

des/

Mã hóa và giải mã đối xứng DES, dùng để kết nối với các hệ thống cũ vẫn còn dùng DES. 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

DES mỗi lần chỉ mã hóa được 8 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 DES 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.

Khóa, IV và padding

Khóa DES dài 8 byte, trong đó bit thấp nhất của mỗi byte là bit kiểm tra chẵn lẻ và không tham gia tính toán, nên khóa hiệu dụng chỉ có 56 bit. Nếu khóa dài hơn 8 byte thì chỉ dùng 8 byte đầu, giống DESKeySpec của Java và CryptoJS; ngắn hơn 8 byte sẽ báo lỗi. Trừ ECB, các chế độ còn lại đều cần IV dài 8 byte. IV không cần giữ bí mật, nhưng không nên dùng lại với cùng một khóa.

ECB và CBC yêu cầu độ dài dữ liệu là bội số của 8 byte, nếu thiếu sẽ được bù cho đủ theo kiểu padding đã chọn. PKCS5Padding và PKCS7Padding với DES 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.

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

Cipher.getInstance("DES/CBC/PKCS5Padding") của Java nghĩa là chọn CBC và PKCS5Padding; chỉ viết "DES" thì mặc định là ECB và PKCS5Padding. Trong Java, CTR chỉ dùng được với NoPadding. Chế độ và padding của CryptoJS.DES.encrypt trùng tên với ở đây, còn CryptoJS.pad.Pkcs7 tương ứng với PKCS7Padding. Với hệ thống mới, hãy dùng thẳng AES.

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

Có mã hóa và giải mã 3DES (DESede, TripleDES) được không

Không, ở đây chỉ có DES đơn. Khóa 3DES dài 16 hoặc 24 byte; dán vào đây thì chỉ dùng 8 byte đầu, kết quả sẽ khác với 3DES, và cạnh ô Khóa cũng hiện thông báo "chỉ dùng 8 byte đầu tiên". Nếu cần 3DES, hãy dùng công cụ hỗ trợ DESede.

Làm gì khi báo "Khóa dài N byte, khóa DES cần ít nhất 8 byte"

Ít hơn 8 byte sẽ báo lỗi, công cụ không tự bù số 0, bạn phải tự bù cho đủ 8 byte. Dễ mắc hơn là chọn sai định dạng: khóa hex 16 ký tự mà để định dạng khóa là string thì sẽ bị coi là văn bản 16 byte, chỉ dùng 8 ký tự đầu, không báo lỗi, chỉ hiện thông báo "chỉ dùng 8 byte đầu tiên" cạnh ô Khóa và bên dưới kết quả, nên kết quả đương nhiên không khớp. 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.

Làm gì khi báo "IV của chế độ này phải dài đúng 8 byte"

IV của DES phải dài đúng 8 byte, không phải 16 byte như AES, với mọi chế độ trừ ECB. Khóa dài hơn 8 byte thì chỉ lấy 8 byte đầu, còn IV thì không: dài hơn hay ngắn hơn đều báo lỗi ngay, nên IV 16 byte lấy từ tham số AES phải đổi thành 8 byte. Cũng hãy xem định dạng trước: hex 16 ký tự mới là 8 byte, chọn string thì chính 16 ký tự đó là 16 byte. ECB không dùng IV nên ô IV sẽ bị ẩn.

Làm gì khi giải mã báo "padding không hợp lệ" hoặc "không phải bội số của 8"

Độ dài bản mã không phải bội số của 8 thường là do sao chép chưa đầy đủ, hoặc chọn nhầm hex với base64. Padding không hợp lệ thường là do 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. 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 8 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.

Kết quả mã hóa không khớp với Java hoặc CryptoJS, 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 64 bit, nên sẽ không khớp nếu bên kia dùng CFB8.

Kết quả của CryptoJS.DES.encrypt bắt đầu bằng U2FsdGVkX1, ở đây giải mã được không

Không. Khi truyền thẳng một chuỗi vào CryptoJS.DES.encrypt(bản rõ, chuỗi), CryptoJS coi nó là mật khẩu: thêm salt ngẫu nhiên rồi sinh khóa và IV theo cách của OpenSSL, kết quả bắt đầu bằng U2FsdGVkX1; định dạng này không được hỗ trợ ở đây. Để khớp với công cụ này, hãy dùng CryptoJS.enc.Utf8.parse để chuyển khóa thành byte rồi truyền vào, đồng thời chỉ định rõ iv, mode và padding.

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, đầu vào và kết quả, cùng một dấu vân tay 8 ký tự tính từ 8 byte đầu của 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ử".