Trái ngược với những gì mà các câu trả lời được ủng hộ nhiều nhất ở đây nhấn mạnh, tính không sai lệch (nghĩa là có một số chuỗi băm thành cùng một giá trị) của một hàm băm mật mã gây ra bởi sự khác biệt giữa kích thước đầu vào lớn (có thể là vô hạn) và kích thước đầu ra cố định không điểm quan trọng - thực ra, chúng tôi thích các hàm băm mà ở đó những va chạm đó hiếm khi xảy ra nhất có thể.
Hãy xem xét hàm này (trong ký hiệu PHP, như câu hỏi):
function simple_hash($input) {
return bin2hex(substr(str_pad($input, 16), 0, 16));
}
Điều này thêm vào một số khoảng trắng, nếu chuỗi quá ngắn và sau đó lấy 16 byte đầu tiên của chuỗi, sau đó mã hóa nó dưới dạng thập lục phân. Nó có cùng kích thước đầu ra như một băm MD5 (32 ký tự thập lục phân hoặc 16 byte nếu chúng ta bỏ qua phần bin2hex).
print simple_hash("stackoverflow.com");
Điều này sẽ xuất ra:
737461636b6f766572666c6f772e636f6d
Hàm này cũng có cùng thuộc tính không gây ô nhiễm như được đánh dấu bởi câu trả lời của Cody cho MD5: Chúng ta có thể chuyển các chuỗi có kích thước bất kỳ (miễn là chúng vừa với máy tính của chúng ta) và nó sẽ chỉ xuất ra 32 chữ số hex. Tất nhiên nó không thể bị thương.
Nhưng trong trường hợp này, việc tìm một chuỗi ánh xạ tới cùng một hàm băm là rất nhỏ (chỉ cần áp dụng hex2bin
cho hàm băm của bạn và bạn có nó). Nếu chuỗi ban đầu của bạn có độ dài 16 (như ví dụ của chúng tôi), bạn thậm chí sẽ nhận được chuỗi gốc này. Không điều gì thuộc loại này có thể xảy ra đối với MD5, ngay cả khi bạn biết độ dài của đầu vào là khá ngắn (ngoại trừ việc thử tất cả các đầu vào có thể cho đến khi chúng tôi tìm thấy một đầu vào phù hợp, ví dụ như một cuộc tấn công bạo lực).
Các giả định quan trọng cho một hàm băm mật mã là:
- thật khó để tìm thấy bất kỳ chuỗi nào tạo ra một hàm băm nhất định (kháng trước hình ảnh)
- khó có thể tìm thấy bất kỳ chuỗi nào khác tạo ra cùng một hàm băm như một chuỗi đã cho (khả năng kháng preimage thứ hai)
- khó có thể tìm thấy bất kỳ cặp chuỗi nào có cùng hàm băm (khả năng chống va chạm)
Rõ ràng là simple_hash
hàm của tôi không đáp ứng các điều kiện này. (Trên thực tế, nếu chúng ta hạn chế không gian đầu vào thành "chuỗi 16 byte", thì hàm của tôi sẽ bị ảnh hưởng và do đó, thậm chí có thể cung cấp khả năng chống va chạm và kháng tiền hình ảnh thứ hai.)
Hiện đã tồn tại các cuộc tấn công xung đột chống lại MD5 (ví dụ: có thể tạo ra một cặp chuỗi, ngay cả với cùng một tiền tố đã cho, có cùng một hàm băm, với khá nhiều công việc, nhưng không phải là không thể thực hiện được), vì vậy bạn không nên sử dụng MD5 cho bất kỳ điều gì quan trọng. Vẫn chưa có một cuộc tấn công preimage, nhưng các cuộc tấn công sẽ tốt hơn.
Để trả lời câu hỏi thực tế:
Điều gì về các hàm này khiến các chuỗi kết quả không thể truy xuất lại?
Điều mà MD5 (và các hàm băm khác được xây dựng dựa trên cấu trúc Merkle-Damgard) thực hiện một cách hiệu quả là áp dụng một thuật toán mã hóa với thông báo là khóa và một số giá trị cố định là "văn bản thuần túy", sử dụng bản mã kết quả làm mã băm. (Trước đó, đầu vào được đệm và chia thành các khối, mỗi khối này được sử dụng để mã hóa đầu ra của khối trước đó, XORed với đầu vào của nó để ngăn các tính toán ngược lại.)
Các thuật toán mã hóa hiện đại (bao gồm cả các thuật toán được sử dụng trong các hàm băm) được thực hiện theo cách khó khôi phục khóa, ngay cả khi cung cấp cả bản rõ và bản mã (hoặc ngay cả khi đối thủ chọn một trong số chúng). Họ thực hiện điều này nói chung bằng cách thực hiện nhiều thao tác xáo trộn bit theo cách mà mỗi bit đầu ra được xác định bởi từng bit khóa (nhiều lần) và cả từng bit đầu vào. Bằng cách đó, bạn chỉ có thể dễ dàng truy xuất lại những gì xảy ra bên trong nếu bạn biết khóa đầy đủ và cả đầu vào hoặc đầu ra.
Đối với các hàm băm giống như MD5 và một cuộc tấn công preimage (với một chuỗi băm đơn khối, để làm cho mọi thứ dễ dàng hơn), bạn chỉ có đầu vào và đầu ra của hàm mã hóa chứ không có khóa (đây là những gì bạn đang tìm kiếm).