Chà, bạn có thể tra cứu nó trên Wikipedia ... Nhưng vì bạn muốn một lời giải thích, tôi sẽ làm hết sức mình ở đây:
Hàm băm
Chúng cung cấp ánh xạ giữa đầu vào độ dài tùy ý và đầu ra (thường là) chiều dài cố định (hoặc chiều dài nhỏ hơn). Nó có thể là bất cứ thứ gì từ một crc32 đơn giản, đến hàm băm mật mã đầy đủ như MD5 hoặc SHA1 / 2/256/512. Vấn đề là có một bản đồ một chiều đang diễn ra. Luôn luôn có nhiều ánh xạ: 1 (nghĩa là sẽ luôn có xung đột) vì mọi hàm tạo ra một đầu ra nhỏ hơn khả năng nhập (Nếu bạn đưa mọi tệp 1mb có thể vào MD5, bạn sẽ nhận được rất nhiều va chạm).
Lý do họ khó (hoặc không thể thực tế) để đảo ngược là vì cách họ làm việc nội bộ. Hầu hết các hàm băm mật mã lặp đi lặp lại trên bộ đầu vào nhiều lần để tạo đầu ra. Vì vậy, nếu chúng ta xem xét từng đoạn có độ dài cố định của đầu vào (phụ thuộc vào thuật toán), hàm băm sẽ gọi đó là trạng thái hiện tại. Sau đó, nó sẽ lặp lại trạng thái và thay đổi nó sang trạng thái mới và sử dụng nó làm phản hồi cho chính nó (MD5 thực hiện điều này 64 lần cho mỗi khối dữ liệu 512 bit). Sau đó, bằng cách nào đó kết hợp các trạng thái kết quả từ tất cả các lần lặp lại với nhau để tạo thành hàm băm kết quả.
Bây giờ, nếu bạn muốn giải mã hàm băm, trước tiên bạn cần tìm ra cách chia băm đã cho thành các trạng thái lặp của nó (1 khả năng cho các đầu vào nhỏ hơn kích thước của một khối dữ liệu, nhiều cho các đầu vào lớn hơn). Sau đó, bạn cần phải đảo ngược việc lặp lại cho mỗi trạng thái. Bây giờ, để giải thích tại sao điều này RẤT khó khăn, hãy tưởng tượng cố gắng suy luận a
và b
từ công thức sau : 10 = a + b
. Có 10 kết hợp tích cực a
và b
có thể làm việc. Bây giờ lặp lại một loạt các lần:tmp = a + b; a = b; b = tmp
. Đối với 64 lần lặp, bạn có hơn 10 ^ 64 khả năng để thử. Và đó chỉ là một bổ sung đơn giản trong đó một số trạng thái được bảo tồn từ lần lặp đến lần lặp. Các hàm băm thực sự thực hiện nhiều hơn 1 thao tác (MD5 thực hiện khoảng 15 thao tác trên 4 biến trạng thái). Và vì lần lặp tiếp theo phụ thuộc vào trạng thái của lần trước và lần trước bị hủy trong việc tạo trạng thái hiện tại, nên không thể xác định trạng thái đầu vào dẫn đến trạng thái đầu ra nhất định (đối với mỗi lần lặp không ít hơn). Kết hợp điều đó, với số lượng lớn các khả năng có liên quan và giải mã ngay cả MD5 sẽ lấy một lượng tài nguyên gần như vô hạn (nhưng không phải vô hạn). Rất nhiều tài nguyên mà nó '
Chức năng mã hóa
Chúng cung cấp ánh xạ 1: 1 giữa đầu vào và đầu ra có độ dài tùy ý. Và chúng luôn luôn có thể đảo ngược. Điều quan trọng cần lưu ý là nó có thể đảo ngược bằng cách sử dụng một số phương pháp. Và nó luôn luôn là 1: 1 cho một khóa nhất định. Bây giờ, có nhiều đầu vào: các cặp khóa có thể tạo ra cùng một đầu ra (thực tế thường có, tùy thuộc vào chức năng mã hóa). Dữ liệu được mã hóa tốt không thể phân biệt với nhiễu ngẫu nhiên. Điều này khác với một đầu ra băm tốt luôn có định dạng nhất quán.
Trường hợp sử dụng
Sử dụng hàm băm khi bạn muốn so sánh một giá trị nhưng không thể lưu trữ biểu diễn đơn giản (vì bất kỳ lý do nào). Mật khẩu phải rất phù hợp với trường hợp sử dụng này vì bạn không muốn lưu trữ chúng dưới dạng văn bản đơn giản vì lý do bảo mật (và không nên). Nhưng nếu bạn muốn kiểm tra một hệ thống tập tin cho các tập tin nhạc lậu thì sao? Sẽ không thực tế khi lưu trữ 3 mb mỗi tệp nhạc. Vì vậy, thay vào đó, lấy hàm băm của tệp và lưu trữ tệp đó (md5 sẽ lưu trữ 16 byte thay vì 3mb). Bằng cách đó, bạn chỉ cần băm từng tệp và so sánh với cơ sở dữ liệu băm được lưu trữ (Điều này không hoạt động tốt trong thực tế vì mã hóa lại, thay đổi tiêu đề tệp, v.v., nhưng đó là trường hợp sử dụng ví dụ).
Sử dụng hàm băm khi bạn kiểm tra tính hợp lệ của dữ liệu đầu vào. Đó là những gì họ được thiết kế cho. Nếu bạn có 2 phần đầu vào và muốn kiểm tra xem chúng có giống nhau không, hãy chạy cả hai thông qua hàm băm. Xác suất va chạm thấp về mặt thiên văn đối với các kích cỡ đầu vào nhỏ (giả sử hàm băm tốt). Đó là lý do tại sao nên sử dụng mật khẩu. Đối với mật khẩu tối đa 32 ký tự, md5 có không gian đầu ra gấp 4 lần. SHA1 có 6 lần không gian đầu ra (xấp xỉ). SHA512 có khoảng 16 lần không gian đầu ra. Bạn không thực sự quan tâm mật khẩu là gì , bạn quan tâm nếu nó giống với mật khẩu được lưu trữ. Đó là lý do tại sao bạn nên sử dụng băm cho mật khẩu.
Sử dụng mã hóa bất cứ khi nào bạn cần để lấy lại dữ liệu đầu vào. Chú ý từ cần . Nếu bạn đang lưu trữ số thẻ tín dụng, bạn cần lấy lại chúng vào một lúc nào đó, nhưng không muốn lưu trữ chúng dưới dạng văn bản đơn giản. Vì vậy, thay vào đó, lưu trữ phiên bản được mã hóa và giữ khóa an toàn nhất có thể.
Các hàm băm cũng rất tốt để ký dữ liệu. Ví dụ: nếu bạn đang sử dụng HMAC, bạn ký một phần dữ liệu bằng cách lấy một hàm băm của dữ liệu được nối với một giá trị đã biết nhưng không được truyền (một giá trị bí mật). Vì vậy, bạn gửi văn bản đơn giản và hàm băm HMAC. Sau đó, người nhận chỉ cần băm dữ liệu đã gửi với giá trị đã biết và kiểm tra xem liệu nó có khớp với HMAC được truyền hay không. Nếu nó giống nhau, bạn biết nó không bị can thiệp bởi một bên mà không có giá trị bí mật. Điều này thường được sử dụng trong các hệ thống cookie bảo mật bởi các khung HTTP, cũng như trong việc truyền thông điệp dữ liệu qua HTTP, nơi bạn muốn đảm bảo tính toàn vẹn trong dữ liệu.
Một lưu ý về băm cho mật khẩu:
Một tính năng chính của các hàm băm mật mã là chúng phải được tạo ra rất nhanh và rất khó / chậm để đảo ngược (rất nhiều đến mức thực tế là không thể). Điều này đặt ra một vấn đề với mật khẩu. Nếu bạn lưu trữ sha512(password)
, bạn sẽ không làm gì để bảo vệ chống lại các bảng cầu vồng hoặc các cuộc tấn công vũ phu. Hãy nhớ rằng, hàm băm được thiết kế cho tốc độ. Vì vậy, thật tầm thường khi kẻ tấn công chỉ chạy một từ điển thông qua chức năng băm và kiểm tra từng kết quả.
Thêm một muối giúp vấn đề vì nó thêm một chút dữ liệu không xác định vào hàm băm. Vì vậy, thay vì tìm thấy bất cứ thứ gì phù hợp md5(foo)
, họ cần tìm thứ gì đó khi thêm vào sản phẩm muối đã biết md5(foo.salt)
(điều này rất khó thực hiện). Nhưng nó vẫn không giải quyết được vấn đề tốc độ vì nếu họ biết muối thì đó chỉ là vấn đề chạy từ điển.
Vì vậy, có nhiều cách để đối phó với điều này. Một phương pháp phổ biến được gọi là tăng cường khóa (hoặc kéo dài khóa). Về cơ bản, bạn lặp đi lặp lại một hàm băm nhiều lần (thường là hàng nghìn). Điều này làm hai điều. Đầu tiên, nó làm chậm thời gian chạy của thuật toán băm. Thứ hai, nếu được thực hiện đúng (chuyển đầu vào và muối trở lại trong mỗi lần lặp) thực sự làm tăng entropy (không gian có sẵn) cho đầu ra, làm giảm cơ hội va chạm. Một thực hiện tầm thường là:
var hash = password + salt;
for (var i = 0; i < 5000; i++) {
hash = sha512(hash + password + salt);
}
Có những cách triển khai khác, chuẩn hơn như PBKDF2 , BCrypt . Nhưng kỹ thuật này được sử dụng bởi khá nhiều hệ thống liên quan đến bảo mật (như PGP, WPA, Apache và OpenSSL).
Điểm mấu chốt, hash(password)
là không đủ tốt. hash(password + salt)
tốt hơn, nhưng vẫn không đủ tốt ... Sử dụng cơ chế băm kéo dài để tạo băm mật khẩu của bạn ...
Một lưu ý khác về kéo dài tầm thường
Không trong mọi trường hợp, cung cấp đầu ra của một hàm băm trực tiếp vào hàm băm :
hash = sha512(password + salt);
for (i = 0; i < 1000; i++) {
hash = sha512(hash); // <-- Do NOT do this!
}
Lý do cho điều này có liên quan đến va chạm. Hãy nhớ rằng tất cả các hàm băm có xung đột vì không gian đầu ra có thể (số lượng đầu ra có thể) nhỏ hơn không gian đầu vào. Để xem tại sao, hãy nhìn vào những gì xảy ra. Để nói trước điều này, chúng ta hãy đưa ra giả định rằng có 0,001% cơ hội va chạm từ sha1()
( thực tế nó thấp hơn nhiều , nhưng với mục đích trình diễn).
hash1 = sha1(password + salt);
Bây giờ, hash1
có xác suất va chạm là 0,001%. Nhưng khi chúng ta làm tiếp theo hash2 = sha1(hash1);
, tất cả các va chạm hash1
tự động trở thành va chạmhash2
. Vì vậy, bây giờ, chúng tôi có tỷ lệ của hash1 ở mức 0,001% và sha1()
cuộc gọi thứ 2 thêm vào đó. Vì vậy, bây giờ, hash2
có xác suất va chạm là 0,002%. Đó là gấp đôi cơ hội! Mỗi lần lặp sẽ thêm một 0.001%
cơ hội va chạm khác vào kết quả. Vì vậy, với 1000 lần lặp, cơ hội va chạm đã tăng từ mức 0,001% đến 1%. Bây giờ, sự xuống cấp là tuyến tính và xác suất thực tế nhỏ hơn rất nhiều, nhưng hiệu quả là như nhau (ước tính khả năng xảy ra va chạm với md5
khoảng 1 / (2 128 ) hoặc 1 / (3x10 38). Mặc dù điều đó có vẻ nhỏ, nhờ vào cuộc tấn công sinh nhật, nó không thực sự nhỏ như nó có vẻ).
Thay vào đó, bằng cách nối lại muối và mật khẩu mỗi lần, bạn sẽ giới thiệu lại dữ liệu vào hàm băm. Vì vậy, bất kỳ va chạm của bất kỳ vòng cụ thể không còn là va chạm của vòng tiếp theo. Vì thế:
hash = sha512(password + salt);
for (i = 0; i < 1000; i++) {
hash = sha512(hash + password + salt);
}
Có cùng cơ hội va chạm với sha512
chức năng bản địa . Đó là những gì bạn muốn. Sử dụng thay thế.