Skip to content

Commit 78a0975

Browse files
committed
Add support for hkdf-sha512, pbkdf2-sha512, and scrypt.
1 parent ca1ef19 commit 78a0975

File tree

6 files changed

+134
-20
lines changed

6 files changed

+134
-20
lines changed

CONTRIBUTING.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ We love your input! We want to make contributing to this project as easy and tra
99
- Becoming a maintainer
1010

1111
## We Develop with Github
12+
1213
We use GitHub to host code, to track issues and feature requests, and to accept Pull Requests.
1314

14-
## Report Bugs using Github's [issues](https://github.com/briandk/transcriptase-atom/issues)
15+
## Report Bugs using Github's Issue Tracker
1516

1617
If you find bugs, mistakes, or inconsistencies in this project's code or documents, please let us know by [opening a new issue](./issues), but consider searching through existing issues first to check and see if the problem has already been reported. If it has, it never hurts to add a quick "+1" or "I have this problem too". This helps prioritize the most common problems and requests.
1718

@@ -24,12 +25,12 @@ If you find bugs, mistakes, or inconsistencies in this project's code or documen
2425
- A quick summary and/or background
2526
- Steps to reproduce
2627
- Be specific!
27-
- Give sample code if you can. [The stackoverflow bug report](http://stackoverflow.com/q/12488905/180626) includes sample code that *anyone* with a base R setup can run to reproduce what I was seeing
28+
- Give sample code if you can. [The stackoverflow bug report](http://stackoverflow.com/q/12488905/180626) includes sample code that _anyone_ with a base R setup can run to reproduce what I was seeing
2829
- What you expected would happen
2930
- What actually happens
3031
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
3132

32-
People *love* thorough bug reports. I'm not even kidding.
33+
People _love_ thorough bug reports. I'm not even kidding.
3334

3435
## Submit Code Changes through Pull Requests
3536

@@ -39,9 +40,9 @@ We ask that more significant improvements to the project be first proposed befor
3940

4041
### Use a Consistent Coding Style
4142

42-
* We indent using two spaces (soft tabs)
43-
* We ALWAYS put spaces after list items and method parameters ([1, 2, 3], not [1,2,3]), around operators (x += 1, not x+=1), and around hash arrows.
44-
* This is open-source software. Consider the people who will read your code, and make it look nice for them. It's sort of like driving a car: Perhaps you love doing donuts when you're alone, but with passengers the goal is to make the ride as smooth as possible.
43+
- We indent using two spaces (soft tabs)
44+
- We ALWAYS put spaces after list items and method parameters ([1, 2, 3], not [1,2,3]), around operators (x += 1, not x+=1), and around hash arrows.
45+
- This is open-source software. Consider the people who will read your code, and make it look nice for them. It's sort of like driving a car: Perhaps you love doing donuts when you're alone, but with passengers the goal is to make the ride as smooth as possible.
4546

4647
### Use [Github Flow](https://guides.github.com/introduction/flow/index.html) for Pull Requests
4748

@@ -61,5 +62,6 @@ In short, when you submit code changes, your submissions are understood to be av
6162
## References
6263

6364
Portions of this CONTRIBUTING.md document were adopted from best practices of a number of open source projects, including:
64-
* [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md)
65-
* [IPFS Contributing](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
65+
66+
- [Facebook's Draft](https://github.com/facebook/draft-js/blob/a9316a723f9e918afde44dea68b5f9f39b7d9b00/CONTRIBUTING.md)
67+
- [IPFS Contributing](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)

Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "bc-crypto"
3-
version = "0.7.0"
4-
edition = "2021"
3+
version = "0.8.0"
4+
edition = "2024"
55
description = "A uniform API for cryptographic primitives used in Blockchain Commons projects"
66
authors = ["Blockchain Commons"]
77
repository = "https://github.com/BlockchainCommons/bc-crypto-rust"
@@ -12,7 +12,7 @@ keywords = ["cryptography"]
1212
categories = ["cryptography"] # https://crates.io/category_slugs
1313

1414
[dependencies]
15-
bc-rand = "^0.3.0"
15+
bc-rand = "^0.4.0"
1616
rand = "^0.8.5"
1717
sha2 = "^0.10.6"
1818
hmac = "^0.12.1"
@@ -26,6 +26,7 @@ thiserror = "^1.0.48"
2626
anyhow = "^1.0.0"
2727
hex = "^0.4.3"
2828
ed25519-dalek = { version = "2.1.1", features = ["rand_core"] }
29+
scrypt = { version = "0.11.0", default-features = false }
2930

3031
[dev-dependencies]
3132
hex-literal = "^0.4.1"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
```toml
2929
[dependencies]
30-
bc-crypto = "0.7.0"
30+
bc-crypto = "0.8.0"
3131
```
3232

3333
## Version History

src/hash.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ pub fn pbkdf2_hmac_sha256(pass: impl AsRef<[u8]>, salt: impl AsRef<[u8]>, iterat
7878
key
7979
}
8080

81+
/// Computes the PBKDF2-HMAC-SHA-512 for the given password.
82+
pub fn pbkdf2_hmac_sha512(pass: impl AsRef<[u8]>, salt: impl AsRef<[u8]>, iterations: u32, key_len: usize) -> Vec<u8> {
83+
let mut key = vec![0u8; key_len];
84+
pbkdf2_hmac::<Sha512>(pass.as_ref(), salt.as_ref(), iterations, &mut key);
85+
key
86+
}
87+
8188
/// Computes the HKDF-HMAC-SHA-256 for the given key material.
8289
pub fn hkdf_hmac_sha256(key_material: impl AsRef<[u8]>, salt: impl AsRef<[u8]>, key_len: usize) -> Vec<u8> {
8390
let mut key = vec![0u8; key_len];
@@ -86,6 +93,14 @@ pub fn hkdf_hmac_sha256(key_material: impl AsRef<[u8]>, salt: impl AsRef<[u8]>,
8693
key
8794
}
8895

96+
/// Computes the HKDF-HMAC-SHA-512 for the given key material.
97+
pub fn hkdf_hmac_sha512(key_material: impl AsRef<[u8]>, salt: impl AsRef<[u8]>, key_len: usize) -> Vec<u8> {
98+
let mut key = vec![0u8; key_len];
99+
let hkdf = Hkdf::<Sha512>::new(Some(salt.as_ref()), key_material.as_ref());
100+
hkdf.expand(&[], &mut key).unwrap();
101+
key
102+
}
103+
89104
#[cfg(test)]
90105
mod tests {
91106
use hex_literal::hex;

src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![doc(html_root_url = "https://docs.rs/bc-crypto/0.7.0")]
1+
#![doc(html_root_url = "https://docs.rs/bc-crypto/0.8.0")]
22
#![warn(rust_2018_idioms)]
33

44
//! # Introduction
@@ -24,7 +24,7 @@
2424
//!
2525
//! ```toml
2626
//! [dependencies]
27-
//! bc-crypto = "0.7.0"
27+
//! bc-crypto = "0.8.0"
2828
//! ```
2929
3030
/// The `hash` module contains functions for hashing data.
@@ -43,7 +43,7 @@ pub use hash::{
4343
};
4444

4545
mod memzero;
46-
pub use memzero::{memzero, memzero_vec_vec_u8};
46+
pub use memzero::{ memzero, memzero_vec_vec_u8 };
4747

4848
mod symmetric_encryption;
4949
pub use symmetric_encryption::{
@@ -57,7 +57,7 @@ pub use symmetric_encryption::{
5757
};
5858

5959
mod public_key_encryption;
60-
pub use public_key_encryption:: {
60+
pub use public_key_encryption::{
6161
x25519_new_private_key_using,
6262
x25519_public_key_from_private_key,
6363
x25519_derive_private_key,
@@ -84,10 +84,7 @@ pub use ecdsa_keys::{
8484
};
8585

8686
mod ecdsa_signing;
87-
pub use ecdsa_signing::{
88-
ecdsa_sign,
89-
ecdsa_verify,
90-
};
87+
pub use ecdsa_signing::{ ecdsa_sign, ecdsa_verify };
9188

9289
mod schnorr_signing;
9390
pub use schnorr_signing::{
@@ -109,6 +106,9 @@ pub use ed25519_signing::{
109106
ED25519_SIGNATURE_SIZE,
110107
};
111108

109+
mod scrypt;
110+
pub use scrypt::{ scrypt, scrypt_opt };
111+
112112
#[cfg(test)]
113113
mod tests {
114114
#[test]

src/scrypt.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use scrypt::scrypt as scrypt_hash;
2+
3+
/// Computes the scrypt key derivation function using recommended parameters.
4+
///
5+
/// # Arguments
6+
///
7+
/// * `pass` - The password or passphrase as a byte slice.
8+
/// * `salt` - The salt as a byte slice.
9+
/// * `output_len` - The desired length of the derived key in bytes. Must be greater than 9 and less than or equal to 64.
10+
///
11+
/// # Returns
12+
///
13+
/// A `Vec<u8>` containing the derived key of the specified length.
14+
///
15+
/// # Panics
16+
///
17+
/// Panics if the scrypt function fails or if the output length is invalid.
18+
///
19+
/// # Examples
20+
///
21+
/// ```
22+
/// use bc_crypto::scrypt;
23+
/// let key = scrypt(b"password", b"salt", 32);
24+
/// assert_eq!(key.len(), 32);
25+
/// ```
26+
pub fn scrypt(
27+
pass: impl AsRef<[u8]>,
28+
salt: impl AsRef<[u8]>,
29+
output_len: usize, // Must be greater than `9` and less than or equal to `64`
30+
) -> Vec<u8> {
31+
let params = scrypt::Params::recommended();
32+
let mut output = vec![0u8; output_len];
33+
scrypt_hash(pass.as_ref(), salt.as_ref(), &params, &mut output)
34+
.expect("scrypt failed");
35+
output
36+
}
37+
38+
pub fn scrypt_opt(
39+
pass: impl AsRef<[u8]>,
40+
salt: impl AsRef<[u8]>,
41+
output_len: usize, // Must be greater than `9` and less than or equal to `64`
42+
log_n: u8, // Must be less than `64`
43+
r: u32, // Must be greater than 0 and less than or equal to `4294967295`
44+
p: u32, // Must be greater than 0 and less than `4294967295`
45+
) -> Vec<u8> {
46+
let params = scrypt::Params::new(log_n, r, p, output_len)
47+
.expect("Invalid Scrypt parameters");
48+
let mut output = vec![0u8; output_len];
49+
scrypt_hash(pass.as_ref(), salt.as_ref(), &params, &mut output)
50+
.expect("scrypt failed");
51+
output
52+
}
53+
54+
#[cfg(test)]
55+
mod tests {
56+
use super::*;
57+
58+
#[test]
59+
fn test_scrypt_basic() {
60+
let pass = b"password";
61+
let salt = b"salt";
62+
let output = scrypt(pass, salt, 32);
63+
assert_eq!(output.len(), 32);
64+
// Scrypt should be deterministic for same input
65+
let output2 = scrypt(pass, salt, 32);
66+
assert_eq!(output, output2);
67+
}
68+
69+
#[test]
70+
fn test_scrypt_different_salt() {
71+
let pass = b"password";
72+
let salt1 = b"salt1";
73+
let salt2 = b"salt2";
74+
let out1 = scrypt(pass, salt1, 32);
75+
let out2 = scrypt(pass, salt2, 32);
76+
assert_ne!(out1, out2);
77+
}
78+
79+
#[test]
80+
fn test_scrypt_opt_basic() {
81+
let pass = b"password";
82+
let salt = b"salt";
83+
let output = scrypt_opt(pass, salt, 32, 15, 8, 1);
84+
assert_eq!(output.len(), 32);
85+
}
86+
87+
#[test]
88+
fn test_scrypt_output_length() {
89+
let pass = b"password";
90+
let salt = b"salt";
91+
for len in [16, 24, 32, 64] {
92+
let output = scrypt(pass, salt, len);
93+
assert_eq!(output.len(), len);
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)