Skip to content

Commit f35d0c1

Browse files
authored
Clean the hash and salt (#2)
2 parents f021644 + 4d7ae4b commit f35d0c1

File tree

4 files changed

+64
-43
lines changed

4 files changed

+64
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ repository = "https://github.com/Techie-Pi/firebase-scrypt-rust"
55
homepage = "https://github.com/Techie-Pi/firebase-scrypt-rust"
66
documentation = "https://github.com/Techie-Pi/firebase-scrypt-rust"
77
readme = "README.md"
8-
version = "0.2.0"
8+
version = "0.2.1"
99
edition = "2021"
1010
license = "MIT"
1111
rust-version = "1.59"

src/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl From<InvalidOutputLen> for DerivedKeyError {
2929

3030
#[derive(Clone, Debug)]
3131
pub(crate) enum EncryptError {
32-
StreamCipher(StreamCipherError)
32+
StreamCipher(StreamCipherError),
3333
}
3434

3535
impl From<StreamCipherError> for EncryptError {

src/lib.rs

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626
//! assert!(firebase_scrypt.verify_password(password, salt, password_hash).unwrap())
2727
//! ```
2828
29-
use aes::{Aes256};
30-
use aes::cipher::{KeyIvInit, StreamCipher};
29+
use crate::errors::{DerivedKeyError, EncryptError, GenerateHashError};
30+
use aes::{
31+
cipher::{KeyIvInit, StreamCipher},
32+
Aes256,
33+
};
3134
use constant_time_eq::constant_time_eq;
32-
use ctr::{Ctr128BE};
35+
use ctr::Ctr128BE;
3336
use scrypt::Params;
34-
use crate::errors::{DerivedKeyError, EncryptError, GenerateHashError};
3537

3638
pub mod errors;
3739
#[cfg(feature = "simple")]
@@ -42,6 +44,10 @@ pub use simple::FirebaseScrypt;
4244

4345
const IV: [u8; 16] = *b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
4446

47+
fn clean(a: &str) -> String {
48+
a.replace("-", "+").replace("_", "/")
49+
}
50+
4551
fn generate_derived_key<'a>(
4652
password: &'a str,
4753
salt: &'a str,
@@ -61,12 +67,7 @@ fn generate_derived_key<'a>(
6167
let params = Params::new(log2_n as u8, rounds, p)?;
6268

6369
let mut result = [0u8; 64];
64-
scrypt::scrypt(
65-
password,
66-
salt.as_slice(),
67-
&params,
68-
&mut result
69-
)?;
70+
scrypt::scrypt(password, salt.as_slice(), &params, &mut result)?;
7071

7172
Ok(result)
7273
}
@@ -75,8 +76,7 @@ fn encrypt(signer_key: &[u8], key: [u8; 32]) -> Result<Vec<u8>, EncryptError> {
7576
let mut cipher = Ctr128BE::<Aes256>::new(&key.into(), &IV.into());
7677

7778
let mut buffer = vec![0u8; signer_key.len()];
78-
cipher
79-
.apply_keystream_b2b(signer_key, &mut buffer)?;
79+
cipher.apply_keystream_b2b(signer_key, &mut buffer)?;
8080

8181
Ok(buffer)
8282
}
@@ -120,9 +120,13 @@ pub fn verify_password(
120120
rounds: u32,
121121
mem_cost: u32,
122122
) -> Result<bool, GenerateHashError> {
123-
let password_hash = generate_raw_hash(password, salt, salt_separator, signer_key, rounds, mem_cost)?;
123+
let password_hash =
124+
generate_raw_hash(password, salt, salt_separator, signer_key, rounds, mem_cost)?;
124125

125-
Ok(constant_time_eq(password_hash.as_slice(), base64::decode(known_hash)?.as_slice()))
126+
Ok(constant_time_eq(
127+
password_hash.as_slice(),
128+
base64::decode(clean(known_hash))?.as_slice(),
129+
))
126130
}
127131

128132
/// Generates a hash in the form of a [`Vec<u8>`]
@@ -164,7 +168,8 @@ pub fn generate_raw_hash(
164168
rounds: u32,
165169
mem_cost: u32,
166170
) -> Result<Vec<u8>, GenerateHashError> {
167-
let derived_key = generate_derived_key(password, salt, salt_separator, rounds, mem_cost)?;
171+
let derived_key =
172+
generate_derived_key(password, &clean(salt), salt_separator, rounds, mem_cost)?;
168173
let signer_key = base64::decode(signer_key)?;
169174

170175
let result = encrypt(signer_key.as_slice(), derived_key[..32].try_into().unwrap())?;
@@ -174,13 +179,15 @@ pub fn generate_raw_hash(
174179
#[cfg(test)]
175180
mod tests {
176181
const SALT_SEPARATOR: &str = "Bw==";
177-
const SIGNER_KEY: &str = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
182+
const SIGNER_KEY: &str =
183+
"jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
178184
const ROUNDS: u32 = 8;
179185
const MEM_COST: u32 = 14;
180186

181187
const PASSWORD: &str = "user1password";
182188
const SALT: &str = "42xEC+ixf3L2lw==";
183-
const PASSWORD_HASH: &str ="lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==";
189+
const PASSWORD_HASH: &str =
190+
"lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==";
184191

185192
use super::*;
186193

@@ -194,27 +201,30 @@ mod tests {
194201
SIGNER_KEY,
195202
ROUNDS,
196203
MEM_COST
197-
).unwrap())
204+
)
205+
.unwrap())
198206
}
199207

200208
#[test]
201209
fn generate_hash_works() {
202-
assert_eq!(base64::encode(generate_raw_hash(
203-
PASSWORD,
204-
SALT,
205-
SALT_SEPARATOR,
206-
SIGNER_KEY,
207-
ROUNDS,
208-
MEM_COST,
209-
).unwrap()), PASSWORD_HASH)
210+
assert_eq!(
211+
base64::encode(
212+
generate_raw_hash(PASSWORD, SALT, SALT_SEPARATOR, SIGNER_KEY, ROUNDS, MEM_COST,)
213+
.unwrap()
214+
),
215+
PASSWORD_HASH
216+
)
210217
}
211218

212219
#[test]
213220
fn encrypt_works() {
214221
let param_1 = b"randomrandomrandomrandomrandomrandomrandom";
215222
let param_2 = b"12345678901234567890123456789012";
216223

217-
assert_eq!(hex::encode(encrypt(param_1, *param_2).unwrap()), "09f509fa3d09cde568f80709416681e4ed5d9677ca8b4807a932869ba3fd057be3606c2940877850ed96");
224+
assert_eq!(
225+
hex::encode(encrypt(param_1, *param_2).unwrap()),
226+
"09f509fa3d09cde568f80709416681e4ed5d9677ca8b4807a932869ba3fd057be3606c2940877850ed96"
227+
);
218228
}
219229

220230
#[test]

src/simple.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{verify_password, GenerateHashError, generate_raw_hash};
1+
use crate::{generate_raw_hash, verify_password, GenerateHashError};
22

33
/// Struct to simplify the usage of hash generation and checking.
44
///
@@ -68,7 +68,12 @@ impl FirebaseScrypt {
6868
///
6969
/// assert!(is_valid)
7070
/// ```
71-
pub fn verify_password(&self, password: &str, salt: &str, known_hash: &str) -> Result<bool, GenerateHashError> {
71+
pub fn verify_password(
72+
&self,
73+
password: &str,
74+
salt: &str,
75+
known_hash: &str,
76+
) -> Result<bool, GenerateHashError> {
7277
verify_password(
7378
password,
7479
known_hash,
@@ -117,7 +122,11 @@ impl FirebaseScrypt {
117122
///
118123
/// firebase_scrypt.generate_base64_hash(password, salt).unwrap();
119124
/// ```
120-
pub fn generate_base64_hash(&self, password: &str, salt: &str) -> Result<String, GenerateHashError> {
125+
pub fn generate_base64_hash(
126+
&self,
127+
password: &str,
128+
salt: &str,
129+
) -> Result<String, GenerateHashError> {
121130
let hash = generate_raw_hash(
122131
password,
123132
salt,
@@ -134,34 +143,36 @@ impl FirebaseScrypt {
134143
#[cfg(test)]
135144
mod tests {
136145
const SALT_SEPARATOR: &str = "Bw==";
137-
const SIGNER_KEY: &str = "jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
146+
const SIGNER_KEY: &str =
147+
"jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==";
138148
const ROUNDS: u32 = 8;
139149
const MEM_COST: u32 = 14;
140150

141151
const PASSWORD: &str = "user1password";
142152
const SALT: &str = "42xEC+ixf3L2lw==";
143-
const PASSWORD_HASH: &str ="lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==";
153+
const PASSWORD_HASH: &str =
154+
"lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==";
144155

145156
use super::*;
146157

147158
#[test]
148159
fn verify_password_with_simple_works() {
149160
let firebase_scrypt = FirebaseScrypt::new(SALT_SEPARATOR, SIGNER_KEY, ROUNDS, MEM_COST);
150161

151-
assert!(firebase_scrypt.verify_password(
152-
PASSWORD,
153-
SALT,
154-
PASSWORD_HASH,
155-
).unwrap())
162+
assert!(firebase_scrypt
163+
.verify_password(PASSWORD, SALT, PASSWORD_HASH,)
164+
.unwrap())
156165
}
157166

158167
#[test]
159168
fn generate_hash_with_simple_works() {
160169
let firebase_scrypt = FirebaseScrypt::new(SALT_SEPARATOR, SIGNER_KEY, ROUNDS, MEM_COST);
161170

162-
assert_eq!(firebase_scrypt.generate_base64_hash(
163-
PASSWORD,
164-
SALT,
165-
).unwrap(), PASSWORD_HASH)
171+
assert_eq!(
172+
firebase_scrypt
173+
.generate_base64_hash(PASSWORD, SALT,)
174+
.unwrap(),
175+
PASSWORD_HASH
176+
)
166177
}
167178
}

0 commit comments

Comments
 (0)