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
//! Seventh Edition Unix DES-based hash.
//
// Copyright (c) 2016 Ivan Nejgebauer <inejge@gmail.com>
//
// Licensed under the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>. This file may not be copied,
// modified, or distributed except according to the terms of this
// license.
//!
//! The original Unix password-hashing algorithm, extremely weak by
//! today's standards. It should be used for backward compatibility only.
//!
//! # Example
//!
//! ```
//! use pwhash::unix_crypt;
//!
//! assert_eq!(unix_crypt::hash_with("xO",
//!     "password").unwrap(), "xOAFZqRz5RduI");
//! assert_eq!(unix_crypt::verify("password","xOAFZqRz5RduI"),
//!     true);
//!     
//! ```
//!
//! # Parameters
//!
//! * __Password length__: effectively eight 7-bit characters; anything
//! longer is ignored.
//!
//! * __Salt length__: 2 characters (12 bits).
//!
//! * __Rounds__: 25 (fixed).
//!
//! # Hash Format
//!
//! The format of the hash is *`{salt}`*_`{checksum}`_, where:
//!
//! * *`{salt}`* is a 2-character Base64 encoding of the salt.
//!
//! * *`{checksum}`* is a 11-character Base64 encoding of the checksum.

use super::{Result, consteq};
use des_crypt::unix_crypt;
use random;

/// Salt length.
pub const SALT_LEN: usize = 2;

/// Hash a password with a randomly generated salt.
///
/// An error is returned if the system random number generator cannot
/// be opened.
#[deprecated(since="0.2.0", note="don't use this algorithm for new passwords")]
pub fn hash<B: AsRef<[u8]>>(pass: B) -> Result<String> {
    let saltstr = random::gen_salt_str(SALT_LEN)?;
    unix_crypt(pass.as_ref(), &saltstr)
}

/// Hash a password with a user-provided salt.
///
/// An error is returned if the salt is too short or contains an invalid
/// character.
#[deprecated(since="0.2.0", note="don't use this algorithm for new passwords")]
pub fn hash_with<B: AsRef<[u8]>>(salt: &str, pass: B) -> Result<String> {
    unix_crypt(pass.as_ref(), salt)
}

/// Verify that the hash corresponds to a password.
pub fn verify<B: AsRef<[u8]>>(pass: B, hash: &str) -> bool {
    consteq(hash, unix_crypt(pass.as_ref(), hash))
}

#[cfg(test)]
mod tests {
    #[test]
    #[allow(deprecated)]
    fn custom() {
	assert_eq!("aZGJuE6EXrjEE", super::hash_with("aZ", "test").unwrap());
	assert_eq!(super::verify("test", "aZGJuE6EXrjEE"), true);
	assert_eq!(super::verify("test", "aZFJuE6EXrjEE"), false);
	assert_eq!(super::verify("test", "!!"), false);
    }

    #[test]
    #[allow(deprecated)]
    #[should_panic(expected="value: EncodingError")]
    fn bad_salt_chars() {
	let _ = super::hash_with("!!", "test").unwrap();
    }

    #[test]
    #[allow(deprecated)]
    #[should_panic(expected="value: InsufficientLength")]
    fn short_salt() {
	let _ = super::hash_with("Z", "test").unwrap();
    }
}