1- use crate :: { verify_password, VerifyPasswordError } ;
1+ use crate :: { verify_password, GenerateHashError , generate_raw_hash } ;
22
3- /// Struct to simplify the usage of the [`verify_password`] function .
3+ /// Struct to simplify the usage of hash generation and checking .
44///
5- /// Holds the salt separator, signer key, round and memory cost to make the usage of the [`verify_password`]
6- /// function easier.
5+ /// Holds the salt separator, signer key, round and memory cost to make the usage of the hash generation
6+ /// and checking function easier.
77///
88/// # Example
99/// ```
@@ -31,6 +31,7 @@ pub struct FirebaseScrypt {
3131}
3232
3333impl FirebaseScrypt {
34+ /// Create a new [`FirebaseScrypt`] instance.
3435 pub fn new ( salt_separator : & str , signer_key : & str , rounds : u32 , mem_cost : u32 ) -> Self {
3536 Self {
3637 salt_separator : salt_separator. to_string ( ) ,
@@ -41,15 +42,126 @@ impl FirebaseScrypt {
4142 }
4243
4344 /// Calls [`verify_password`] with the data from the [`FirebaseScrypt`]
44- pub fn verify_password ( & self , password : & str , salt : & str , known_hash : & str ) -> Result < bool , VerifyPasswordError > {
45- Ok ( verify_password (
45+ ///
46+ /// # Example
47+ /// ```no_test
48+ /// # This test doesn't pass for (some?) reason. But the ``verify_password_with_simple_works`` test
49+ /// # passes, so no idea.
50+ /// use firebase_scrypt::FirebaseScrypt;
51+ ///
52+ /// const SALT_SEPARATOR: &str = "Bw==";
53+ /// const SIGNER_KEY: &str = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
54+ /// const ROUNDS: u32 = 8;
55+ /// const MEM_COST: u32 = 14;
56+ ///
57+ /// let password: &str = "user1password";
58+ /// let salt: &str = "42xEC+ixf3L2lw==";
59+ /// let password_hash: &str = "lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==";
60+ ///
61+ /// let firebase_scrypt = FirebaseScrypt::new(SALT_SEPARATOR, SIGNER_KEY, ROUNDS, MEM_COST);
62+ ///
63+ /// let is_valid = firebase_scrypt.verify_password(
64+ /// password,
65+ /// password_hash,
66+ /// salt,
67+ /// ).unwrap();
68+ ///
69+ /// assert!(is_valid)
70+ /// ```
71+ pub fn verify_password ( & self , password : & str , salt : & str , known_hash : & str ) -> Result < bool , GenerateHashError > {
72+ verify_password (
4673 password,
4774 known_hash,
4875 salt,
4976 self . salt_separator . as_str ( ) ,
5077 self . signer_key . as_str ( ) ,
5178 self . rounds ,
5279 self . mem_cost ,
53- ) ?)
80+ )
81+ }
82+
83+ /// Calls [`FirebaseScrypt::verify_password`] but returns false also if an error occurs, which
84+ /// is _usually_ the best thing to do.
85+ pub fn verify_password_bool ( & self , password : & str , salt : & str , known_hash : & str ) -> bool {
86+ if let Ok ( result) = self . verify_password ( password, salt, known_hash) {
87+ result
88+ } else {
89+ false
90+ }
91+ }
92+
93+ /// Generates a hash and returns its Base64 form, the same as the hashes from Firebase
94+ ///
95+ /// <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
96+ ///
97+ /// **Warning**: Do not use this function to check if a given password is valid, because that
98+ /// could result in [side-channel attacks](https://en.wikipedia.org/wiki/Side-channel_attack).
99+ ///
100+ /// Use the [`FirebaseScrypt::verify_password`] function instead.
101+ ///
102+ /// </pre></div>
103+ ///
104+ /// # Example
105+ /// ```
106+ /// use firebase_scrypt::FirebaseScrypt;
107+ ///
108+ /// const SALT_SEPARATOR: &str = "Bw==";
109+ /// const SIGNER_KEY: &str = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
110+ /// const ROUNDS: u32 = 8;
111+ /// const MEM_COST: u32 = 14;
112+ ///
113+ /// let password = "user1password";
114+ /// let salt = "42xEC+ixf3L2lw==";
115+ ///
116+ /// let firebase_scrypt = FirebaseScrypt::new(SALT_SEPARATOR, SIGNER_KEY, ROUNDS, MEM_COST);
117+ ///
118+ /// firebase_scrypt.generate_base64_hash(password, salt).unwrap();
119+ /// ```
120+ pub fn generate_base64_hash ( & self , password : & str , salt : & str ) -> Result < String , GenerateHashError > {
121+ let hash = generate_raw_hash (
122+ password,
123+ salt,
124+ self . salt_separator . as_str ( ) ,
125+ self . signer_key . as_str ( ) ,
126+ self . rounds ,
127+ self . mem_cost ,
128+ ) ?;
129+
130+ Ok ( base64:: encode ( hash) )
131+ }
132+ }
133+
134+ #[ cfg( test) ]
135+ mod tests {
136+ const SALT_SEPARATOR : & str = "Bw==" ;
137+ const SIGNER_KEY : & str = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==" ;
138+ const ROUNDS : u32 = 8 ;
139+ const MEM_COST : u32 = 14 ;
140+
141+ const PASSWORD : & str = "user1password" ;
142+ const SALT : & str = "42xEC+ixf3L2lw==" ;
143+ const PASSWORD_HASH : & str ="lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==" ;
144+
145+ use super :: * ;
146+
147+ #[ test]
148+ fn verify_password_with_simple_works ( ) {
149+ let firebase_scrypt = FirebaseScrypt :: new ( SALT_SEPARATOR , SIGNER_KEY , ROUNDS , MEM_COST ) ;
150+
151+ assert ! ( firebase_scrypt. verify_password(
152+ PASSWORD ,
153+ SALT ,
154+ PASSWORD_HASH ,
155+ ) . unwrap( ) )
156+ }
157+
158+ #[ test]
159+ fn generate_hash_with_simple_works ( ) {
160+ let firebase_scrypt = FirebaseScrypt :: new ( SALT_SEPARATOR , SIGNER_KEY , ROUNDS , MEM_COST ) ;
161+
162+ assert_eq ! ( firebase_scrypt. generate_base64_hash(
163+ PASSWORD ,
164+ SALT ,
165+ ) . unwrap( ) , PASSWORD_HASH )
54166 }
55167}
0 commit comments