plan: libxcrypt-compatible sha512-crypt (16-char salt); KAT test
This commit is contained in:
1 parent
07ff88c18d
commit
bc600c27a0
1 file changed
+19
-3
+19
-3
@@ -219,11 +219,19 @@ pub fn classify_secret(s: &str) -> SecretKind {
|
|||||||
SecretKind::Plaintext(s.to_string())
|
SecretKind::Plaintext(s.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SHA512-crypt hash (what `mkpasswd -m sha-512` produces).
|
/// SHA512-crypt hash compatible with glibc/libxcrypt (Dovecot, `mkpasswd -m sha-512`).
|
||||||
|
///
|
||||||
|
/// The salt is 12 random bytes = exactly 16 salt characters. sha-crypt 0.6's
|
||||||
|
/// default (16 bytes -> 22 characters) hashes over all 22 characters, while
|
||||||
|
/// libxcrypt only uses the first 16, so such hashes never verify in Dovecot
|
||||||
|
/// (caught by the e2e test).
|
||||||
pub fn sha512_crypt(password: &str) -> Result<String> {
|
pub fn sha512_crypt(password: &str) -> Result<String> {
|
||||||
|
use rand::RngExt;
|
||||||
use sha_crypt::{PasswordHasher, ShaCrypt};
|
use sha_crypt::{PasswordHasher, ShaCrypt};
|
||||||
let h =
|
let salt: [u8; 12] = rand::rng().random();
|
||||||
ShaCrypt::default().hash_password(password.as_bytes()).map_err(|e| anyhow::anyhow!("hashing password: {e}"))?;
|
let h = ShaCrypt::default()
|
||||||
|
.hash_password_with_salt(password.as_bytes(), &salt)
|
||||||
|
.map_err(|e| anyhow::anyhow!("hashing password: {e}"))?;
|
||||||
Ok(h.as_str().to_string())
|
Ok(h.as_str().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,6 +495,14 @@ mod tests {
|
|||||||
assert!(h.starts_with("$6$"));
|
assert!(h.starts_with("$6$"));
|
||||||
assert!(verify_sha_crypt("correct horse", &h));
|
assert!(verify_sha_crypt("correct horse", &h));
|
||||||
assert!(!verify_sha_crypt("wrong", &h));
|
assert!(!verify_sha_crypt("wrong", &h));
|
||||||
|
// glibc/libxcrypt only use 16 salt characters; longer salts never verify there.
|
||||||
|
let salt = h.trim_start_matches("$6$").split('$').find(|f| !f.starts_with("rounds=")).unwrap();
|
||||||
|
assert_eq!(salt.len(), 16, "{h}");
|
||||||
|
// Algorithm matches glibc (Drepper's test vector).
|
||||||
|
assert!(verify_sha_crypt(
|
||||||
|
"Hello world!",
|
||||||
|
"$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJuesI68u4OTLiBFdcbYEdFCoEOfaS35inz1"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in new issue
Block a user