Rust wrapper: add wolfssl::wolfcrypt::ecc module

This commit is contained in:
Josh Holtrop
2025-10-06 17:20:01 -04:00
parent 3f460b40bc
commit 883da3dd35
6 changed files with 1891 additions and 8 deletions

View File

@@ -122,7 +122,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id);
slot.
\return 0 Returned on success.
\return ECC_BAD_ARG_E Returned if rng or key evaluate to NULL
\return ECC_BAD_ARG_E Returned if key is NULL
\return BAD_FUNC_ARG Returned if the supplied key is not a valid ecc_key.
\return MEMORY_E Returned if there is an error allocating memory while
computing the public key
@@ -172,11 +172,10 @@ int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut);
an existing private component. If pubOut is supplied, the computed public
key is stored there, else it is stored in the supplied ecc_key public
component slot. The supplied rng, if non-NULL, is used to blind the private
key value used in the computation. If rng is NULL, an ephemeral rng is
instantiated internally.
key value used in the computation.
\return 0 Returned on success.
\return ECC_BAD_ARG_E Returned if rng or key evaluate to NULL
\return ECC_BAD_ARG_E Returned if key is NULL
\return BAD_FUNC_ARG Returned if the supplied key is not a valid ecc_key.
\return MEMORY_E Returned if there is an error allocating memory while
computing the public key

View File

