#![cfg(wolfssl_ecc)]
extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use core::ptr;
use crate::error::{check, len_as_u32, WolfCryptError};
use crate::rand::WolfRng;
use wolfcrypt_rs::{
wc_ecc_check_key, wc_ecc_export_private_only, wc_ecc_export_x963,
wc_ecc_get_curve_size_from_id, wc_ecc_import_private_key, wc_ecc_import_private_key_ex,
wc_ecc_import_x963, wc_ecc_init_ex, wc_ecc_key, wc_ecc_key_free, wc_ecc_key_new,
wc_ecc_make_key_ex, wc_ecc_shared_secret, wc_ecc_sign_hash, wc_ecc_verify_hash, ECC_SECP256K1,
ECC_SECP256R1, ECC_SECP384R1, ECC_SECP521R1,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
pub enum EccCurveId {
SecP256R1 = ECC_SECP256R1,
SecP384R1 = ECC_SECP384R1,
SecP521R1 = ECC_SECP521R1,
SecP256K1 = ECC_SECP256K1,
}
const MAX_X963_PUB_SIZE: usize = 133;
const MAX_DER_SIG_SIZE: usize = 256;
const MAX_PRIV_KEY_SIZE: usize = 66;
const MAX_SHARED_SECRET_SIZE: usize = 66;
pub struct EccKey {
key: *mut wc_ecc_key,
}
unsafe impl Send for EccKey {}
impl EccKey {
fn alloc_and_init() -> Result<*mut wc_ecc_key, WolfCryptError> {
let key = unsafe { wc_ecc_key_new(ptr::null_mut()) };
if key.is_null() {
return Err(WolfCryptError::AllocFailed);
}
let rc = unsafe { wc_ecc_init_ex(key, ptr::null_mut(), -1) };
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wc_ecc_init_ex",
});
}
Ok(key)
}
pub fn generate(curve: EccCurveId, rng: &mut WolfRng) -> Result<Self, WolfCryptError> {
let key = Self::alloc_and_init()?;
let key_size = unsafe { wc_ecc_get_curve_size_from_id(curve as i32) };
if key_size <= 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::InvalidInput);
}
let rc = unsafe { wc_ecc_make_key_ex(&mut rng.rng, key_size, key, curve as i32) };
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wc_ecc_make_key_ex",
});
}
Ok(Self { key })
}
pub fn from_private_and_public(
_curve: EccCurveId,
priv_key: &[u8],
pub_key: &[u8],
) -> Result<Self, WolfCryptError> {
let key = Self::alloc_and_init()?;
let rc = unsafe {
wc_ecc_import_private_key(
priv_key.as_ptr(),
len_as_u32(priv_key.len()),
pub_key.as_ptr(),
len_as_u32(pub_key.len()),
key,
)
};
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wc_ecc_import_private_key",
});
}
Ok(Self { key })
}
pub fn from_private(curve: EccCurveId, priv_key: &[u8]) -> Result<Self, WolfCryptError> {
let key = Self::alloc_and_init()?;
let rc = unsafe {
wc_ecc_import_private_key_ex(
priv_key.as_ptr(),
len_as_u32(priv_key.len()),
ptr::null(),
0,
key,
curve as i32,
)
};
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wc_ecc_import_private_key_ex",
});
}
Ok(Self { key })
}
pub fn from_public_x963(pub_key: &[u8]) -> Result<Self, WolfCryptError> {
let key = Self::alloc_and_init()?;
let rc = unsafe { wc_ecc_import_x963(pub_key.as_ptr(), len_as_u32(pub_key.len()), key) };
if rc != 0 {
unsafe { wc_ecc_key_free(key) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wc_ecc_import_x963",
});
}
Ok(Self { key })
}
pub fn export_public_x963(&self) -> Result<Vec<u8>, WolfCryptError> {
let mut buf = vec![0u8; MAX_X963_PUB_SIZE];
let mut out_len: u32 = buf.len() as u32;
let rc = unsafe { wc_ecc_export_x963(self.key, buf.as_mut_ptr(), &mut out_len) };
check(rc, "wc_ecc_export_x963")?;
buf.truncate(out_len as usize);
Ok(buf)
}
pub fn export_private(&self) -> Result<Vec<u8>, WolfCryptError> {
let mut buf = vec![0u8; MAX_PRIV_KEY_SIZE];
let mut out_len: u32 = buf.len() as u32;
let rc = unsafe { wc_ecc_export_private_only(self.key, buf.as_mut_ptr(), &mut out_len) };
check(rc, "wc_ecc_export_private_only")?;
buf.truncate(out_len as usize);
Ok(buf)
}
pub fn ecdh_shared_secret(&mut self, peer: &mut EccKey) -> Result<Vec<u8>, WolfCryptError> {
let mut buf = vec![0u8; MAX_SHARED_SECRET_SIZE];
let mut out_len: u32 = buf.len() as u32;
let rc =
unsafe { wc_ecc_shared_secret(self.key, peer.key, buf.as_mut_ptr(), &mut out_len) };
check(rc, "wc_ecc_shared_secret")?;
buf.truncate(out_len as usize);
Ok(buf)
}
pub fn sign_hash(&mut self, hash: &[u8], rng: &mut WolfRng) -> Result<Vec<u8>, WolfCryptError> {
let mut buf = vec![0u8; MAX_DER_SIG_SIZE];
let mut out_len: u32 = buf.len() as u32;
let rc = unsafe {
wc_ecc_sign_hash(
hash.as_ptr(),
len_as_u32(hash.len()),
buf.as_mut_ptr(),
&mut out_len,
&mut rng.rng,
self.key,
)
};
check(rc, "wc_ecc_sign_hash")?;
buf.truncate(out_len as usize);
Ok(buf)
}
pub fn verify_hash(&mut self, sig: &[u8], hash: &[u8]) -> Result<bool, WolfCryptError> {
let mut result: i32 = 0;
let rc = unsafe {
wc_ecc_verify_hash(
sig.as_ptr(),
len_as_u32(sig.len()),
hash.as_ptr(),
len_as_u32(hash.len()),
&mut result,
self.key,
)
};
check(rc, "wc_ecc_verify_hash")?;
Ok(result == 1)
}
pub fn check_key(&mut self) -> Result<(), WolfCryptError> {
let rc = unsafe { wc_ecc_check_key(self.key) };
check(rc, "wc_ecc_check_key")
}
}
impl Drop for EccKey {
fn drop(&mut self) {
if !self.key.is_null() {
unsafe { wc_ecc_key_free(self.key) };
}
}
}
pub fn ecc_sig_der_to_rs(
der_sig: &[u8],
) -> Result<(alloc::vec::Vec<u8>, alloc::vec::Vec<u8>), WolfCryptError> {
let mut r = [0u8; 66];
let mut s = [0u8; 66];
let mut r_len = r.len() as u32;
let mut s_len = s.len() as u32;
let rc = unsafe {
wolfcrypt_rs::wc_ecc_sig_to_rs(
der_sig.as_ptr(),
len_as_u32(der_sig.len()),
r.as_mut_ptr(),
&mut r_len,
s.as_mut_ptr(),
&mut s_len,
)
};
check(rc, "wc_ecc_sig_to_rs")?;
Ok((r[..r_len as usize].to_vec(), s[..s_len as usize].to_vec()))
}
pub fn ecc_sig_rs_to_der(r: &[u8], s: &[u8]) -> Result<alloc::vec::Vec<u8>, WolfCryptError> {
let mut out = [0u8; 144];
let mut out_len = out.len() as u32;
let rc = unsafe {
wolfcrypt_rs::wc_ecc_rs_raw_to_sig(
r.as_ptr(),
len_as_u32(r.len()),
s.as_ptr(),
len_as_u32(s.len()),
out.as_mut_ptr(),
&mut out_len,
)
};
check(rc, "wc_ecc_rs_raw_to_sig")?;
Ok(out[..out_len as usize].to_vec())
}