Skip to content

Commit

Permalink
Add support for secp256k1 curve
Browse files Browse the repository at this point in the history
  • Loading branch information
erskingardner committed Jul 7, 2024
1 parent 7c486f1 commit 2acf903
Show file tree
Hide file tree
Showing 11 changed files with 425 additions and 15 deletions.
3 changes: 2 additions & 1 deletion benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const KDF_IDS: [KdfAlgorithm; 3] = [
KdfAlgorithm::HkdfSha384,
KdfAlgorithm::HkdfSha512,
];
const KEM_IDS: [KemAlgorithm; 5] = [
const KEM_IDS: [KemAlgorithm; 6] = [
KemAlgorithm::DhKemP256,
KemAlgorithm::DhKemK256,
KemAlgorithm::DhKemP384,
KemAlgorithm::DhKemP521,
KemAlgorithm::DhKem25519,
Expand Down
3 changes: 2 additions & 1 deletion benches/manual_benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ const KDF_IDS: [KdfAlgorithm; 3] = [
KdfAlgorithm::HkdfSha384,
KdfAlgorithm::HkdfSha512,
];
const KEM_IDS: [KemAlgorithm; 5] = [
const KEM_IDS: [KemAlgorithm; 6] = [
KemAlgorithm::DhKemP256,
KemAlgorithm::DhKemK256,
KemAlgorithm::DhKemP384,
KemAlgorithm::DhKemP521,
KemAlgorithm::DhKem25519,
Expand Down
1 change: 1 addition & 0 deletions fuzz/fuzz_targets/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fuzz_target!(|data: &[u8]| {
let mut hpke = Hpke::<hpke_rs_rust_crypto::HpkeRustCrypto>::new(
HpkeMode::Base,
KemAlgorithm::DhKemP256,
KemAlgorithm::DhKemK256,
KdfAlgorithm::HkdfSha256,
AeadAlgorithm::Aes128Gcm,
);
Expand Down
8 changes: 8 additions & 0 deletions rust_crypto_provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ p256 = { version = "0.13", features = [
"arithmetic",
"ecdh",
], default-features = false }
k256 = { version = "0.13", features = [
"arithmetic",
"ecdh",
], default-features = false }
p384 = { version = "0.13", default-features = false }
x25519-dalek = { version = "2", features = ["static_secrets"] }
chacha20poly1305 = { version = "0.10", default-features = false, features = [
Expand Down Expand Up @@ -46,6 +50,10 @@ harness = false
name = "bench_p256"
harness = false

[[bench]]
name = "bench_k256"
harness = false

[[bench]]
name = "bench_x25519"
harness = false
3 changes: 2 additions & 1 deletion rust_crypto_provider/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
![Rust Version][rustc-image]

This crate provides an implementation of the [HpkeCrypto] trait using native Rust crypto implementations
([hkdf], [sha2], [p256], [p384], [x25519-dalek], [chacha20poly1305], [aes-gcm]).
([hkdf], [sha2], [p256], [k256], [p384], [x25519-dalek], [chacha20poly1305], [aes-gcm]).

Please see [hpke-rs] for more details.

[hkdf]: https://docs.rs/hkdf/
[sha2]: https://docs.rs/sha2
[p256]: https://docs.rs/p256
[k256]: https://docs.rs/k256
[p384]: https://docs.rs/p384
[x25519-dalek]: https://docs.rs/x25519-dalek
[chacha20poly1305]: https://docs.rs/chacha20poly1305
Expand Down
42 changes: 42 additions & 0 deletions rust_crypto_provider/benches/bench_k256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
use hpke_rs_crypto::{types::KemAlgorithm, HpkeCrypto};
use hpke_rs_rust_crypto::*;

fn criterion_benchmark(c: &mut Criterion) {
c.bench_function(&format!("K256 Derive"), |b| {
b.iter_batched(
|| {
let sk = HpkeRustCrypto::kem_key_gen(
KemAlgorithm::DhKemK256,
&mut HpkeRustCrypto::prng(),
)
.unwrap();
let pk = HpkeRustCrypto::kem_derive_base(KemAlgorithm::DhKemK256, &sk).unwrap();
(sk.clone(), pk.clone())
},
|(sk, pk)| {
let _ = HpkeRustCrypto::kem_derive(KemAlgorithm::DhKemK256, &pk, &sk);
},
BatchSize::SmallInput,
)
});
c.bench_function(&format!("K256 Derive Base"), |b| {
b.iter_batched(
|| {
let sk = HpkeRustCrypto::kem_key_gen(
KemAlgorithm::DhKemK256,
&mut HpkeRustCrypto::prng(),
)
.unwrap();
sk.clone()
},
|sk| {
let _pk = HpkeRustCrypto::kem_derive_base(KemAlgorithm::DhKemK256, &sk).unwrap();
},
BatchSize::SmallInput,
)
});
}

criterion_group!(benches, criterion_benchmark,);
criterion_main!(benches);
50 changes: 39 additions & 11 deletions rust_crypto_provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,15 @@ use hpke_rs_crypto::{
CryptoRng, HpkeCrypto, HpkeTestRng, RngCore,
};
use p256::{
elliptic_curve::{ecdh::diffie_hellman, sec1::ToEncodedPoint},
PublicKey, SecretKey,
elliptic_curve::ecdh::diffie_hellman as p256diffie_hellman, PublicKey as p256PublicKey,
SecretKey as p256SecretKey,
};

use k256::{
elliptic_curve::{ecdh::diffie_hellman as k256diffie_hellman, sec1::ToEncodedPoint},
PublicKey as k256PublicKey, SecretKey as k256SecretKey,
};

use rand_core::SeedableRng;
use x25519_dalek::{PublicKey as X25519PublicKey, StaticSecret as X25519StaticSecret};

Expand Down Expand Up @@ -80,9 +86,19 @@ impl HpkeCrypto for HpkeRustCrypto {
.to_vec())
}
KemAlgorithm::DhKemP256 => {
let sk = SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
let pk = PublicKey::from_sec1_bytes(pk).map_err(|_| Error::KemInvalidPublicKey)?;
Ok(diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
let sk = p256SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
let pk =
p256PublicKey::from_sec1_bytes(pk).map_err(|_| Error::KemInvalidPublicKey)?;
Ok(p256diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
.raw_secret_bytes()
.as_slice()
.into())
}
KemAlgorithm::DhKemK256 => {
let sk = k256SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
let pk =
k256PublicKey::from_sec1_bytes(pk).map_err(|_| Error::KemInvalidPublicKey)?;
Ok(k256diffie_hellman(sk.to_nonzero_scalar(), pk.as_affine())
.raw_secret_bytes()
.as_slice()
.into())
Expand All @@ -103,7 +119,11 @@ impl HpkeCrypto for HpkeRustCrypto {
Ok(X25519PublicKey::from(&sk).as_bytes().to_vec())
}
KemAlgorithm::DhKemP256 => {
let sk = SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
let sk = p256SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
Ok(sk.public_key().to_encoded_point(false).as_bytes().into())
}
KemAlgorithm::DhKemK256 => {
let sk = k256SecretKey::from_slice(sk).map_err(|_| Error::KemInvalidSecretKey)?;
Ok(sk.public_key().to_encoded_point(false).as_bytes().into())
}
_ => Err(Error::UnknownKemAlgorithm),
Expand All @@ -116,16 +136,24 @@ impl HpkeCrypto for HpkeRustCrypto {
KemAlgorithm::DhKem25519 => Ok(X25519StaticSecret::random_from_rng(&mut *rng)
.to_bytes()
.to_vec()),
KemAlgorithm::DhKemP256 => {
Ok(SecretKey::random(&mut *rng).to_bytes().as_slice().into())
}
KemAlgorithm::DhKemP256 => Ok(p256SecretKey::random(&mut *rng)
.to_bytes()
.as_slice()
.into()),
KemAlgorithm::DhKemK256 => Ok(k256SecretKey::random(&mut *rng)
.to_bytes()
.as_slice()
.into()),
_ => Err(Error::UnknownKemAlgorithm),
}
}

fn kem_validate_sk(alg: KemAlgorithm, sk: &[u8]) -> Result<Vec<u8>, Error> {
match alg {
KemAlgorithm::DhKemP256 => SecretKey::from_slice(sk)
KemAlgorithm::DhKemP256 => p256SecretKey::from_slice(sk)
.map_err(|_| Error::KemInvalidSecretKey)
.map(|_| sk.into()),
KemAlgorithm::DhKemK256 => k256SecretKey::from_slice(sk)
.map_err(|_| Error::KemInvalidSecretKey)
.map(|_| sk.into()),
_ => Err(Error::UnknownKemAlgorithm),
Expand Down Expand Up @@ -188,7 +216,7 @@ impl HpkeCrypto for HpkeRustCrypto {
/// Returns an error if the KEM algorithm is not supported by this crypto provider.
fn supports_kem(alg: KemAlgorithm) -> Result<(), Error> {
match alg {
KemAlgorithm::DhKem25519 | KemAlgorithm::DhKemP256 => Ok(()),
KemAlgorithm::DhKem25519 | KemAlgorithm::DhKemP256 | KemAlgorithm::DhKemK256 => Ok(()),
_ => Err(Error::UnknownKemAlgorithm),
}
}
Expand Down
30 changes: 29 additions & 1 deletion src/dh_kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,36 @@ pub(super) fn derive_key_pair<Crypto: HpkeCrypto>(
ctr += 1;
}
}
KemAlgorithm::DhKemK256 => {
let mut ctr = 0u8;
// Do rejection sampling trying to find a valid key.
// It is expected that there aren't too many iteration and that
// the loop will always terminate.
loop {
let candidate = labeled_expand::<Crypto>(
alg.into(),
&dkp_prk,
suite_id,
"candidate",
&ctr.to_be_bytes(),
alg.private_key_len(),
);
if let Ok(sk) = &candidate {
if let Ok(sk) = Crypto::kem_validate_sk(alg, sk) {
break sk;
}
}
if ctr == u8::MAX {
// If we get here we lost. This should never happen.
return Err(Error::CryptoLibraryError(
"Unable to generate a valid K256 private key".to_string(),
));
}
ctr += 1;
}
}
_ => {
panic!("This should be unreachable. Only x25519 and P256 KEMs are implemented")
panic!("This should be unreachable. Only x25519, P256, and K256 KEMs are implemented")
}
};
Ok((Crypto::kem_derive_base(alg, &sk)?, sk))
Expand Down
5 changes: 5 additions & 0 deletions src/kem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub(crate) fn encaps<Crypto: HpkeCrypto>(
) -> Result<(Vec<u8>, Vec<u8>), Error> {
match alg {
KemAlgorithm::DhKemP256
| KemAlgorithm::DhKemK256
| KemAlgorithm::DhKemP384
| KemAlgorithm::DhKemP521
| KemAlgorithm::DhKem25519
Expand All @@ -36,6 +37,7 @@ pub(crate) fn decaps<Crypto: HpkeCrypto>(
) -> Result<Vec<u8>, Error> {
match alg {
KemAlgorithm::DhKemP256
| KemAlgorithm::DhKemK256
| KemAlgorithm::DhKemP384
| KemAlgorithm::DhKemP521
| KemAlgorithm::DhKem25519
Expand All @@ -51,6 +53,7 @@ pub(crate) fn auth_encaps<Crypto: HpkeCrypto>(
) -> Result<(Vec<u8>, Vec<u8>), Error> {
match alg {
KemAlgorithm::DhKemP256
| KemAlgorithm::DhKemK256
| KemAlgorithm::DhKemP384
| KemAlgorithm::DhKemP521
| KemAlgorithm::DhKem25519
Expand All @@ -68,6 +71,7 @@ pub(crate) fn auth_decaps<Crypto: HpkeCrypto>(
) -> Result<Vec<u8>, Error> {
match alg {
KemAlgorithm::DhKemP256
| KemAlgorithm::DhKemK256
| KemAlgorithm::DhKemP384
| KemAlgorithm::DhKemP521
| KemAlgorithm::DhKem25519
Expand All @@ -83,6 +87,7 @@ pub(crate) fn key_gen<Crypto: HpkeCrypto>(
) -> Result<(Vec<u8>, Vec<u8>), Error> {
match alg {
KemAlgorithm::DhKemP256
| KemAlgorithm::DhKemK256
| KemAlgorithm::DhKemP384
| KemAlgorithm::DhKemP521
| KemAlgorithm::DhKem25519
Expand Down
Loading

0 comments on commit 2acf903

Please sign in to comment.