@@ -4083,7 +4083,9 @@ int wc_ecc_mulmod(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a,
/**
* Allocate a new ECC point (if one not provided)
* use a heap hint when creating new ecc_point
* return an allocated point on success or NULL on failure
* @return 0 on success
* @return BAD_FUNC_ARG for invalid arguments
* @return MEMORY_E on failure to allocate memory
*/
static int wc_ecc_new_point_ex(ecc_point** point, void* heap)
{
@@ -11811,15 +11813,14 @@ static int wc_ecc_import_raw_private(ecc_key* key, const char* qx,
qy y component of the public key, as ASCII hex string
d private key, as ASCII hex string, optional if importing public
key only
dp Custom ecc_set_type
return MP_OKAY on success
curve_id The id of the curve.
@return MP_OKAY on success
*/
int wc_ecc_import_raw_ex(ecc_key* key, const char* qx, const char* qy,
const char* d, int curve_id)
{
return wc_ecc_import_raw_private(key, qx, qy, d, curve_id,
WC_TYPE_HEX_STR);
}
/* Import x, y and optional private (d) as unsigned binary */

View File

@@ -17,8 +17,10 @@ EXTRA_DIST += wrapper/rust/wolfssl/build.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/lib.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/aes.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/ecc.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/random.rs
EXTRA_DIST += wrapper/rust/wolfssl/src/wolfcrypt/rsa.rs
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_aes.rs
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_ecc.rs
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_random.rs
EXTRA_DIST += wrapper/rust/wolfssl/tests/test_rsa.rs

View File

@@ -19,5 +19,6 @@
*/
pub mod aes;
pub mod ecc;
pub mod random;
pub mod rsa;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,267 @@
use std::fs;
use wolfssl::wolfcrypt::ecc::*;
use wolfssl::wolfcrypt::random::RNG;
#[test]
fn test_ecc_generate() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc = ECC::generate(32, &mut rng).expect("Error with generate()");
ecc.check().expect("Error with check()");
}
#[test]
fn test_ecc_generate_ex() {
let mut rng = RNG::new().expect("Failed to create RNG");
let curve_id = ECC::SECP256R1;
let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()");
assert_eq!(curve_size, 32);
let mut ecc = ECC::generate_ex(curve_size, &mut rng, curve_id).expect("Error with generate_ex()");
ecc.check().expect("Error with check()");
let mut x963 = [0u8; 128];
let x963_size = ecc.export_x963(&mut x963).expect("Error with export_x963()");
let x963 = &x963[0..x963_size];
let mut ecc = ECC::import_x963_ex(x963, ECC::SECP256R1).expect("Error with import_x963_ex");
ecc.check().expect("Error with check()");
}
#[test]
fn test_ecc_generate_ex2() {
let mut rng = RNG::new().expect("Failed to create RNG");
let curve_id = ECC::SECP256R1;
let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()");
assert_eq!(curve_size, 32);
let mut ecc = ECC::generate_ex2(curve_size, &mut rng, curve_id, ECC::FLAG_COFACTOR).expect("Error with generate_ex2()");
ecc.check().expect("Error with check()");
}
fn bytes_to_asciiz_hex_string(bytes: &[u8]) -> String {
let mut hex_string = String::with_capacity(bytes.len() * 2 + 1);
for byte in bytes {
hex_string.push_str(&format!("{:02X}", byte));
}
hex_string.push('\0');
hex_string
}
#[test]
fn test_ecc_import_export_sign_verify() {
let mut rng = RNG::new().expect("Failed to create RNG");
let key_path = "../../../certs/ecc-client-key.der";
let der: Vec<u8> = fs::read(key_path).expect("Error reading key file");
let mut ecc = ECC::import_der(&der).expect("Error with import_der()");
let hash = [0x42u8; 32];
let mut signature = [0u8; 128];
let signature_length = ecc.sign_hash(&hash, &mut signature, &mut rng).expect("Error with sign_hash()");
assert!(signature_length > 0 && signature_length <= signature.len());
let signature = &mut signature[0..signature_length];
let key_path = "../../../certs/ecc-client-keyPub.der";
let der: Vec<u8> = fs::read(key_path).expect("Error reading key file");
let mut ecc = ECC::import_public_der(&der).expect("Error with import_public_der()");
let valid = ecc.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
let mut x963 = [0u8; 128];
let x963_size = ecc.export_x963(&mut x963).expect("Error with export_x963()");
let x963 = &x963[0..x963_size];
let mut ecc = ECC::import_x963(x963).expect("Error with import_x963");
let valid = ecc.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
let mut x963 = [0u8; 128];
let x963_size = ecc.export_x963_compressed(&mut x963).expect("Error with export_x963_compressed()");
let x963 = &x963[0..x963_size];
let mut ecc = ECC::import_x963(x963).expect("Error with import_x963");
let valid = ecc.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
let mut r = [0u8; 32];
let mut r_size = 0u32;
let mut s = [0u8; 32];
let mut s_size = 0u32;
ECC::sig_to_rs(signature, &mut r, &mut r_size, &mut s, &mut s_size).expect("Error with sig_to_rs()");
assert_eq!(r_size, 32);
assert_eq!(s_size, 32);
let r = &r[0..r_size as usize];
let s = &s[0..s_size as usize];
let mut sig_out = [0u8; 128];
let sig_out_size = ECC::rs_bin_to_sig(r, s, &mut sig_out).expect("Error with rs_bin_to_sig()");
assert_eq!(*signature, *&sig_out[0..sig_out_size]);
let r_hex_string = bytes_to_asciiz_hex_string(r);
let s_hex_string = bytes_to_asciiz_hex_string(s);
let mut sig_out = [0u8; 128];
let sig_out_size = ECC::rs_hex_to_sig(&r_hex_string[0..r_hex_string.len()].as_bytes(), &s_hex_string[0..s_hex_string.len()].as_bytes(), &mut sig_out).expect("Error with rs_hex_to_sig()");
assert_eq!(*signature, *&sig_out[0..sig_out_size]);
signature[signature.len() - 2] = 0xDEu8;
signature[signature.len() - 1] = 0xADu8;
let valid = ecc.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, false);
ecc.set_rng(&mut rng).expect("Error with set_rng()");
}
#[test]
fn test_ecc_shared_secret() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc0 = ECC::generate(32, &mut rng).expect("Error with generate()");
let mut ecc1 = ECC::generate(32, &mut rng).expect("Error with generate()");
let mut ss0 = [0u8; 128];
let mut ss1 = [0u8; 128];
let ss0_size = ecc0.shared_secret(&mut ecc1, &mut ss0).expect("Error with shared_secret()");
let ss1_size = ecc1.shared_secret(&mut ecc0, &mut ss1).expect("Error with shared_secret()");
assert_eq!(ss0_size, ss1_size);
let ss0 = &ss0[0..ss0_size];
let ss1 = &ss1[0..ss1_size];
assert_eq!(*ss0, *ss1);
let mut ss0 = [0u8; 128];
let ecc_point = ecc1.make_pub_to_point(None).expect("Error with make_pub_to_point()");
let ss0_size = ecc0.shared_secret_ex(&ecc_point, &mut ss0).expect("Error with shared_secret_ex()");
let ss0 = &ss0[0..ss0_size];
assert_eq!(*ss0, *ss1);
}
#[test]
fn test_ecc_export() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc = ECC::generate(32, &mut rng).expect("Error with generate()");
let mut qx = [0u8; 32];
let mut qx_len = 0u32;
let mut qy = [0u8; 32];
let mut qy_len = 0u32;
let mut d = [0u8; 32];
let mut d_len = 0u32;
ecc.export(&mut qx, &mut qx_len, &mut qy, &mut qy_len, &mut d, &mut d_len).expect("Error with export()");
}
#[test]
fn test_ecc_export_ex() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc = ECC::generate(32, &mut rng).expect("Error with generate()");
let mut qx = [0u8; 32];
let mut qx_len = 0u32;
let mut qy = [0u8; 32];
let mut qy_len = 0u32;
let mut d = [0u8; 32];
let mut d_len = 0u32;
ecc.export_ex(&mut qx, &mut qx_len, &mut qy, &mut qy_len, &mut d, &mut d_len, false).expect("Error with export_ex()");
}
#[test]
fn test_ecc_import_export_private() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc = ECC::generate(32, &mut rng).expect("Error with generate()");
let hash = [0x42u8; 32];
let mut signature = [0u8; 128];
let signature_length = ecc.sign_hash(&hash, &mut signature, &mut rng).expect("Error with sign_hash()");
let signature = &signature[0..signature_length];
let mut d = [0u8; 32];
let d_size = ecc.export_private(&mut d).expect("Error with export_private()");
assert_eq!(d_size, 32);
let mut x963 = [0u8; 128];
let x963_size = ecc.export_x963(&mut x963).expect("Error with export_x963()");
let x963 = &x963[0..x963_size];
let mut ecc2 = ECC::import_private_key(&d, x963).expect("Error with import_private_key()");
let valid = ecc2.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
}
#[test]
fn test_ecc_import_export_private_ex() {
let mut rng = RNG::new().expect("Failed to create RNG");
let curve_id = ECC::SECP256R1;
let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()");
let mut ecc = ECC::generate_ex(curve_size, &mut rng, curve_id).expect("Error with generate_ex()");
let hash = [0x42u8; 32];
let mut signature = [0u8; 128];
let signature_length = ecc.sign_hash(&hash, &mut signature, &mut rng).expect("Error with sign_hash()");
let signature = &signature[0..signature_length];
let mut d = [0u8; 32];
let d_size = ecc.export_private(&mut d).expect("Error with export_private()");
assert_eq!(d_size, 32);
let mut x963 = [0u8; 128];
let x963_size = ecc.export_x963(&mut x963).expect("Error with export_x963()");
let x963 = &x963[0..x963_size];
let mut ecc2 = ECC::import_private_key_ex(&d, x963, curve_id).expect("Error with import_private_key_ex()");
let valid = ecc2.verify_hash(&signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
}
#[test]
fn test_ecc_export_public() {
let mut rng = RNG::new().expect("Failed to create RNG");
let mut ecc = ECC::generate(32, &mut rng).expect("Error with generate()");
let mut qx = [0u8; 32];
let mut qx_len = 0u32;
let mut qy = [0u8; 32];
let mut qy_len = 0u32;
ecc.export_public(&mut qx, &mut qx_len, &mut qy, &mut qy_len).expect("Error with export_public()");
}
#[test]
fn test_ecc_import_unsigned() {
let mut rng = RNG::new().expect("Failed to create RNG");
let curve_id = ECC::SECP256R1;
let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()");
let mut ecc = ECC::generate_ex(curve_size, &mut rng, curve_id).expect("Error with generate()");
let mut qx = [0u8; 32];
let mut qx_len = 0u32;
let mut qy = [0u8; 32];
let mut qy_len = 0u32;
let mut d = [0u8; 32];
let mut d_len = 0u32;
ecc.export_ex(&mut qx, &mut qx_len, &mut qy, &mut qy_len, &mut d, &mut d_len, false).expect("Error with export_ex()");
let mut ecc2 = ECC::import_unsigned(&qx, &qy, &d, curve_id).expect("Error with import_unsigned()");
let hash = [0x42u8; 32];
let mut signature = [0u8; 128];
let signature_length = ecc.sign_hash(&hash, &mut signature, &mut rng).expect("Error with sign_hash()");
let signature = &signature[0..signature_length];
let valid = ecc2.verify_hash(signature, &hash).expect("Error with verify_hash()");
assert_eq!(valid, true);
}
#[test]
fn test_ecc_make_pub() {
let mut rng = RNG::new().expect("Failed to create RNG");
let key_path = "../../../certs/ecc-client-key.der";
let der: Vec<u8> = fs::read(key_path).expect("Error reading key file");
let mut ecc = ECC::import_der(&der).expect("Error with import_der()");
ecc.make_pub(Some(&mut rng)).expect("Error with make_pub()");
ecc.make_pub(None).expect("Error with make_pub()");
ecc.make_pub_to_point(Some(&mut rng)).expect("Error with make_pub_to_point()");
ecc.make_pub_to_point(None).expect("Error with make_pub_to_point()");
}
#[test]
fn test_ecc_point() {
let mut rng = RNG::new().expect("Failed to create RNG");
let curve_id = ECC::SECP256R1;
let curve_size = ECC::get_curve_size_from_id(curve_id).expect("Error with get_curve_size_from_id()");
let mut ecc = ECC::generate_ex(curve_size, &mut rng, curve_id).expect("Error with generate()");
let ecc_point = ecc.make_pub_to_point(Some(&mut rng)).expect("Error with make_pub_to_point()");
let mut der = [0u8; 128];
let size = ecc_point.export_der(&mut der, curve_id).expect("Error with export_der()");
assert!(size > 0 && size <= der.len());
ECCPoint::import_der(&der[0..size], curve_id).expect("Error with import_der()");
let size = ecc_point.export_der_compressed(&mut der, curve_id).expect("Error with export_der_compressed()");
ECCPoint::import_der_ex(&der[0..size], curve_id, 1).expect("Error with import_der_ex()");
ecc_point.forcezero();
}
#[test]
fn test_ecc_import() {
let qx = b"7a4e287890a1a47ad3457e52f2f76a83ce46cbc947616d0cbaa82323818a793d\0";
let qy = b"eec4084f5b29ebf29c44cce3b3059610922f8b30ea6e8811742ac7238fe87308\0";
let d = b"8c14b793cb19137e323a6d2e2a870bca2e7a493ec1153b3a95feb8a4873f8d08\0";
ECC::import_raw(qx, qy, d, b"SECP256R1\0").expect("Error with import_raw()");
ECC::import_raw_ex(qx, qy, d, ECC::SECP256R1).expect("Error with import_raw_ex()");
}