Skip to content

Commit 5d0369c

Browse files
authored
sha-crypt: simplify Base64 encoding (#728)
Composes the "simple" MCF API in terms of the existing Base64 APIs, and factors the Base64 encoding functions into those Base64 APIs.
1 parent 0ae86aa commit 5d0369c

File tree

4 files changed

+29
-81
lines changed

4 files changed

+29
-81
lines changed

sha-crypt/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ rust-version = "1.85"
1818

1919
[dependencies]
2020
sha2 = { version = "0.11.0-rc.2", default-features = false }
21-
base64ct = { version = "1.7.1", default-features = false }
21+
base64ct = { version = "1.7.1", default-features = false, features = ["alloc"] }
2222

2323
# optional dependencies
2424
mcf = { version = "0.2", optional = true, default-features = false, features = ["alloc", "base64"] }
@@ -27,7 +27,7 @@ subtle = { version = "2", optional = true, default-features = false }
2727

2828
[features]
2929
default = ["simple"]
30-
simple = ["base64ct/alloc", "dep:mcf", "dep:rand_core", "dep:subtle"]
30+
simple = ["dep:mcf", "dep:rand_core", "dep:subtle"]
3131

3232
[package.metadata.docs.rs]
3333
all-features = true

sha-crypt/src/b64.rs

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,13 @@
11
//! Base64 encoding support
22
3-
use crate::consts::{
4-
BLOCK_SIZE_SHA256, BLOCK_SIZE_SHA512, MAP_SHA256, MAP_SHA512, PW_SIZE_SHA256, PW_SIZE_SHA512,
3+
#![cfg(feature = "simple")]
4+
5+
use crate::{
6+
consts::{BLOCK_SIZE_SHA256, BLOCK_SIZE_SHA512, MAP_SHA256, MAP_SHA512, PW_SIZE_SHA256},
7+
errors::DecodeError,
58
};
69
use base64ct::{Base64ShaCrypt, Encoding};
710

8-
#[cfg(feature = "simple")]
9-
use crate::errors::DecodeError;
10-
11-
pub fn encode_sha512(source: &[u8]) -> [u8; PW_SIZE_SHA512] {
12-
let mut transposed = [0u8; BLOCK_SIZE_SHA512];
13-
for (i, &ti) in MAP_SHA512.iter().enumerate() {
14-
transposed[i] = source[ti as usize];
15-
}
16-
let mut buf = [0u8; PW_SIZE_SHA512];
17-
Base64ShaCrypt::encode(&transposed, &mut buf).unwrap();
18-
buf
19-
}
20-
21-
pub fn encode_sha256(source: &[u8]) -> [u8; PW_SIZE_SHA256] {
22-
let mut transposed = [0u8; BLOCK_SIZE_SHA256];
23-
for (i, &ti) in MAP_SHA256.iter().enumerate() {
24-
transposed[i] = source[ti as usize];
25-
}
26-
let mut buf = [0u8; PW_SIZE_SHA256];
27-
Base64ShaCrypt::encode(&transposed, &mut buf).unwrap();
28-
buf
29-
}
30-
31-
#[cfg(feature = "simple")]
3211
pub fn decode_sha512(source: &[u8]) -> Result<[u8; BLOCK_SIZE_SHA512], DecodeError> {
3312
const BUF_SIZE: usize = 86;
3413
let mut buf = [0u8; BUF_SIZE];
@@ -40,7 +19,6 @@ pub fn decode_sha512(source: &[u8]) -> Result<[u8; BLOCK_SIZE_SHA512], DecodeErr
4019
Ok(transposed)
4120
}
4221

43-
#[cfg(feature = "simple")]
4422
pub fn decode_sha256(source: &[u8]) -> Result<[u8; BLOCK_SIZE_SHA256], DecodeError> {
4523
let mut buf = [0u8; PW_SIZE_SHA256];
4624
Base64ShaCrypt::decode(source, &mut buf).unwrap();
@@ -51,41 +29,3 @@ pub fn decode_sha256(source: &[u8]) -> Result<[u8; BLOCK_SIZE_SHA256], DecodeErr
5129
}
5230
Ok(transposed)
5331
}
54-
55-
mod tests {
56-
#[cfg(feature = "simple")]
57-
#[test]
58-
fn test_encode_decode_sha512() {
59-
let original: [u8; 64] = [
60-
0x0b, 0x5b, 0xdf, 0x7d, 0x92, 0xe2, 0xfc, 0xbd, 0xab, 0x57, 0xcb, 0xf3, 0xe0, 0x03,
61-
0x16, 0x62, 0xd3, 0x6e, 0xa0, 0x57, 0x44, 0x8c, 0xca, 0x35, 0xec, 0x80, 0x75, 0x2a,
62-
0x37, 0xd4, 0xe6, 0xfa, 0xf7, 0xd7, 0x78, 0xf4, 0x8e, 0x0b, 0x3e, 0xab, 0x23, 0x05,
63-
0x15, 0xdd, 0x79, 0x14, 0x45, 0xac, 0x66, 0x60, 0x25, 0x94, 0x97, 0x5e, 0x0f, 0x7f,
64-
0x5f, 0xaf, 0x1a, 0xe5, 0x08, 0xe7, 0x7d, 0xd4,
65-
];
66-
67-
let e = super::encode_sha512(&original);
68-
let d = super::decode_sha512(&e).unwrap();
69-
70-
for i in 0..d.len() {
71-
assert_eq!(&original[i], &d[i]);
72-
}
73-
}
74-
75-
#[cfg(feature = "simple")]
76-
#[test]
77-
fn test_encode_decode_sha256() {
78-
let original: [u8; 32] = [
79-
0x0b, 0x5b, 0xdf, 0x7d, 0x92, 0xe2, 0xfc, 0xbd, 0xab, 0x57, 0xcb, 0xf3, 0xe0, 0x03,
80-
0x16, 0x62, 0xd3, 0x6e, 0xa0, 0x57, 0x44, 0x8c, 0xca, 0x35, 0xec, 0x80, 0x75, 0x2a,
81-
0x5f, 0xaf, 0x1a, 0xe5,
82-
];
83-
84-
let e = super::encode_sha256(&original);
85-
let d = super::decode_sha256(&e).unwrap();
86-
87-
for i in 0..d.len() {
88-
assert_eq!(&original[i], &d[i]);
89-
}
90-
}
91-
}

sha-crypt/src/consts.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ pub const BLOCK_SIZE_SHA256: usize = 32;
55
pub const BLOCK_SIZE_SHA512: usize = 64;
66

77
/// PWD part length of the password string of SHA256
8+
#[cfg(feature = "simple")]
89
pub const PW_SIZE_SHA256: usize = 43;
910

10-
/// PWD part length of the password string of SHA512
11-
pub const PW_SIZE_SHA512: usize = 86;
12-
1311
/// Maximum length of a salt
1412
#[cfg(feature = "simple")]
1513
pub const SALT_MAX_LEN: usize = 16;

sha-crypt/src/lib.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,18 @@ pub use crate::{
5252
};
5353

5454
use alloc::{string::String, vec::Vec};
55+
use base64ct::{Base64ShaCrypt, Encoding};
5556
use sha2::{Digest, Sha256, Sha512};
5657

5758
#[cfg(feature = "simple")]
5859
pub use crate::errors::{CheckError, DecodeError};
5960

61+
use crate::consts::{MAP_SHA256, MAP_SHA512};
62+
6063
#[cfg(feature = "simple")]
6164
use {
6265
crate::consts::SALT_MAX_LEN,
6366
alloc::string::ToString,
64-
base64ct::{Base64ShaCrypt, Encoding},
6567
rand_core::{OsRng, RngCore, TryRngCore},
6668
};
6769

@@ -283,7 +285,13 @@ pub fn sha256_crypt(
283285
/// - `Err(errors::CryptError)` otherwise
284286
pub fn sha512_crypt_b64(password: &[u8], salt: &[u8], params: &Sha512Params) -> String {
285287
let output = sha512_crypt(password, salt, params);
286-
String::from_utf8(b64::encode_sha512(&output).to_vec()).unwrap()
288+
289+
let mut transposed = [0u8; BLOCK_SIZE_SHA512];
290+
for (i, &ti) in MAP_SHA512.iter().enumerate() {
291+
transposed[i] = output[ti as usize];
292+
}
293+
294+
Base64ShaCrypt::encode_string(&transposed)
287295
}
288296

289297
/// Same as sha256_crypt except base64 representation will be returned.
@@ -299,7 +307,13 @@ pub fn sha512_crypt_b64(password: &[u8], salt: &[u8], params: &Sha512Params) ->
299307
/// - `Err(errors::CryptError)` otherwise
300308
pub fn sha256_crypt_b64(password: &[u8], salt: &[u8], params: &Sha256Params) -> String {
301309
let output = sha256_crypt(password, salt, params);
302-
String::from_utf8(b64::encode_sha256(&output).to_vec()).unwrap()
310+
311+
let mut transposed = [0u8; BLOCK_SIZE_SHA256];
312+
for (i, &ti) in MAP_SHA256.iter().enumerate() {
313+
transposed[i] = output[ti as usize];
314+
}
315+
316+
Base64ShaCrypt::encode_string(&transposed)
303317
}
304318

305319
/// Simple interface for generating a SHA512 password hash.
@@ -316,7 +330,7 @@ pub fn sha256_crypt_b64(password: &[u8], salt: &[u8], params: &Sha256Params) ->
316330
#[cfg(feature = "simple")]
317331
pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
318332
let salt = random_salt();
319-
let out = sha512_crypt(password.as_bytes(), salt.as_bytes(), params);
333+
let out = sha512_crypt_b64(password.as_bytes(), salt.as_bytes(), params);
320334

321335
let mut mcf_hash = mcf::PasswordHash::from_id(SHA512_MCF_ID).expect("should have valid ID");
322336

@@ -327,9 +341,7 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
327341
}
328342

329343
mcf_hash.push_str(&salt).expect("should have valid salt");
330-
331-
let s = String::from_utf8(b64::encode_sha512(&out).to_vec()).unwrap();
332-
mcf_hash.push_str(&s).expect("should have valid hash");
344+
mcf_hash.push_str(&out).expect("should have valid hash");
333345

334346
mcf_hash.into()
335347
}
@@ -348,7 +360,7 @@ pub fn sha512_simple(password: &str, params: &Sha512Params) -> String {
348360
#[cfg(feature = "simple")]
349361
pub fn sha256_simple(password: &str, params: &Sha256Params) -> String {
350362
let salt = random_salt();
351-
let out = sha256_crypt(password.as_bytes(), salt.as_bytes(), params);
363+
let out = sha256_crypt_b64(password.as_bytes(), salt.as_bytes(), params);
352364

353365
let mut mcf_hash = mcf::PasswordHash::from_id(SHA256_MCF_ID).expect("should have valid ID");
354366

@@ -359,9 +371,7 @@ pub fn sha256_simple(password: &str, params: &Sha256Params) -> String {
359371
}
360372

361373
mcf_hash.push_str(&salt).expect("should have valid salt");
362-
363-
let s = String::from_utf8(b64::encode_sha256(&out).to_vec()).unwrap();
364-
mcf_hash.push_str(&s).expect("should have valid hash");
374+
mcf_hash.push_str(&out).expect("should have valid hash");
365375

366376
mcf_hash.into()
367377
}

0 commit comments

Comments
 (0)