use core::cell::UnsafeCell;
use core::ffi::c_void;
use core::ptr;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::{check, len_as_u32, WolfCryptError};
use wolfcrypt_rs::{
EVP_DigestSignFinal, EVP_DigestSignInit, EVP_DigestSignUpdate,
EVP_DigestVerifyFinal, EVP_DigestVerifyInit, EVP_DigestVerifyUpdate,
EVP_MD, EVP_MD_CTX, EVP_MD_CTX_free, EVP_MD_CTX_new,
EVP_PKEY, EVP_PKEY_CTX, EVP_PKEY_CTX_free, EVP_PKEY_CTX_new,
EVP_PKEY_CTX_new_id,
EVP_PKEY_CTX_set_rsa_keygen_bits, EVP_PKEY_CTX_set_rsa_mgf1_md,
EVP_PKEY_CTX_set_rsa_oaep_md,
EVP_PKEY_CTX_set_rsa_padding, EVP_PKEY_CTX_set_rsa_pss_saltlen,
EVP_PKEY_encrypt, EVP_PKEY_encrypt_init,
EVP_PKEY_decrypt, EVP_PKEY_decrypt_init,
EVP_PKEY_free, EVP_PKEY_keygen, EVP_PKEY_keygen_init,
EVP_PKEY_RSA, EVP_sha1, EVP_sha256, EVP_sha384, EVP_sha512,
i2d_PUBKEY, i2d_PrivateKey, d2i_PUBKEY, d2i_PrivateKey,
RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING,
RSA_PKCS1_PSS_PADDING, RSA_PSS_SALTLEN_DIGEST,
};
const RSA_MIN_SIG_BYTES: usize = 64;
#[derive(Clone, Debug)]
pub struct RsaPkcs1v15Signature(Vec<u8>);
impl AsRef<[u8]> for RsaPkcs1v15Signature {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl signature_trait::SignatureEncoding for RsaPkcs1v15Signature {
type Repr = Box<[u8]>;
}
impl TryFrom<&[u8]> for RsaPkcs1v15Signature {
type Error = signature_trait::Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < RSA_MIN_SIG_BYTES {
return Err(signature_trait::Error::new());
}
Ok(Self(bytes.to_vec()))
}
}
impl From<RsaPkcs1v15Signature> for Box<[u8]> {
fn from(sig: RsaPkcs1v15Signature) -> Box<[u8]> {
sig.0.into_boxed_slice()
}
}
#[derive(Clone, Debug)]
pub struct RsaPssSignature(Vec<u8>);
impl AsRef<[u8]> for RsaPssSignature {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl signature_trait::SignatureEncoding for RsaPssSignature {
type Repr = Box<[u8]>;
}
impl TryFrom<&[u8]> for RsaPssSignature {
type Error = signature_trait::Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() < RSA_MIN_SIG_BYTES {
return Err(signature_trait::Error::new());
}
Ok(Self(bytes.to_vec()))
}
}
impl From<RsaPssSignature> for Box<[u8]> {
fn from(sig: RsaPssSignature) -> Box<[u8]> {
sig.0.into_boxed_slice()
}
}
struct MdCtx(*mut EVP_MD_CTX);
impl MdCtx {
fn new() -> Result<Self, WolfCryptError> {
let p = unsafe { EVP_MD_CTX_new() };
if p.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
Ok(Self(p))
}
fn as_mut_ptr(&self) -> *mut EVP_MD_CTX {
self.0
}
}
impl Drop for MdCtx {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { EVP_MD_CTX_free(self.0) };
}
}
}
struct PkeyCtx(*mut EVP_PKEY_CTX);
impl PkeyCtx {
fn new(pkey: *mut EVP_PKEY) -> Result<Self, WolfCryptError> {
let p = unsafe { EVP_PKEY_CTX_new(pkey, ptr::null_mut()) };
if p.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
Ok(Self(p))
}
fn as_mut_ptr(&self) -> *mut EVP_PKEY_CTX {
self.0
}
}
impl Drop for PkeyCtx {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { EVP_PKEY_CTX_free(self.0) };
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RsaDigest {
Sha1,
Sha256,
Sha384,
Sha512,
}
impl RsaDigest {
fn evp_md(self) -> *const EVP_MD {
unsafe {
match self {
Self::Sha1 => EVP_sha1(),
Self::Sha256 => EVP_sha256(),
Self::Sha384 => EVP_sha384(),
Self::Sha512 => EVP_sha512(),
}
}
}
}
#[derive(Clone, Copy)]
enum RsaPadding {
Pkcs1v15,
Pss,
Oaep,
}
impl RsaPadding {
fn as_c_int(self) -> i32 {
match self {
Self::Pkcs1v15 => RSA_PKCS1_PADDING,
Self::Pss => RSA_PKCS1_PSS_PADDING,
Self::Oaep => RSA_PKCS1_OAEP_PADDING,
}
}
}
unsafe fn evp_encrypt(
pkey: *mut EVP_PKEY,
plaintext: &[u8],
padding: RsaPadding,
) -> Result<Vec<u8>, WolfCryptError> {
unsafe {
let ctx = PkeyCtx::new(pkey)?;
let rc = EVP_PKEY_encrypt_init(ctx.as_mut_ptr());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_encrypt_init" });
}
let rc = EVP_PKEY_CTX_set_rsa_padding(ctx.as_mut_ptr(), padding.as_c_int());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_padding" });
}
if matches!(padding, RsaPadding::Oaep) {
let rc = EVP_PKEY_CTX_set_rsa_oaep_md(ctx.as_mut_ptr(), EVP_sha256());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_oaep_md" });
}
}
let mut out_len: usize = 0;
let rc = EVP_PKEY_encrypt(
ctx.as_mut_ptr(),
ptr::null_mut(),
&mut out_len,
plaintext.as_ptr(),
plaintext.len(),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_encrypt" });
}
if out_len == 0 {
return Err(WolfCryptError::Ffi { code: 0, func: "EVP_PKEY_encrypt (zero output length)" });
}
let mut out = vec![0u8; out_len];
let rc = EVP_PKEY_encrypt(
ctx.as_mut_ptr(),
out.as_mut_ptr(),
&mut out_len,
plaintext.as_ptr(),
plaintext.len(),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_encrypt" });
}
out.truncate(out_len);
Ok(out)
}
}
unsafe fn evp_decrypt(
pkey: *mut EVP_PKEY,
ciphertext: &[u8],
padding: RsaPadding,
) -> Result<Vec<u8>, WolfCryptError> {
unsafe {
let ctx = PkeyCtx::new(pkey)?;
let rc = EVP_PKEY_decrypt_init(ctx.as_mut_ptr());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_decrypt_init" });
}
let rc = EVP_PKEY_CTX_set_rsa_padding(ctx.as_mut_ptr(), padding.as_c_int());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_padding" });
}
if matches!(padding, RsaPadding::Oaep) {
let rc = EVP_PKEY_CTX_set_rsa_oaep_md(ctx.as_mut_ptr(), EVP_sha256());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_oaep_md" });
}
}
let mut out_len: usize = 0;
let rc = EVP_PKEY_decrypt(
ctx.as_mut_ptr(),
ptr::null_mut(),
&mut out_len,
ciphertext.as_ptr(),
ciphertext.len(),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_decrypt" });
}
if out_len == 0 {
return Err(WolfCryptError::Ffi { code: 0, func: "EVP_PKEY_decrypt (zero output length)" });
}
let mut out = vec![0u8; out_len];
let rc = EVP_PKEY_decrypt(
ctx.as_mut_ptr(),
out.as_mut_ptr(),
&mut out_len,
ciphertext.as_ptr(),
ciphertext.len(),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_decrypt" });
}
out.truncate(out_len);
Ok(out)
}
}
unsafe fn evp_sign(
pkey: *mut EVP_PKEY,
msg: &[u8],
padding: RsaPadding,
digest: RsaDigest,
) -> Result<Vec<u8>, WolfCryptError> {
unsafe {
let md_ctx = MdCtx::new()?;
let mut pkey_ctx: *mut EVP_PKEY_CTX = ptr::null_mut();
let rc = EVP_DigestSignInit(
md_ctx.as_mut_ptr(),
&mut pkey_ctx,
digest.evp_md(),
ptr::null_mut(), pkey,
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestSignInit" });
}
let rc = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding.as_c_int());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_padding" });
}
if matches!(padding, RsaPadding::Pss) {
let rc = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, RSA_PSS_SALTLEN_DIGEST);
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_pss_saltlen" });
}
let rc = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest.evp_md());
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_mgf1_md" });
}
}
let rc = EVP_DigestSignUpdate(
md_ctx.as_mut_ptr(),
msg.as_ptr() as *const c_void,
len_as_u32(msg.len()),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestSignUpdate" });
}
let mut sig_len: usize = 0;
let rc = EVP_DigestSignFinal(md_ctx.as_mut_ptr(), ptr::null_mut(), &mut sig_len);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestSignFinal" });
}
if sig_len == 0 {
return Err(WolfCryptError::Ffi { code: 0, func: "EVP_DigestSignFinal (zero output length)" });
}
let mut sig = vec![0u8; sig_len];
let rc = EVP_DigestSignFinal(md_ctx.as_mut_ptr(), sig.as_mut_ptr(), &mut sig_len);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestSignFinal" });
}
sig.truncate(sig_len);
Ok(sig)
}
}
unsafe fn evp_verify(
pkey: *mut EVP_PKEY,
msg: &[u8],
sig: &[u8],
padding: RsaPadding,
digest: RsaDigest,
) -> Result<(), WolfCryptError> {
unsafe {
let md_ctx = MdCtx::new()?;
let mut pkey_ctx: *mut EVP_PKEY_CTX = ptr::null_mut();
let rc = EVP_DigestVerifyInit(
md_ctx.as_mut_ptr(),
&mut pkey_ctx,
digest.evp_md(),
ptr::null_mut(),
pkey,
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestVerifyInit" });
}
let rc = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding.as_c_int());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_padding" });
}
if matches!(padding, RsaPadding::Pss) {
let rc = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, RSA_PSS_SALTLEN_DIGEST);
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_pss_saltlen" });
}
let rc = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest.evp_md());
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_mgf1_md" });
}
}
let rc = EVP_DigestVerifyUpdate(
md_ctx.as_mut_ptr(),
msg.as_ptr() as *const c_void,
msg.len(),
);
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestVerifyUpdate" });
}
let rc = EVP_DigestVerifyFinal(md_ctx.as_mut_ptr(), sig.as_ptr(), sig.len());
if rc != 1 {
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_DigestVerifyFinal" });
}
Ok(())
}
}
pub struct RsaPrivateKey {
pkey: UnsafeCell<*mut EVP_PKEY>,
}
unsafe impl Send for RsaPrivateKey {}
impl RsaPrivateKey {
pub fn from_pkcs1_der(der: &[u8]) -> Result<Self, WolfCryptError> {
unsafe {
let mut in_ptr = der.as_ptr();
let pkey = d2i_PrivateKey(
EVP_PKEY_RSA,
ptr::null_mut(),
&mut in_ptr as *mut *const u8 as *mut *const u8,
der.len() as core::ffi::c_long,
);
if pkey.is_null() {
return Err(WolfCryptError::Ffi { code: -1, func: "d2i_PrivateKey" });
}
Ok(Self {
pkey: UnsafeCell::new(pkey),
})
}
}
pub fn to_pkcs1_der(&self) -> Result<Vec<u8>, WolfCryptError> {
unsafe {
let pkey = *self.pkey.get();
let der_len = i2d_PrivateKey(pkey as *const _, ptr::null_mut());
if der_len <= 0 {
return Err(WolfCryptError::Ffi { code: der_len, func: "i2d_PrivateKey" });
}
let mut der = vec![0u8; der_len as usize];
let mut out_ptr = der.as_mut_ptr();
let written = i2d_PrivateKey(pkey as *const _, &mut out_ptr);
if written != der_len {
return Err(WolfCryptError::Ffi { code: written, func: "i2d_PrivateKey" });
}
Ok(der)
}
}
pub fn generate(bits: u32) -> Result<Self, WolfCryptError> {
unsafe {
let ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, ptr::null_mut());
if ctx.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let rc = EVP_PKEY_keygen_init(ctx);
if rc != 1 {
EVP_PKEY_CTX_free(ctx);
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_keygen_init" });
}
let rc = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits as i32);
if rc != 1 {
EVP_PKEY_CTX_free(ctx);
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_CTX_set_rsa_keygen_bits" });
}
let mut pkey: *mut EVP_PKEY = ptr::null_mut();
let rc = EVP_PKEY_keygen(ctx, &mut pkey);
EVP_PKEY_CTX_free(ctx);
if rc != 1 || pkey.is_null() {
if !pkey.is_null() {
EVP_PKEY_free(pkey);
}
return Err(WolfCryptError::Ffi { code: rc, func: "EVP_PKEY_keygen" });
}
Ok(Self {
pkey: UnsafeCell::new(pkey),
})
}
}
pub fn public_key(&self) -> RsaPublicKey {
unsafe {
let pkey = *self.pkey.get();
let der_len = i2d_PUBKEY(pkey as *const _, ptr::null_mut());
assert!(der_len > 0, "i2d_PUBKEY failed (invalid key)");
let mut der = vec![0u8; der_len as usize];
let mut out_ptr = der.as_mut_ptr();
let written = i2d_PUBKEY(pkey as *const _, &mut out_ptr);
assert_eq!(written, der_len, "i2d_PUBKEY size mismatch");
let mut in_ptr = der.as_ptr();
let new_pkey = d2i_PUBKEY(
ptr::null_mut(),
&mut in_ptr as *mut *const u8 as *mut *const u8,
der_len as core::ffi::c_long,
);
assert!(!new_pkey.is_null(), "d2i_PUBKEY failed (invalid DER)");
RsaPublicKey {
pkey: UnsafeCell::new(new_pkey),
}
}
}
pub fn sign_pkcs1v15(&self, msg: &[u8]) -> Result<RsaPkcs1v15Signature, WolfCryptError> {
self.sign_pkcs1v15_with_digest(msg, RsaDigest::Sha256)
}
pub fn sign_pkcs1v15_with_digest(
&self,
msg: &[u8],
digest: RsaDigest,
) -> Result<RsaPkcs1v15Signature, WolfCryptError> {
let sig = unsafe { evp_sign(*self.pkey.get(), msg, RsaPadding::Pkcs1v15, digest)? };
Ok(RsaPkcs1v15Signature(sig))
}
pub fn sign_pss(&self, msg: &[u8]) -> Result<RsaPssSignature, WolfCryptError> {
self.sign_pss_with_digest(msg, RsaDigest::Sha256)
}
pub fn sign_pss_with_digest(
&self,
msg: &[u8],
digest: RsaDigest,
) -> Result<RsaPssSignature, WolfCryptError> {
let sig = unsafe { evp_sign(*self.pkey.get(), msg, RsaPadding::Pss, digest)? };
Ok(RsaPssSignature(sig))
}
pub fn encrypt_oaep(&self, plaintext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_encrypt(*self.pkey.get(), plaintext, RsaPadding::Oaep) }
}
pub fn decrypt_oaep(&self, ciphertext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_decrypt(*self.pkey.get(), ciphertext, RsaPadding::Oaep) }
}
pub fn encrypt_pkcs1v15(&self, plaintext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_encrypt(*self.pkey.get(), plaintext, RsaPadding::Pkcs1v15) }
}
pub fn decrypt_pkcs1v15(&self, ciphertext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_decrypt(*self.pkey.get(), ciphertext, RsaPadding::Pkcs1v15) }
}
}
impl Drop for RsaPrivateKey {
fn drop(&mut self) {
unsafe {
let pkey = *self.pkey.get();
if !pkey.is_null() {
EVP_PKEY_free(pkey);
}
}
}
}
impl signature_trait::Signer<RsaPkcs1v15Signature> for RsaPrivateKey {
fn try_sign(&self, msg: &[u8]) -> Result<RsaPkcs1v15Signature, signature_trait::Error> {
self.sign_pkcs1v15(msg).map_err(|_| signature_trait::Error::new())
}
}
impl signature_trait::Signer<RsaPssSignature> for RsaPrivateKey {
fn try_sign(&self, msg: &[u8]) -> Result<RsaPssSignature, signature_trait::Error> {
self.sign_pss(msg).map_err(|_| signature_trait::Error::new())
}
}
pub struct RsaPublicKey {
pkey: UnsafeCell<*mut EVP_PKEY>,
}
unsafe impl Send for RsaPublicKey {}
impl RsaPublicKey {
pub fn from_der(der: &[u8]) -> Result<Self, WolfCryptError> {
unsafe {
let mut in_ptr = der.as_ptr();
let pkey = d2i_PUBKEY(
ptr::null_mut(),
&mut in_ptr as *mut *const u8 as *mut *const u8,
der.len() as core::ffi::c_long,
);
if pkey.is_null() {
return Err(WolfCryptError::Ffi { code: -1, func: "d2i_PUBKEY" });
}
Ok(Self {
pkey: UnsafeCell::new(pkey),
})
}
}
pub fn encrypt_oaep(&self, plaintext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_encrypt(*self.pkey.get(), plaintext, RsaPadding::Oaep) }
}
pub fn encrypt_pkcs1v15(&self, plaintext: &[u8]) -> Result<Vec<u8>, WolfCryptError> {
unsafe { evp_encrypt(*self.pkey.get(), plaintext, RsaPadding::Pkcs1v15) }
}
pub fn verify_pkcs1v15(
&self,
msg: &[u8],
sig: &RsaPkcs1v15Signature,
) -> Result<(), WolfCryptError> {
self.verify_pkcs1v15_with_digest(msg, sig, RsaDigest::Sha256)
}
pub fn verify_pkcs1v15_with_digest(
&self,
msg: &[u8],
sig: &RsaPkcs1v15Signature,
digest: RsaDigest,
) -> Result<(), WolfCryptError> {
unsafe { evp_verify(*self.pkey.get(), msg, &sig.0, RsaPadding::Pkcs1v15, digest) }
}
pub fn verify_pss(&self, msg: &[u8], sig: &RsaPssSignature) -> Result<(), WolfCryptError> {
self.verify_pss_with_digest(msg, sig, RsaDigest::Sha256)
}
pub fn verify_pss_with_digest(
&self,
msg: &[u8],
sig: &RsaPssSignature,
digest: RsaDigest,
) -> Result<(), WolfCryptError> {
unsafe { evp_verify(*self.pkey.get(), msg, &sig.0, RsaPadding::Pss, digest) }
}
}
impl Drop for RsaPublicKey {
fn drop(&mut self) {
unsafe {
let pkey = *self.pkey.get();
if !pkey.is_null() {
EVP_PKEY_free(pkey);
}
}
}
}
impl signature_trait::Verifier<RsaPkcs1v15Signature> for RsaPublicKey {
fn verify(
&self,
msg: &[u8],
signature: &RsaPkcs1v15Signature,
) -> Result<(), signature_trait::Error> {
self.verify_pkcs1v15(msg, signature)
.map_err(|_| signature_trait::Error::new())
}
}
impl signature_trait::Verifier<RsaPssSignature> for RsaPublicKey {
fn verify(
&self,
msg: &[u8],
signature: &RsaPssSignature,
) -> Result<(), signature_trait::Error> {
self.verify_pss(msg, signature)
.map_err(|_| signature_trait::Error::new())
}
}
#[cfg(feature = "rsa-direct")]
const RSA_TYPE_PUBLIC_ENCRYPT: i32 = 0;
#[cfg(feature = "rsa-direct")]
const RSA_TYPE_PUBLIC_DECRYPT: i32 = 1;
#[cfg(feature = "rsa-direct")]
const RSA_TYPE_PRIVATE_ENCRYPT: i32 = 2;
#[cfg(feature = "rsa-direct")]
const RSA_TYPE_PRIVATE_DECRYPT: i32 = 3;
#[cfg(feature = "rsa-direct")]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RsaDirectType {
PublicEncrypt,
PublicDecrypt,
PrivateEncrypt,
PrivateDecrypt,
}
#[cfg(feature = "rsa-direct")]
impl RsaDirectType {
fn as_c_int(self) -> i32 {
match self {
Self::PublicEncrypt => RSA_TYPE_PUBLIC_ENCRYPT,
Self::PublicDecrypt => RSA_TYPE_PUBLIC_DECRYPT,
Self::PrivateEncrypt => RSA_TYPE_PRIVATE_ENCRYPT,
Self::PrivateDecrypt => RSA_TYPE_PRIVATE_DECRYPT,
}
}
}
#[cfg(feature = "rsa-direct")]
pub struct NativeRsaKey {
key: *mut wolfcrypt_rs::RsaKey,
}
#[cfg(feature = "rsa-direct")]
unsafe impl Send for NativeRsaKey {}
#[cfg(feature = "rsa-direct")]
impl NativeRsaKey {
fn alloc() -> Result<*mut wolfcrypt_rs::RsaKey, WolfCryptError> {
let mut rc: core::ffi::c_int = 0;
let key = unsafe {
wolfcrypt_rs::wc_NewRsaKey(
ptr::null_mut(),
wolfcrypt_rs::INVALID_DEVID,
&mut rc,
)
};
if key.is_null() {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_NewRsaKey" });
}
Ok(key)
}
pub fn generate_native(
bits: u32,
rng: &mut crate::rand::WolfRng,
) -> Result<Self, WolfCryptError> {
let key = Self::alloc()?;
let rc = unsafe {
wolfcrypt_rs::wc_MakeRsaKey(
key,
bits as core::ffi::c_int,
65537,
&mut rng.rng,
)
};
if rc != 0 {
unsafe { wolfcrypt_rs::wc_DeleteRsaKey(key, ptr::null_mut()) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_MakeRsaKey" });
}
Ok(Self { key })
}
pub fn to_pkcs1_der(&self) -> Result<alloc::vec::Vec<u8>, WolfCryptError> {
let mut buf = alloc::vec![0u8; 4096];
let rc = unsafe {
wolfcrypt_rs::wc_RsaKeyToDer(
self.key,
buf.as_mut_ptr(),
len_as_u32(buf.len()),
)
};
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaKeyToDer" });
}
buf.truncate(rc as usize);
Ok(buf)
}
pub fn from_private_der(der: &[u8]) -> Result<Self, WolfCryptError> {
let key = Self::alloc()?;
let mut idx: u32 = 0;
let rc = unsafe {
wolfcrypt_rs::wc_RsaPrivateKeyDecode(
der.as_ptr(),
&mut idx,
key,
len_as_u32(der.len()),
)
};
if rc != 0 {
unsafe { wolfcrypt_rs::wc_DeleteRsaKey(key, ptr::null_mut()); }
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaPrivateKeyDecode" });
}
Ok(Self { key })
}
pub fn from_public_der(der: &[u8]) -> Result<Self, WolfCryptError> {
let key = Self::alloc()?;
let mut idx: u32 = 0;
let rc = unsafe {
wolfcrypt_rs::wc_RsaPublicKeyDecode(
der.as_ptr(),
&mut idx,
key,
len_as_u32(der.len()),
)
};
if rc != 0 {
unsafe { wolfcrypt_rs::wc_DeleteRsaKey(key, ptr::null_mut()); }
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaPublicKeyDecode" });
}
Ok(Self { key })
}
pub fn generate(bits: u32, rng: &mut crate::rand::WolfRng) -> Result<Self, WolfCryptError> {
let key = Self::alloc()?;
let rc = unsafe {
wolfcrypt_rs::wc_MakeRsaKey(
key,
bits as core::ffi::c_int,
65537, &mut rng.rng,
)
};
if rc != 0 {
unsafe { wolfcrypt_rs::wc_DeleteRsaKey(key, ptr::null_mut()); }
return Err(WolfCryptError::Ffi { code: rc, func: "wc_MakeRsaKey" });
}
Ok(Self { key })
}
pub fn encrypt_size(&self) -> Result<usize, WolfCryptError> {
let sz = unsafe { wolfcrypt_rs::wc_RsaEncryptSize(self.key as *const _) };
if sz <= 0 {
return Err(WolfCryptError::Ffi { code: sz, func: "wc_RsaEncryptSize" });
}
Ok(sz as usize)
}
pub fn rsa_direct(
&mut self,
input: &[u8],
type_: RsaDirectType,
rng: &mut crate::rand::WolfRng,
) -> Result<Vec<u8>, WolfCryptError> {
let key_sz = self.encrypt_size()?;
if input.len() != key_sz {
return Err(WolfCryptError::InvalidInput);
}
let mut out = vec![0u8; key_sz];
let mut out_len: u32 = key_sz as u32;
let rc = unsafe {
wolfcrypt_rs::wc_RsaFunction(
input.as_ptr(),
len_as_u32(input.len()),
out.as_mut_ptr(),
&mut out_len,
type_.as_c_int(),
self.key,
&mut rng.rng,
)
};
check(rc, "wc_RsaFunction")?;
out.truncate(out_len as usize);
Ok(out)
}
pub fn from_raw_components(
n: &[u8],
e: &[u8],
d: &[u8],
p: &[u8],
q: &[u8],
iqmp: &[u8],
) -> Result<Self, WolfCryptError> {
let key = Self::alloc()?;
let rc = unsafe {
wolfcrypt_rs::wc_RsaPrivateKeyDecodeRaw(
n.as_ptr(), len_as_u32(n.len()),
e.as_ptr(), len_as_u32(e.len()),
d.as_ptr(), len_as_u32(d.len()),
iqmp.as_ptr(), len_as_u32(iqmp.len()),
p.as_ptr(), len_as_u32(p.len()),
q.as_ptr(), len_as_u32(q.len()),
ptr::null(), 0, ptr::null(), 0, key,
)
};
if rc != 0 {
unsafe { wolfcrypt_rs::wc_DeleteRsaKey(key, ptr::null_mut()) };
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaPrivateKeyDecodeRaw" });
}
Ok(Self { key })
}
pub fn key_size(&self) -> Result<usize, WolfCryptError> {
let rc = unsafe { wolfcrypt_rs::wc_RsaEncryptSize(self.key) };
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaEncryptSize" });
}
Ok(rc as usize)
}
pub fn sign_pkcs1v15_raw(
&self,
digest_info: &[u8],
rng: &mut crate::rand::WolfRng,
) -> Result<alloc::vec::Vec<u8>, WolfCryptError> {
let key_sz = self.key_size()?;
let mut out = alloc::vec![0u8; key_sz];
let rc = unsafe {
wolfcrypt_rs::wc_RsaSSL_Sign(
digest_info.as_ptr(),
len_as_u32(digest_info.len()),
out.as_mut_ptr(),
len_as_u32(out.len()),
self.key,
&mut rng.rng,
)
};
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaSSL_Sign" });
}
out.truncate(rc as usize);
Ok(out)
}
pub fn verify_pkcs1v15_raw(
&self,
signature: &[u8],
) -> Result<alloc::vec::Vec<u8>, WolfCryptError> {
let key_sz = self.key_size()?;
let mut out = alloc::vec![0u8; key_sz];
let rc = unsafe {
wolfcrypt_rs::wc_RsaSSL_Verify(
signature.as_ptr(),
len_as_u32(signature.len()),
out.as_mut_ptr(),
len_as_u32(out.len()),
self.key,
)
};
if rc < 0 {
return Err(WolfCryptError::Ffi { code: rc, func: "wc_RsaSSL_Verify" });
}
out.truncate(rc as usize);
Ok(out)
}
pub fn export_raw_components(
&mut self,
) -> Result<RsaRawComponents, WolfCryptError> {
let sz = self.key_size()?;
let mut e = alloc::vec![0u8; sz];
let mut n = alloc::vec![0u8; sz];
let mut d = alloc::vec![0u8; sz];
let mut p = alloc::vec![0u8; sz];
let mut q = alloc::vec![0u8; sz];
let mut e_sz = len_as_u32(e.len());
let mut n_sz = len_as_u32(n.len());
let mut d_sz = len_as_u32(d.len());
let mut p_sz = len_as_u32(p.len());
let mut q_sz = len_as_u32(q.len());
let rc = unsafe {
wolfcrypt_rs::wc_RsaExportKey(
self.key,
e.as_mut_ptr(), &mut e_sz,
n.as_mut_ptr(), &mut n_sz,
d.as_mut_ptr(), &mut d_sz,
p.as_mut_ptr(), &mut p_sz,
q.as_mut_ptr(), &mut q_sz,
)
};
check(rc, "wc_RsaExportKey")?;
e.truncate(e_sz as usize);
n.truncate(n_sz as usize);
d.truncate(d_sz as usize);
p.truncate(p_sz as usize);
q.truncate(q_sz as usize);
let der = self.to_pkcs1_der()?;
let iqmp = extract_iqmp_from_pkcs1_der(&der)?;
Ok(RsaRawComponents { e, n, d, p, q, iqmp })
}
pub fn from_raw_public(n: &[u8], e: &[u8]) -> Result<Self, WolfCryptError> {
let der = build_pkcs1_public_key_der(n, e);
Self::from_public_der(&der)
}
}
#[cfg(feature = "rsa-direct")]
pub struct RsaRawComponents {
pub e: alloc::vec::Vec<u8>,
pub n: alloc::vec::Vec<u8>,
pub d: alloc::vec::Vec<u8>,
pub p: alloc::vec::Vec<u8>,
pub q: alloc::vec::Vec<u8>,
pub iqmp: alloc::vec::Vec<u8>,
}
#[cfg(feature = "rsa-direct")]
fn build_pkcs1_public_key_der(n: &[u8], e: &[u8]) -> alloc::vec::Vec<u8> {
let n_der = der_encode_unsigned_integer(n);
let e_der = der_encode_unsigned_integer(e);
let content_len = n_der.len() + e_der.len();
let mut der = alloc::vec::Vec::with_capacity(content_len + 10);
der.push(0x30); der_push_length(content_len, &mut der);
der.extend_from_slice(&n_der);
der.extend_from_slice(&e_der);
der
}
#[cfg(feature = "rsa-direct")]
fn der_encode_unsigned_integer(bytes: &[u8]) -> alloc::vec::Vec<u8> {
if bytes.is_empty() {
return alloc::vec![0x02, 0x01, 0x00];
}
let significant = match bytes.iter().position(|&b| b != 0) {
Some(i) => &bytes[i..],
None => &bytes[bytes.len() - 1..], };
let needs_pad = significant[0] & 0x80 != 0;
let value_len = significant.len() + usize::from(needs_pad);
let mut out = alloc::vec::Vec::with_capacity(value_len + 4);
out.push(0x02); der_push_length(value_len, &mut out);
if needs_pad {
out.push(0x00);
}
out.extend_from_slice(significant);
out
}
#[cfg(feature = "rsa-direct")]
fn der_push_length(len: usize, out: &mut alloc::vec::Vec<u8>) {
if len < 0x80 {
out.push(len as u8);
} else if len < 0x100 {
out.push(0x81);
out.push(len as u8);
} else {
out.push(0x82);
out.push((len >> 8) as u8);
out.push(len as u8);
}
}
#[cfg(feature = "rsa-direct")]
fn extract_iqmp_from_pkcs1_der(der: &[u8]) -> Result<alloc::vec::Vec<u8>, WolfCryptError> {
let err = || WolfCryptError::Ffi { code: -1, func: "extract_iqmp_from_pkcs1_der" };
let mut pos = 0;
if pos >= der.len() || der[pos] != 0x30 { return Err(err()); }
pos = pos.checked_add(1).ok_or_else(err)?;
let (_seq_len, hdr) = der_read_len(der, pos).ok_or_else(err)?;
pos = pos.checked_add(hdr).ok_or_else(err)?;
for _ in 0..8 {
pos = der_skip_int(der, pos).ok_or_else(err)?;
}
let val = der_read_int(der, pos).ok_or_else(err)?;
Ok(val.to_vec())
}
#[cfg(feature = "rsa-direct")]
fn der_read_len(data: &[u8], pos: usize) -> Option<(usize, usize)> {
let b = *data.get(pos)?;
if b < 0x80 {
Some((b as usize, 1))
} else {
let n = (b & 0x7f) as usize;
if n == 0 || n > 4 { return None; }
let end = pos.checked_add(1)?.checked_add(n)?;
if end > data.len() { return None; }
let mut len = 0usize;
for i in 0..n {
len = len.checked_shl(8)? | (*data.get(pos + 1 + i)? as usize);
}
Some((len, 1 + n))
}
}
#[cfg(feature = "rsa-direct")]
fn der_read_int(data: &[u8], pos: usize) -> Option<&[u8]> {
if *data.get(pos)? != 0x02 { return None; }
let (len, hdr) = der_read_len(data, pos.checked_add(1)?)?;
let start = pos.checked_add(1)?.checked_add(hdr)?;
let end = start.checked_add(len)?;
if end > data.len() { return None; }
let mut val = &data[start..end];
while val.len() > 1 && val[0] == 0 { val = &val[1..]; }
Some(val)
}
#[cfg(feature = "rsa-direct")]
fn der_skip_int(data: &[u8], pos: usize) -> Option<usize> {
if *data.get(pos)? != 0x02 { return None; }
let (len, hdr) = der_read_len(data, pos.checked_add(1)?)?;
let end = pos.checked_add(1)?.checked_add(hdr)?.checked_add(len)?;
if end > data.len() { return None; }
Some(end)
}
#[cfg(feature = "rsa-direct")]
impl Drop for NativeRsaKey {
fn drop(&mut self) {
if !self.key.is_null() {
unsafe {
wolfcrypt_rs::wc_DeleteRsaKey(self.key, ptr::null_mut());
}
}
}
}