Skip to content

Commit 30c0f6d

Browse files
committed
use base64ct for sha-crypt base64 en-/decoding
1 parent 55df2a4 commit 30c0f6d

File tree

5 files changed

+64
-76
lines changed

5 files changed

+64
-76
lines changed

Cargo.lock

+8-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sha-crypt/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ sha2 = { version = "0.10", default-features = false }
2121
# optional dependencies
2222
rand = { version = "0.8", optional = true }
2323
subtle = { version = ">=2, <2.5", optional = true, default-features = false }
24+
base64ct = { git = "https://github.com/ibotty/rustcrypto-formats", branch = "shacrypt" }
2425

2526
[features]
2627
default = ["simple"]

sha-crypt/src/b64.rs

+23-46
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,41 @@
11
//! Base64 encoding support
22
3-
use crate::defs::{MAP, TAB};
3+
use crate::defs::{BLOCK_SIZE, MAP_SHA512, PW_SIZE_SHA512};
44
use alloc::vec::Vec;
5+
use base64ct::{Base64ShaCrypt, Encoding};
6+
57

68
#[cfg(feature = "simple")]
79
use crate::errors::DecodeError;
810

9-
pub fn encode(source: &[u8]) -> Vec<u8> {
10-
let mut out: Vec<u8> = vec![];
11-
for entry in &MAP {
12-
let mut w: usize = 0;
13-
if entry.3 > 2 {
14-
w |= source[entry.2 as usize] as usize;
15-
w <<= 8;
16-
w |= source[entry.1 as usize] as usize;
17-
w <<= 8;
18-
}
19-
w |= source[entry.0 as usize] as usize;
20-
21-
for _ in 0..entry.3 {
22-
out.push(TAB[(w & 0x3f) as usize]);
23-
w >>= 6;
24-
}
11+
pub fn encode_sha512(source: &[u8]) -> Vec<u8> {
12+
const BUF_SIZE: usize = PW_SIZE_SHA512;
13+
let mut transposed = [0u8; BLOCK_SIZE];
14+
for (i, &ti) in MAP_SHA512.iter().enumerate() {
15+
transposed[i] = source[ti as usize];
2516
}
26-
out
17+
let mut buf = [0u8; BUF_SIZE];
18+
Base64ShaCrypt::encode(&transposed, &mut buf).unwrap();
19+
buf.to_vec()
2720
}
2821

2922
#[cfg(feature = "simple")]
30-
pub fn decode(source: &[u8]) -> Result<Vec<u8>, DecodeError> {
31-
let mut out: [u8; 64] = [0; 64];
32-
33-
for iter in MAP.iter().enumerate() {
34-
let (i, entry) = iter;
35-
36-
let mut w: usize = 0;
37-
38-
for k in (0..entry.3).rev() {
39-
let byte = source.get(i * 4 + k as usize).ok_or(DecodeError)?;
40-
let pos = TAB.iter().position(|x| x == byte).ok_or(DecodeError)?;
41-
w <<= 6;
42-
w |= pos as usize;
43-
}
44-
45-
out[entry.0 as usize] = (w & 0xff) as u8;
46-
w >>= 8;
47-
48-
if entry.3 > 2 {
49-
out[entry.1 as usize] = (w & 0xff) as u8;
50-
w >>= 8;
51-
out[entry.2 as usize] = (w & 0xff) as u8;
52-
}
23+
pub fn decode_sha512(source: &[u8]) -> Result<Vec<u8>, DecodeError> {
24+
const BUF_SIZE: usize = 86;
25+
let mut buf = [0u8; BUF_SIZE];
26+
Base64ShaCrypt::decode(&source, &mut buf).map_err(|_| DecodeError)?;
27+
28+
let mut transposed = [0u8; BLOCK_SIZE];
29+
for (i, &ti) in MAP_SHA512.iter().enumerate() {
30+
transposed[ti as usize] = buf[i];
5331
}
54-
55-
Ok(out.to_vec())
32+
Ok(transposed.to_vec())
5633
}
5734

5835
mod tests {
5936
#[cfg(feature = "simple")]
6037
#[test]
61-
fn test_encode_decode() {
38+
fn test_encode_decode_sha512() {
6239
let original: [u8; 64] = [
6340
0x0b, 0x5b, 0xdf, 0x7d, 0x92, 0xe2, 0xfc, 0xbd, 0xab, 0x57, 0xcb, 0xf3, 0xe0, 0x03,
6441
0x16, 0x62, 0xd3, 0x6e, 0xa0, 0x57, 0x44, 0x8c, 0xca, 0x35, 0xec, 0x80, 0x75, 0x2a,
@@ -67,8 +44,8 @@ mod tests {
6744
0x5f, 0xaf, 0x1a, 0xe5, 0x08, 0xe7, 0x7d, 0xd4,
6845
];
6946

70-
let e = super::encode(&original);
71-
let d = super::decode(&e).unwrap();
47+
let e = super::encode_sha512(&original);
48+
let d = super::decode_sha512(&e).unwrap();
7249

7350
for i in 0..d.len() {
7451
assert_eq!(&original[i], &d[i]);

sha-crypt/src/defs.rs

+29-25
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
1-
/// Block size
1+
/// Block size for SHA512
22
pub const BLOCK_SIZE: usize = 64;
33

4+
/// PWD part length of the password string of sha-512
5+
pub const PW_SIZE_SHA512: usize = 86;
6+
47
/// Maximum length of a salt
58
#[cfg(feature = "simple")]
69
pub const SALT_MAX_LEN: usize = 16;
710

811
/// Encoding table.
12+
#[cfg(feature = "simple")]
913
pub static TAB: &[u8] = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
1014

11-
/// Inverse encoding map.
12-
pub const MAP: [(u8, u8, u8, u8); 22] = [
13-
(42, 21, 0, 4),
14-
(1, 43, 22, 4),
15-
(23, 2, 44, 4),
16-
(45, 24, 3, 4),
17-
(4, 46, 25, 4),
18-
(26, 5, 47, 4),
19-
(48, 27, 6, 4),
20-
(7, 49, 28, 4),
21-
(29, 8, 50, 4),
22-
(51, 30, 9, 4),
23-
(10, 52, 31, 4),
24-
(32, 11, 53, 4),
25-
(54, 33, 12, 4),
26-
(13, 55, 34, 4),
27-
(35, 14, 56, 4),
28-
(57, 36, 15, 4),
29-
(16, 58, 37, 4),
30-
(38, 17, 59, 4),
31-
(60, 39, 18, 4),
32-
(19, 61, 40, 4),
33-
(41, 20, 62, 4),
34-
(63, 0, 0, 2),
15+
/// Inverse encoding map for SHA512.
16+
pub const MAP_SHA512: [u8; 64] = [
17+
42, 21, 0,
18+
1, 43, 22,
19+
23, 2, 44,
20+
45, 24, 3,
21+
4, 46, 25,
22+
26, 5, 47,
23+
48, 27, 6,
24+
7, 49, 28,
25+
29, 8, 50,
26+
51, 30, 9,
27+
10, 52, 31,
28+
32, 11, 53,
29+
54, 33, 12,
30+
13, 55, 34,
31+
35, 14, 56,
32+
57, 36, 15,
33+
16, 58, 37,
34+
38, 17, 59,
35+
60, 39, 18,
36+
19, 61, 40,
37+
41, 20, 62,
38+
63,
3539
];

sha-crypt/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ pub fn sha512_crypt_b64(
193193
params: &Sha512Params,
194194
) -> Result<String, CryptError> {
195195
let output = sha512_crypt(password, salt, params)?;
196-
let r = String::from_utf8(b64::encode(&output))?;
196+
let r = String::from_utf8(b64::encode_sha512(&output))?;
197197
Ok(r)
198198
}
199199

@@ -228,7 +228,7 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> Result<String, Cr
228228
}
229229
result.push_str(&salt);
230230
result.push('$');
231-
let s = String::from_utf8(b64::encode(&out))?;
231+
let s = String::from_utf8(b64::encode_sha512(&out))?;
232232
result.push_str(&s);
233233
Ok(result)
234234
}
@@ -303,7 +303,7 @@ pub fn sha512_check(password: &str, hashed_value: &str) -> Result<(), CheckError
303303
Err(e) => return Err(CheckError::Crypt(e)),
304304
};
305305

306-
let hash = b64::decode(hash.as_bytes())?;
306+
let hash = b64::decode_sha512(hash.as_bytes())?;
307307

308308
use subtle::ConstantTimeEq;
309309
if output.ct_eq(&hash).into() {

0 commit comments

Comments
 (0)