Dovecot dùng hàm dovadm để mã hóa mật khẩu email
doveadm pw -s SHA512-CRYPT -p plain_text_password
Trong PHP, có thể dùng shell_exec để gọi hàm dovadm, nhưng trước hết phải cài đặt dovecot trên server. Ngoài ra việc gọi shell_exec được đánh giá là không an toàn.
$password = shell_exec('/usr/bin/doveadm pw -s SHA512-CRYPT -p plain_text_password);
PHP có nhiều hàm dành cho việc mã hóa, vấn đề là tìm được cơ chế tương đương với hàm dovadm, nhưng việc khảo sát có khó khăn vì mỗi lúc dovadm cho ra một chuỗi mã hóa khác nhau của cùng một mật khẩu thô ban đầu.
Câu lệnh PHP mã hóa kiểu Dovecot
- SHA512-CRYPT
$password = "PlainTextPassword";
$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SHA512-CRYPT}" . crypt($password, "$6$$salt");
- SHA512 Base64 Encoded
$password = "PlainTextPassword";
//$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SHA512.b64}" . base64_encode(hash('sha512', $password, true));
- SHA256-CRYPT
$password = "PlainTextPassword";
$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SHA256-CRYPT}" . crypt($password, "$5$$salt");
- SHA256 Base64 Encoded
$password = "PlainTextPassword";
//$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SHA256.b64}" . base64_encode(hash('sha256', $password, true));
- SSHA512-CRYPT (Salted)
$password = "PlainTextPassword";
$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SSHA512}" . base64_encode(hash('sha512', $password . $salt, true) . $salt);
- SSHA256-CRYPT (Salted)
$password = "PlainTextPassword";
$salt = substr(sha1(rand()), 0, 16);
$hashedPassword = "{SSHA256}" . base64_encode(hash('sha256', $password . $salt, true) . $salt);
Chú thích
- $salt là chuỗi ngẫu nhiên 16 ký tự. Đây là nguyên nhân chuỗi mã hóa CRYPT mỗi lúc mỗi khác nhau
- Mã hóa dùng hash trả về chuỗi nhị phân nên cần dùng base64_encode để chuyển về ký tự ASCII
- SSHA512-CRYPT (Salted) mặc định được dùng trong iRedMail các phiên bản gần đây
- Phương pháp mã hóa được đặt trước chuỗi mã hóa để dùng trong tính toán so khớp mật khẩu. Đầu tiên phải lấy được chuỗi $salt ở cuối, sau đó tùy theo phương thức mã hóa đễ mã hóa mật khẩu thô rồi so sánh với mật khẩu mã hóa đã lưu. Các phương pháp mã hóa nêu trên là 1 chiều, không có đủ thông tin để tìm lại mật khẩu gốc từ mật khẩu mã hóa.
// $db_password: Mật khẩu đã mã hóa
// $password: Mật khẩu thô
if (preg_match('/\{(\w+)\}/', $db_password, $m) === false) exit;
$scheme = $m[1];
$tmp = base64_decode(substr($db_password, strlen($scheme)+2));
$salt = substr($tmp,-16);
// Thí dụ trường hợp SSHA512
if ($scheme == 'SSHA512'){
$yes = $db_password=='{SSHA512}'.base64_encode(hash('sha512', $password.$salt, true).$salt);
}