Skip to content

Commit 741dd01

Browse files
committed
fix(bcrypt): update to upstream rust-bcrypt implementation
Fix panic in verify #579
1 parent 20bafa8 commit 741dd01

File tree

7 files changed

+6
-409
lines changed

7 files changed

+6
-409
lines changed

packages/bcrypt/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ version = "0.1.0"
88
crate-type = ["cdylib"]
99

1010
[dependencies]
11+
bcrypt = "0.10"
1112
blowfish = {version = "0.8", features = ["bcrypt"]}
1213
byteorder = "1"
1314
global_alloc = {path = "../../crates/alloc"}

packages/bcrypt/src/b64.rs

Lines changed: 1 addition & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,6 @@
1-
use crate::errors::{BcryptError, BcryptResult};
21
use phf::phf_map;
32
use radix64::STD;
43

5-
// Decoding table from bcrypt base64 to standard base64 and standard -> bcrypt
6-
// Bcrypt has its own base64 alphabet
7-
// ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
8-
static BCRYPT_TO_STANDARD: phf::Map<char, &'static str> = phf_map! {
9-
'/' => "B",
10-
'.' => "A",
11-
'1' => "3",
12-
'0' => "2",
13-
'3' => "5",
14-
'2' => "4",
15-
'5' => "7",
16-
'4' => "6",
17-
'7' => "9",
18-
'6' => "8",
19-
'9' => "/",
20-
'8' => "+",
21-
'A' => "C",
22-
'C' => "E",
23-
'B' => "D",
24-
'E' => "G",
25-
'D' => "F",
26-
'G' => "I",
27-
'F' => "H",
28-
'I' => "K",
29-
'H' => "J",
30-
'K' => "M",
31-
'J' => "L",
32-
'M' => "O",
33-
'L' => "N",
34-
'O' => "Q",
35-
'N' => "P",
36-
'Q' => "S",
37-
'P' => "R",
38-
'S' => "U",
39-
'R' => "T",
40-
'U' => "W",
41-
'T' => "V",
42-
'W' => "Y",
43-
'V' => "X",
44-
'Y' => "a",
45-
'X' => "Z",
46-
'Z' => "b",
47-
'a' => "c",
48-
'c' => "e",
49-
'b' => "d",
50-
'e' => "g",
51-
'd' => "f",
52-
'g' => "i",
53-
'f' => "h",
54-
'i' => "k",
55-
'h' => "j",
56-
'k' => "m",
57-
'j' => "l",
58-
'm' => "o",
59-
'l' => "n",
60-
'o' => "q",
61-
'n' => "p",
62-
'q' => "s",
63-
'p' => "r",
64-
's' => "u",
65-
'r' => "t",
66-
'u' => "w",
67-
't' => "v",
68-
'w' => "y",
69-
'v' => "x",
70-
'y' => "0",
71-
'x' => "z",
72-
'z' => "1",
73-
};
74-
754
static STANDARD_TO_BCRYPT: phf::Map<char, &'static str> = phf_map! {
765
'B' => "/",
776
'A' => ".",
@@ -157,51 +86,13 @@ pub fn encode(words: &[u8]) -> String {
15786
res
15887
}
15988

160-
// Can potentially panic if the hash given contains invalid characters
161-
pub fn decode(hash: &str) -> BcryptResult<Vec<u8>> {
162-
let mut res = String::with_capacity(hash.len());
163-
for ch in hash.chars() {
164-
if let Some(c) = BCRYPT_TO_STANDARD.get(&ch) {
165-
res.push_str(c);
166-
} else {
167-
return Err(BcryptError::DecodeError(ch, hash.to_string()));
168-
}
169-
}
170-
171-
// Bcrypt base64 has no padding but standard has
172-
// so we need to actually add padding ourselves
173-
if hash.len() % 4 > 0 {
174-
let padding = 4 - hash.len() % 4;
175-
for _ in 0..padding {
176-
res.push('=');
177-
}
178-
}
179-
180-
// safe unwrap: if we had non standard chars, it would have errored before
181-
Ok(STD.decode(&res).unwrap())
182-
}
183-
18489
#[cfg(test)]
18590
mod tests {
186-
use super::{decode, encode};
187-
188-
#[test]
189-
fn can_decode_bcrypt_base64() {
190-
let hash = "YETqZE6eb07wZEO";
191-
assert_eq!(
192-
"hello world",
193-
String::from_utf8_lossy(&decode(hash).unwrap())
194-
);
195-
}
91+
use super::encode;
19692

19793
#[test]
19894
fn can_encode_to_bcrypt_base64() {
19995
let expected = "YETqZE6eb07wZEO";
20096
assert_eq!(encode(b"hello world"), expected);
20197
}
202-
203-
#[test]
204-
fn decode_errors_with_unknown_char() {
205-
assert!(decode("YETqZE6e_b07wZEO").is_err());
206-
}
20798
}

