1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crypto::sha2::Sha512;
use super::{Result, HashSetup, IntoHashSetup, consteq};
use random;
use sha2_crypt::{sha2_crypt, parse_sha2_hash, sha2_hash_with};
pub use sha2_crypt::MIN_ROUNDS;
pub use sha2_crypt::MAX_ROUNDS;
pub use sha2_crypt::DEFAULT_ROUNDS;
pub use sha2_crypt::MAX_SALT_LEN;
const SHA512_MAGIC: &'static str = "$6$";
const SHA512_TRANSPOSE: &'static [u8] = b"\x2a\x15\x00\x01\x2b\x16\x17\x02\x2c\x2d\x18\x03\x04\x2e\x19\x1a\
\x05\x2f\x30\x1b\x06\x07\x31\x1c\x1d\x08\x32\x33\x1e\x09\x0a\x34\
\x1f\x20\x0b\x35\x36\x21\x0c\x0d\x37\x22\x23\x0e\x38\x39\x24\x0f\
\x10\x3a\x25\x26\x11\x3b\x3c\x27\x12\x13\x3d\x28\x29\x14\x3e\x3f";
fn do_sha512_crypt(pass: &[u8], salt: &str, rounds: Option<u32>) -> Result<String> {
sha2_crypt(pass, salt, rounds, Sha512::new, SHA512_TRANSPOSE, SHA512_MAGIC)
}
pub fn hash<B: AsRef<[u8]>>(pass: B) -> Result<String> {
let saltstr = random::gen_salt_str(MAX_SALT_LEN)?;
do_sha512_crypt(pass.as_ref(), &saltstr, None)
}
fn parse_sha512_hash(hash: &str) -> Result<HashSetup> {
parse_sha2_hash(hash, SHA512_MAGIC)
}
pub fn hash_with<'a, IHS, B>(param: IHS, pass: B) -> Result<String>
where IHS: IntoHashSetup<'a>, B: AsRef<[u8]>
{
sha2_hash_with(IHS::into_hash_setup(param, parse_sha512_hash)?, pass.as_ref(), do_sha512_crypt)
}
pub fn verify<B: AsRef<[u8]>>(pass: B, hash: &str) -> bool {
consteq(hash, hash_with(hash, pass))
}
#[cfg(test)]
mod tests {
use ::HashSetup;
#[test]
fn custom() {
assert_eq!(super::hash_with(
"$6$rounds=11531$G/gkPn17kHYo0gTF$Kq.uZBHlSBXyzsOJXtxJruOOH4yc0Is13\
uY7yK0PvAvXxbvc1w8DO1RzREMhKsc82K/Jh8OquV8FZUlreYPJk1", "test").unwrap(),
"$6$rounds=11531$G/gkPn17kHYo0gTF$Kq.uZBHlSBXyzsOJXtxJruOOH4yc0Is13\
uY7yK0PvAvXxbvc1w8DO1RzREMhKsc82K/Jh8OquV8FZUlreYPJk1");
assert_eq!(super::hash_with(HashSetup { salt: Some("G/gkPn17kHYo0gTF"), rounds: Some(11531) }, "test").unwrap(),
"$6$rounds=11531$G/gkPn17kHYo0gTF$Kq.uZBHlSBXyzsOJXtxJruOOH4yc0Is13\
uY7yK0PvAvXxbvc1w8DO1RzREMhKsc82K/Jh8OquV8FZUlreYPJk1");
}
#[test]
fn implicit_dflt_rounds() {
assert_eq!(super::hash_with(
"$6$G/gkPn17kHYo0gTF$xhDFU0QYExdMH2ghOWKrrVtu1BuTpNMSJURCXk43.\
EYekmK8iwV6RNqftUUC8mqDel1J7m3JEbUkbu4YyqSyv/", "test").unwrap(),
"$6$G/gkPn17kHYo0gTF$xhDFU0QYExdMH2ghOWKrrVtu1BuTpNMSJURCXk43.\
EYekmK8iwV6RNqftUUC8mqDel1J7m3JEbUkbu4YyqSyv/");
}
}