mod bignum;
mod ed25519;
mod ed448;
mod mldsa;
mod mlkem;
mod named_curve;
mod p256;
mod p384;
mod pq_selftest;
mod rsa;
mod x25519;
mod x448;
use core::cmp::Ordering;
use crate::drbg::HmacDrbgSha256;
use crate::internal_alloc::Vec;
use bignum::BigUint;
#[cfg(not(feature = "hazardous-legacy-crypto"))]
use noxtls_core::Error;
use noxtls_core::Result;
pub use ed25519::{
noxtls_ed25519_generate_private_key_auto,
noxtls_ed25519_public_key_from_subject_public_key_info, noxtls_ed25519_verify,
Ed25519PrivateKey, Ed25519PublicKey,
};
pub use ed448::{
noxtls_ed448_generate_private_key_auto, noxtls_ed448_public_key_from_subject_public_key_info,
noxtls_ed448_verify, Ed448PrivateKey, Ed448PublicKey,
};
pub use mldsa::{
noxtls_mldsa_generate_keypair_auto, noxtls_mldsa_public_key_from_subject_public_key_info,
noxtls_mldsa_verify, MlDsaPrivateKey, MlDsaPublicKey, OID_ID_MLDSA65,
};
pub use mlkem::{
noxtls_mlkem_decapsulate, noxtls_mlkem_encapsulate_auto, noxtls_mlkem_generate_keypair_auto,
noxtls_mlkem_generate_keypair_auto_for_parameter_set, MlKemParameterSet, MlKemPrivateKey,
MlKemPublicKey, MLKEM1024_CIPHERTEXT_LEN, MLKEM1024_PRIVATE_KEY_LEN, MLKEM1024_PUBLIC_KEY_LEN,
MLKEM512_CIPHERTEXT_LEN, MLKEM512_PRIVATE_KEY_LEN, MLKEM512_PUBLIC_KEY_LEN,
MLKEM_CIPHERTEXT_LEN, MLKEM_PRIVATE_KEY_LEN, MLKEM_PUBLIC_KEY_LEN, MLKEM_SHARED_SECRET_LEN,
};
pub use named_curve::{
noxtls_named_curve_from_mbedtls_name, noxtls_named_curve_info,
noxtls_named_ec_generate_private_key_auto, noxtls_named_ecdh_shared_secret,
noxtls_named_ecdsa_sign_digest, noxtls_named_ecdsa_verify_digest,
noxtls_secp256k1_ecdsa_sign_sha256, noxtls_secp521r1_ecdsa_sign_sha512, NamedCurve,
NamedCurveInfo, NamedEcPrivateKey, NamedEcPublicKey, NOXTLS_MBEDTLS_ECC_CURVES,
};
pub use p256::{
noxtls_p256_ecdh_shared_secret, noxtls_p256_ecdsa_sign_digest,
noxtls_p256_ecdsa_sign_digest_auto, noxtls_p256_ecdsa_sign_sha256,
noxtls_p256_ecdsa_sign_sha256_auto, noxtls_p256_ecdsa_verify_digest,
noxtls_p256_ecdsa_verify_sha256, noxtls_p256_generate_private_key_auto, P256PrivateKey,
P256PublicKey,
};
pub use p384::{
noxtls_p384_ecdh_shared_secret, noxtls_p384_ecdsa_sign_digest,
noxtls_p384_ecdsa_sign_digest_auto, noxtls_p384_ecdsa_sign_sha384,
noxtls_p384_ecdsa_sign_sha384_auto, noxtls_p384_ecdsa_verify_digest,
noxtls_p384_ecdsa_verify_sha384, noxtls_p384_generate_private_key_auto, P384PrivateKey,
P384PublicKey,
};
pub use pq_selftest::noxtls_run_pq_self_tests;
#[cfg(feature = "hazardous-legacy-crypto")]
pub use rsa::{noxtls_rsa_generate_keypair_auto, noxtls_rsa_generate_keypair_with_exponent_auto};
pub use rsa::{
noxtls_rsa_generate_keypair_secure_auto, noxtls_rsa_generate_keypair_with_policy_auto,
noxtls_rsaes_oaep_sha256_decrypt, noxtls_rsaes_oaep_sha256_decrypt_crt_only,
noxtls_rsaes_oaep_sha256_encrypt_auto, noxtls_rsaes_pkcs1_v15_decrypt,
noxtls_rsaes_pkcs1_v15_decrypt_crt_only, noxtls_rsaes_pkcs1_v15_encrypt_auto,
noxtls_rsassa_pss_sha256_sign, noxtls_rsassa_pss_sha256_sign_auto,
noxtls_rsassa_pss_sha256_verify, noxtls_rsassa_pss_sha384_sign,
noxtls_rsassa_pss_sha384_sign_auto, noxtls_rsassa_pss_sha384_verify, noxtls_rsassa_pss_sign,
noxtls_rsassa_pss_verify, noxtls_rsassa_sha1_sign, noxtls_rsassa_sha1_verify,
noxtls_rsassa_sha256_sign, noxtls_rsassa_sha256_verify, noxtls_rsassa_sha384_sign,
noxtls_rsassa_sha384_verify, noxtls_rsassa_sha512_sign, noxtls_rsassa_sha512_verify,
RsaKeySizePolicy, RsaPrivateKey, RsaPssHashAlgorithm, RsaPublicKey,
};
pub use x25519::{
noxtls_x25519, noxtls_x25519_basepoint, noxtls_x25519_generate_private_key_auto,
noxtls_x25519_shared_secret, X25519PrivateKey, X25519PublicKey,
};
#[cfg(feature = "hazardous-legacy-crypto")]
pub use x448::noxtls_x448_generate_private_key_auto;
#[cfg(feature = "hazardous-legacy-crypto")]
pub use x448::{noxtls_x448, noxtls_x448_basepoint, noxtls_x448_shared_secret};
pub use x448::{X448PrivateKey, X448PublicKey};
fn noxtls_parse_ffdhe_value(value: &[u8], label: &'static str) -> Result<BigUint> {
if value.is_empty() {
return Err(Error::InvalidLength(label));
}
Ok(BigUint::from_be_bytes(value))
}
fn noxtls_validate_ffdhe_prime(prime: &BigUint) -> Result<()> {
if prime.cmp(&BigUint::from_u128(3)) != Ordering::Greater || !prime.is_odd() {
return Err(Error::CryptoFailure(
"ffdhe prime must be an odd integer greater than 3",
));
}
Ok(())
}
fn noxtls_validate_ffdhe_private(private_key: &BigUint, prime: &BigUint) -> Result<()> {
if private_key.cmp(&BigUint::from_u128(1)) != Ordering::Greater {
return Err(Error::CryptoFailure(
"ffdhe private key must be greater than 1",
));
}
let upper = prime.sub(&BigUint::from_u128(1));
if private_key.cmp(&upper) != Ordering::Less {
return Err(Error::CryptoFailure(
"ffdhe private key must be less than p - 1",
));
}
Ok(())
}
fn noxtls_validate_ffdhe_public(public_key: &BigUint, prime: &BigUint) -> Result<()> {
if public_key.cmp(&BigUint::from_u128(1)) != Ordering::Greater {
return Err(Error::CryptoFailure(
"ffdhe public key must be greater than 1",
));
}
let upper = prime.sub(&BigUint::from_u128(1));
if public_key.cmp(&upper) != Ordering::Less {
return Err(Error::CryptoFailure(
"ffdhe public key must be less than p - 1",
));
}
Ok(())
}
pub fn noxtls_ffdhe_public_key(
private_key: &[u8],
generator: &[u8],
prime: &[u8],
) -> Result<Vec<u8>> {
let p = noxtls_parse_ffdhe_value(prime, "ffdhe prime must not be empty")?;
let g = noxtls_parse_ffdhe_value(generator, "ffdhe generator must not be empty")?;
let x = noxtls_parse_ffdhe_value(private_key, "ffdhe private key must not be empty")?;
noxtls_validate_ffdhe_prime(&p)?;
noxtls_validate_ffdhe_private(&x, &p)?;
noxtls_validate_ffdhe_public(&g, &p)?;
Ok(BigUint::mod_exp(&g, &x, &p).to_be_bytes())
}
pub fn noxtls_ffdhe_shared_secret(
private_key: &[u8],
peer_public_key: &[u8],
prime: &[u8],
) -> Result<Vec<u8>> {
let p = noxtls_parse_ffdhe_value(prime, "ffdhe prime must not be empty")?;
let x = noxtls_parse_ffdhe_value(private_key, "ffdhe private key must not be empty")?;
let y = noxtls_parse_ffdhe_value(peer_public_key, "ffdhe peer public key must not be empty")?;
noxtls_validate_ffdhe_prime(&p)?;
noxtls_validate_ffdhe_private(&x, &p)?;
noxtls_validate_ffdhe_public(&y, &p)?;
Ok(BigUint::mod_exp(&y, &x, &p).to_be_bytes())
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum EccKeyAlgorithm {
Secp192R1,
Secp224R1,
P256,
P384,
P521,
Secp192K1,
Secp224K1,
Secp256K1,
BrainpoolP256R1,
BrainpoolP384R1,
BrainpoolP512R1,
X25519,
X448,
Ed25519,
Ed448,
}
#[derive(Debug, Clone)]
pub enum EccPrivateKey {
P256(P256PrivateKey),
P384(P384PrivateKey),
Named(NamedEcPrivateKey),
X25519(X25519PrivateKey),
X448(X448PrivateKey),
Ed25519(Ed25519PrivateKey),
Ed448(Ed448PrivateKey),
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum EccPublicKey {
P256(P256PublicKey),
P384(P384PublicKey),
Named(NamedEcPublicKey),
X25519(X25519PublicKey),
X448(X448PublicKey),
Ed25519(Ed25519PublicKey),
Ed448(Ed448PublicKey),
}
pub fn noxtls_ecc_generate_keypair_auto(
noxtls_algorithm: EccKeyAlgorithm,
drbg: &mut HmacDrbgSha256,
) -> Result<(EccPrivateKey, EccPublicKey)> {
match noxtls_algorithm {
EccKeyAlgorithm::Secp192R1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp192R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::Secp224R1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp224R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::P256 => {
let private = noxtls_p256_generate_private_key_auto(drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::P256(private), EccPublicKey::P256(public)))
}
EccKeyAlgorithm::P384 => {
let private = noxtls_p384_generate_private_key_auto(drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::P384(private), EccPublicKey::P384(public)))
}
EccKeyAlgorithm::P521 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp521R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::Secp192K1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp192K1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::Secp224K1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp224K1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::Secp256K1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::Secp256K1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::BrainpoolP256R1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::BrainpoolP256R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::BrainpoolP384R1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::BrainpoolP384R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::BrainpoolP512R1 => {
let private = noxtls_named_ec_generate_private_key_auto(NamedCurve::BrainpoolP512R1, drbg)?;
let public = private.public_key()?;
Ok((EccPrivateKey::Named(private), EccPublicKey::Named(public)))
}
EccKeyAlgorithm::X25519 => {
let private = noxtls_x25519_generate_private_key_auto(drbg)?;
let public = private.clone().public_key();
Ok((EccPrivateKey::X25519(private), EccPublicKey::X25519(public)))
}
#[cfg(feature = "hazardous-legacy-crypto")]
EccKeyAlgorithm::X448 => {
let private = noxtls_x448_generate_private_key_auto(drbg)?;
let public = private.clone().public_key();
Ok((EccPrivateKey::X448(private), EccPublicKey::X448(public)))
}
#[cfg(not(feature = "hazardous-legacy-crypto"))]
EccKeyAlgorithm::X448 => Err(Error::StateError(
"x448 operations are disabled by default; enable `hazardous-legacy-crypto` to use non-constant-time x448 implementation",
)),
EccKeyAlgorithm::Ed25519 => {
let private = noxtls_ed25519_generate_private_key_auto(drbg)?;
let public = private.verifying_key();
Ok((
EccPrivateKey::Ed25519(private),
EccPublicKey::Ed25519(public),
))
}
EccKeyAlgorithm::Ed448 => {
let private = noxtls_ed448_generate_private_key_auto(drbg)?;
let public = private.verifying_key();
Ok((
EccPrivateKey::Ed448(private),
EccPublicKey::Ed448(public),
))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ecc_keygen_includes_standard_named_weierstrass_curves() {
let algorithms = [
EccKeyAlgorithm::Secp192R1,
EccKeyAlgorithm::Secp224R1,
EccKeyAlgorithm::P384,
EccKeyAlgorithm::P521,
EccKeyAlgorithm::Secp192K1,
EccKeyAlgorithm::Secp224K1,
EccKeyAlgorithm::Secp256K1,
EccKeyAlgorithm::BrainpoolP256R1,
EccKeyAlgorithm::BrainpoolP384R1,
EccKeyAlgorithm::BrainpoolP512R1,
EccKeyAlgorithm::Ed448,
];
for algorithm in algorithms {
let mut drbg =
HmacDrbgSha256::noxtls_new(b"ecc-standard-curves-keygen-seed", b"nonce", b"pkc")
.expect("drbg init");
let (private, public) =
noxtls_ecc_generate_keypair_auto(algorithm, &mut drbg).expect("curve keygen");
match algorithm {
EccKeyAlgorithm::P384 => {
assert!(matches!(private, EccPrivateKey::P384(_)));
assert!(matches!(public, EccPublicKey::P384(_)));
}
EccKeyAlgorithm::Ed448 => {
assert!(matches!(private, EccPrivateKey::Ed448(_)));
assert!(matches!(public, EccPublicKey::Ed448(_)));
}
_ => {
assert!(matches!(private, EccPrivateKey::Named(_)));
assert!(matches!(public, EccPublicKey::Named(_)));
}
}
}
}
}