packages/bcrypt/src/errors.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use std::error;
22
use std::fmt;
33
use std::io;
44

5-
use crate::lib_bcrypt::{MAX_COST, MIN_COST};
6-
75
/// Library generic result type.
86
pub type BcryptResult<T> = Result<T, BcryptError>;
97

@@ -12,13 +10,10 @@ pub type BcryptResult<T> = Result<T, BcryptError>;
1210
/// passwords
1311
pub enum BcryptError {
1412
Io(io::Error),
15-
CostNotAllowed(u32),
16-
InvalidPassword,
1713
InvalidVersion(String),
1814
InvalidCost(String),
1915
InvalidPrefix(String),
2016
InvalidHash(String),
21-
DecodeError(char, String),
2217
Rand(rand::Error),
2318
}
2419

@@ -40,18 +35,9 @@ impl fmt::Display for BcryptError {
4035
match *self {
4136
BcryptError::Io(ref err) => write!(f, "IO error: {}", err),
4237
BcryptError::InvalidCost(ref cost) => write!(f, "Invalid Cost: {}", cost),
43-
BcryptError::CostNotAllowed(ref cost) => write!(
44-
f,
45-
"Cost needs to be between {} and {}, got {}",
46-
MIN_COST, MAX_COST, cost
47-
),
48-
BcryptError::InvalidPassword => write!(f, "Invalid password: contains NULL byte"),
4938
BcryptError::InvalidVersion(ref v) => write!(f, "Invalid version: {}", v),
5039
BcryptError::InvalidPrefix(ref prefix) => write!(f, "Invalid Prefix: {}", prefix),
5140
BcryptError::InvalidHash(ref hash) => write!(f, "Invalid hash: {}", hash),
52-
BcryptError::DecodeError(ref c, ref s) => {
53-
write!(f, "Invalid base64 error in {}, char {}", c, s)
54-
}
5541
BcryptError::Rand(ref err) => write!(f, "Rand error: {}", err),
5642
}
5743
}
@@ -62,11 +48,8 @@ impl error::Error for BcryptError {
6248
match *self {
6349
BcryptError::Io(ref err) => Some(err),
6450
BcryptError::InvalidCost(_)
65-
| BcryptError::CostNotAllowed(_)
66-
| BcryptError::InvalidPassword
6751
| BcryptError::InvalidVersion(_)
6852
| BcryptError::InvalidPrefix(_)
69-
| BcryptError::DecodeError(_, _)
7053
| BcryptError::InvalidHash(_) => None,
7154
BcryptError::Rand(ref err) => Some(err),
7255
}

packages/bcrypt/src/hash_task.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ use napi::{
33
};
44
use napi_derive::napi;
55

6-
use crate::lib_bcrypt::hash;
7-
86
pub enum AsyncHashInput {
97
String(String),
108
Buffer(Ref<JsBufferValue>),
@@ -42,7 +40,7 @@ impl HashTask {
4240

4341
#[inline]
4442
pub fn hash(buf: &[u8], cost: u32) -> Result<String> {
45-
hash(buf, cost).map_err(|_| Error::from_status(Status::GenericFailure))
43+
bcrypt::hash(buf, cost).map_err(|_| Error::from_status(Status::GenericFailure))
4644
}
4745
}
4846

packages/bcrypt/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use crate::lib_bcrypt::{format_salt, gen_salt, Version};
1515
use crate::verify_task::VerifyTask;
1616

1717
mod b64;
18-
mod bcrypt;
1918
mod errors;
2019
mod hash_task;
2120
mod lib_bcrypt;

0 commit comments

Comments
 (0)