#![cfg_attr(
not(boringssl),
doc = r#"\
Generate a CMAC key
```
use openssl::pkey_ctx::PkeyCtx;
use openssl::pkey::Id;
use openssl::cipher::Cipher;
let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
ctx.keygen_init().unwrap();
ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap();
let cmac_key = ctx.keygen().unwrap();
```"#
)]
#[cfg(not(boringssl))]
use crate::cipher::CipherRef;
use crate::error::ErrorStack;
use crate::md::MdRef;
use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private};
use crate::rsa::Padding;
use crate::sign::RsaPssSaltlen;
use crate::{cvt, cvt_p};
use foreign_types::{ForeignType, ForeignTypeRef};
#[cfg(not(boringssl))]
use libc::c_int;
#[cfg(ossl320)]
use libc::c_uint;
use openssl_macros::corresponds;
use std::convert::TryFrom;
#[cfg(ossl320)]
use std::ffi::CStr;
use std::ptr;
#[cfg(any(ossl111, libressl360))]
pub struct HkdfMode(c_int);
#[cfg(any(ossl111, libressl360))]
impl HkdfMode {
pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND);
pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY);
pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
}
#[cfg(ossl320)]
#[derive(Debug, PartialEq)]
pub struct NonceType(c_uint);
#[cfg(ossl320)]
impl NonceType {
pub const RANDOM_K: Self = NonceType(0);
pub const DETERMINISTIC_K: Self = NonceType(1);
}
generic_foreign_type_and_impl_send_sync! {
type CType = ffi::EVP_PKEY_CTX;
fn drop = ffi::EVP_PKEY_CTX_free;
pub struct PkeyCtx<T>;
pub struct PkeyCtxRef<T>;
}
impl<T> PkeyCtx<T> {
#[corresponds(EVP_PKEY_CTX_new)]
#[inline]
pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> {
unsafe {
let ptr = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?;
Ok(PkeyCtx::from_ptr(ptr))
}
}
}
impl PkeyCtx<()> {
#[corresponds(EVP_PKEY_new_id)]
#[inline]
pub fn new_id(id: Id) -> Result<Self, ErrorStack> {
unsafe {
let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?;
Ok(PkeyCtx::from_ptr(ptr))
}
}
}
impl<T> PkeyCtxRef<T>
where
T: HasPublic,
{
#[corresponds(EVP_PKEY_encrypt_init)]
#[inline]
pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_verify_init)]
#[inline]
pub fn verify_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_verify_recover_init)]
#[inline]
pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_verify_recover_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_encrypt)]
#[inline]
pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
let mut written = to.as_ref().map_or(0, |b| b.len());
unsafe {
cvt(ffi::EVP_PKEY_encrypt(
self.as_ptr(),
to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
&mut written,
from.as_ptr(),
from.len(),
))?;
}
Ok(written)
}
pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
let base = out.len();
let len = self.encrypt(from, None)?;
out.resize(base + len, 0);
let len = self.encrypt(from, Some(&mut out[base..]))?;
out.truncate(base + len);
Ok(len)
}
#[corresponds(EVP_PKEY_verify)]
#[inline]
pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> {
unsafe {
let r = ffi::EVP_PKEY_verify(
self.as_ptr(),
sig.as_ptr(),
sig.len(),
data.as_ptr(),
data.len(),
);
if r <= 0 {
let errors = ErrorStack::get();
if !errors.errors().is_empty() {
return Err(errors);
}
}
Ok(r == 1)
}
}
#[corresponds(EVP_PKEY_verify_recover)]
#[inline]
pub fn verify_recover(
&mut self,
sig: &[u8],
to: Option<&mut [u8]>,
) -> Result<usize, ErrorStack> {
let mut written = to.as_ref().map_or(0, |b| b.len());
unsafe {
cvt(ffi::EVP_PKEY_verify_recover(
self.as_ptr(),
to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
&mut written,
sig.as_ptr(),
sig.len(),
))?;
}
Ok(written)
}
}
impl<T> PkeyCtxRef<T>
where
T: HasPrivate,
{
#[corresponds(EVP_PKEY_decrypt_init)]
#[inline]
pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_sign_init)]
#[inline]
pub fn sign_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_derive_set_peer)]
pub fn derive_set_peer<U>(&mut self, key: &PKeyRef<U>) -> Result<(), ErrorStack>
where
U: HasPublic,
{
unsafe {
cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_decrypt)]
#[inline]
pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
let mut written = to.as_ref().map_or(0, |b| b.len());
unsafe {
cvt(ffi::EVP_PKEY_decrypt(
self.as_ptr(),
to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
&mut written,
from.as_ptr(),
from.len(),
))?;
}
Ok(written)
}
pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> {
let base = out.len();
let len = self.decrypt(from, None)?;
out.resize(base + len, 0);
let len = self.decrypt(from, Some(&mut out[base..]))?;
out.truncate(base + len);
Ok(len)
}
#[corresponds(EVP_PKEY_sign)]
#[inline]
pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
let mut written = sig.as_ref().map_or(0, |b| b.len());
unsafe {
cvt(ffi::EVP_PKEY_sign(
self.as_ptr(),
sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
&mut written,
data.as_ptr(),
data.len(),
))?;
}
Ok(written)
}
pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec<u8>) -> Result<usize, ErrorStack> {
let base = sig.len();
let len = self.sign(data, None)?;
sig.resize(base + len, 0);
let len = self.sign(data, Some(&mut sig[base..]))?;
sig.truncate(base + len);
Ok(len)
}
}
impl<T> PkeyCtxRef<T> {
#[corresponds(EVP_PKEY_derive_init)]
#[inline]
pub fn derive_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_keygen_init)]
#[inline]
pub fn keygen_init(&mut self) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set_signature_md)]
#[inline]
pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_signature_md(
self.as_ptr(),
md.as_ptr(),
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_get_rsa_padding)]
#[inline]
pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> {
let mut pad = 0;
unsafe {
cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?;
}
Ok(Padding::from_raw(pad))
}
#[corresponds(EVP_PKEY_CTX_set_rsa_padding)]
#[inline]
pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(
self.as_ptr(),
padding.as_raw(),
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)]
#[inline]
pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen(
self.as_ptr(),
len.as_raw(),
))
.map(|_| ())
}
}
#[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)]
#[inline]
pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md(
self.as_ptr(),
md.as_ptr(),
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)]
#[cfg(any(ossl102, libressl310, boringssl))]
#[inline]
pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md(
self.as_ptr(),
md.as_ptr() as *mut _,
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)]
#[cfg(any(ossl102, libressl310, boringssl))]
pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> {
use crate::LenType;
let len = LenType::try_from(label.len()).unwrap();
unsafe {
let p = ffi::OPENSSL_malloc(label.len() as _);
ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len());
let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label(
self.as_ptr(),
p as *mut _,
len,
));
if r.is_err() {
ffi::OPENSSL_free(p);
}
r?;
}
Ok(())
}
#[cfg(not(boringssl))]
#[corresponds(EVP_PKEY_CTX_ctrl)]
#[inline]
pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_ctrl(
self.as_ptr(),
-1,
ffi::EVP_PKEY_OP_KEYGEN,
ffi::EVP_PKEY_CTRL_CIPHER,
0,
cipher.as_ptr() as *mut _,
))?;
}
Ok(())
}
#[cfg(not(boringssl))]
#[corresponds(EVP_PKEY_CTX_ctrl)]
#[inline]
pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> {
let len = c_int::try_from(key.len()).unwrap();
unsafe {
cvt(ffi::EVP_PKEY_CTX_ctrl(
self.as_ptr(),
-1,
ffi::EVP_PKEY_OP_KEYGEN,
ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
len,
key.as_ptr() as *mut _,
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set_hkdf_md)]
#[cfg(any(ossl110, boringssl, libressl360))]
#[inline]
pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_hkdf_md(
self.as_ptr(),
digest.as_ptr(),
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set_hkdf_mode)]
#[cfg(any(ossl111, libressl360))]
#[inline]
pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> {
unsafe {
cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set1_hkdf_key)]
#[cfg(any(ossl110, boringssl, libressl360))]
#[inline]
pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> {
#[cfg(not(boringssl))]
let len = c_int::try_from(key.len()).unwrap();
#[cfg(boringssl)]
let len = key.len();
unsafe {
cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key(
self.as_ptr(),
key.as_ptr(),
len,
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)]
#[cfg(any(ossl110, boringssl, libressl360))]
#[inline]
pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> {
#[cfg(not(boringssl))]
let len = c_int::try_from(salt.len()).unwrap();
#[cfg(boringssl)]
let len = salt.len();
unsafe {
cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt(
self.as_ptr(),
salt.as_ptr(),
len,
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_CTX_add1_hkdf_info)]
#[cfg(any(ossl110, boringssl, libressl360))]
#[inline]
pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> {
#[cfg(not(boringssl))]
let len = c_int::try_from(info.len()).unwrap();
#[cfg(boringssl)]
let len = info.len();
unsafe {
cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info(
self.as_ptr(),
info.as_ptr(),
len,
))?;
}
Ok(())
}
#[corresponds(EVP_PKEY_derive)]
pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result<usize, ErrorStack> {
let mut len = buf.as_ref().map_or(0, |b| b.len());
unsafe {
cvt(ffi::EVP_PKEY_derive(
self.as_ptr(),
buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()),
&mut len,
))?;
}
Ok(len)
}
pub fn derive_to_vec(&mut self, buf: &mut Vec<u8>) -> Result<usize, ErrorStack> {
let base = buf.len();
let len = self.derive(None)?;
buf.resize(base + len, 0);
let len = self.derive(Some(&mut buf[base..]))?;
buf.truncate(base + len);
Ok(len)
}
#[corresponds(EVP_PKEY_keygen)]
#[inline]
pub fn keygen(&mut self) -> Result<PKey<Private>, ErrorStack> {
unsafe {
let mut key = ptr::null_mut();
cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?;
Ok(PKey::from_ptr(key))
}
}
#[cfg(ossl320)]
#[corresponds(EVP_PKEY_CTX_set_params)]
pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> {
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
let mut nonce_type = nonce_type.0;
unsafe {
let param_nonce =
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
let param_end = ffi::OSSL_PARAM_construct_end();
let params = [param_nonce, param_end];
cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?;
}
Ok(())
}
#[cfg(ossl320)]
#[corresponds(EVP_PKEY_CTX_get_params)]
pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> {
let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap();
let mut nonce_type: c_uint = 0;
unsafe {
let param_nonce =
ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type);
let param_end = ffi::OSSL_PARAM_construct_end();
let mut params = [param_nonce, param_end];
cvt(ffi::EVP_PKEY_CTX_get_params(
self.as_ptr(),
params.as_mut_ptr(),
))?;
}
Ok(NonceType(nonce_type))
}
}
#[cfg(test)]
mod test {
use super::*;
#[cfg(not(boringssl))]
use crate::cipher::Cipher;
use crate::ec::{EcGroup, EcKey};
use crate::hash::{hash, MessageDigest};
use crate::md::Md;
use crate::nid::Nid;
use crate::pkey::PKey;
use crate::rsa::Rsa;
use crate::sign::Verifier;
#[test]
fn rsa() {
let key = include_bytes!("../test/rsa.pem");
let rsa = Rsa::private_key_from_pem(key).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let mut ctx = PkeyCtx::new(&pkey).unwrap();
ctx.encrypt_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
let pt = "hello world".as_bytes();
let mut ct = vec![];
ctx.encrypt_to_vec(pt, &mut ct).unwrap();
ctx.decrypt_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
let mut out = vec![];
ctx.decrypt_to_vec(&ct, &mut out).unwrap();
assert_eq!(pt, out);
}
#[test]
#[cfg(any(ossl102, libressl310, boringssl))]
fn rsa_oaep() {
let key = include_bytes!("../test/rsa.pem");
let rsa = Rsa::private_key_from_pem(key).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let mut ctx = PkeyCtx::new(&pkey).unwrap();
ctx.encrypt_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap();
ctx.set_rsa_oaep_md(Md::sha256()).unwrap();
ctx.set_rsa_mgf1_md(Md::sha256()).unwrap();
let pt = "hello world".as_bytes();
let mut ct = vec![];
ctx.encrypt_to_vec(pt, &mut ct).unwrap();
ctx.decrypt_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap();
ctx.set_rsa_oaep_md(Md::sha256()).unwrap();
ctx.set_rsa_mgf1_md(Md::sha256()).unwrap();
let mut out = vec![];
ctx.decrypt_to_vec(&ct, &mut out).unwrap();
assert_eq!(pt, out);
}
#[test]
fn rsa_sign() {
let key = include_bytes!("../test/rsa.pem");
let rsa = Rsa::private_key_from_pem(key).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let mut ctx = PkeyCtx::new(&pkey).unwrap();
ctx.sign_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
ctx.set_signature_md(Md::sha384()).unwrap();
let msg = b"hello world";
let digest = hash(MessageDigest::sha384(), msg).unwrap();
let mut signature = vec![];
ctx.sign_to_vec(&digest, &mut signature).unwrap();
let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap();
verifier.update(msg).unwrap();
assert!(matches!(verifier.verify(&signature), Ok(true)));
}
#[test]
fn rsa_sign_pss() {
let key = include_bytes!("../test/rsa.pem");
let rsa = Rsa::private_key_from_pem(key).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let mut ctx = PkeyCtx::new(&pkey).unwrap();
ctx.sign_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
ctx.set_signature_md(Md::sha384()).unwrap();
ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap();
let msg = b"hello world";
let digest = hash(MessageDigest::sha384(), msg).unwrap();
let mut signature = vec![];
ctx.sign_to_vec(&digest, &mut signature).unwrap();
let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap();
verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
verifier
.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14))
.unwrap();
verifier.update(msg).unwrap();
assert!(matches!(verifier.verify(&signature), Ok(true)));
}
#[test]
fn derive() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let key1 = EcKey::generate(&group).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();
let key2 = EcKey::generate(&group).unwrap();
let key2 = PKey::from_ec_key(key2).unwrap();
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.derive_init().unwrap();
ctx.derive_set_peer(&key2).unwrap();
let mut buf = vec![];
ctx.derive_to_vec(&mut buf).unwrap();
}
#[test]
#[cfg(not(boringssl))]
fn cmac_keygen() {
let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap();
ctx.keygen_init().unwrap();
ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap();
ctx.set_keygen_mac_key(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d").unwrap())
.unwrap();
ctx.keygen().unwrap();
}
#[test]
#[cfg(any(ossl110, boringssl, libressl360))]
fn hkdf() {
let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
ctx.derive_init().unwrap();
ctx.set_hkdf_md(Md::sha256()).unwrap();
ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap())
.unwrap();
ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap())
.unwrap();
ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap())
.unwrap();
let mut out = [0; 42];
ctx.derive(Some(&mut out)).unwrap();
assert_eq!(
&out[..],
hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
.unwrap()
);
}
#[test]
#[cfg(any(ossl111, libressl360))]
fn hkdf_expand() {
let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
ctx.derive_init().unwrap();
ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap();
ctx.set_hkdf_md(Md::sha256()).unwrap();
ctx.set_hkdf_key(
&hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")
.unwrap(),
)
.unwrap();
ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap())
.unwrap();
let mut out = [0; 42];
ctx.derive(Some(&mut out)).unwrap();
assert_eq!(
&out[..],
hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865")
.unwrap()
);
}
#[test]
#[cfg(any(ossl111, libressl360))]
fn hkdf_extract() {
let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap();
ctx.derive_init().unwrap();
ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap();
ctx.set_hkdf_md(Md::sha256()).unwrap();
ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap())
.unwrap();
ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap())
.unwrap();
let mut out = vec![];
ctx.derive_to_vec(&mut out).unwrap();
assert_eq!(
&out[..],
hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5")
.unwrap()
);
}
#[test]
fn verify_fail() {
let key1 = Rsa::generate(4096).unwrap();
let key1 = PKey::from_rsa(key1).unwrap();
let data = b"Some Crypto Text";
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.sign_init().unwrap();
let mut signature = vec![];
ctx.sign_to_vec(data, &mut signature).unwrap();
let bad_data = b"Some Crypto text";
ctx.verify_init().unwrap();
let valid = ctx.verify(bad_data, &signature);
assert!(matches!(valid, Ok(false) | Err(_)));
assert!(ErrorStack::get().errors().is_empty());
}
#[test]
fn verify_fail_ec() {
let key1 =
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();
let data = b"Some Crypto Text";
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.verify_init().unwrap();
assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_)));
assert!(ErrorStack::get().errors().is_empty());
}
#[test]
fn test_verify_recover() {
let key = Rsa::generate(2048).unwrap();
let key = PKey::from_rsa(key).unwrap();
let digest = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
];
let mut ctx = PkeyCtx::new(&key).unwrap();
ctx.sign_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
ctx.set_signature_md(Md::sha256()).unwrap();
let mut signature = vec![];
ctx.sign_to_vec(&digest, &mut signature).unwrap();
let mut ctx = PkeyCtx::new(&key).unwrap();
ctx.verify_recover_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
ctx.set_signature_md(Md::sha256()).unwrap();
let length = ctx.verify_recover(&signature, None).unwrap();
let mut result_buf = vec![0; length];
let length = ctx
.verify_recover(&signature, Some(&mut result_buf))
.unwrap();
assert_eq!(length, digest.len());
assert_eq!(result_buf[..length], digest);
let mut ctx = PkeyCtx::new(&key).unwrap();
ctx.verify_recover_init().unwrap();
ctx.set_rsa_padding(Padding::PKCS1).unwrap();
let length = ctx.verify_recover(&signature, None).unwrap();
let mut result_buf = vec![0; length];
let length = ctx
.verify_recover(&signature, Some(&mut result_buf))
.unwrap();
assert_eq!(length, 51);
assert_eq!(result_buf[length - digest.len()..length], digest);
}
#[test]
#[cfg(ossl320)]
fn set_nonce_type() {
let key1 =
EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.sign_init().unwrap();
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
let nonce_type = ctx.nonce_type().unwrap();
assert_eq!(nonce_type, NonceType::DETERMINISTIC_K);
assert!(ErrorStack::get().errors().is_empty());
}
#[test]
#[cfg(ossl320)]
fn ecdsa_deterministic_signature() {
let private_key_pem = "-----BEGIN PRIVATE KEY-----
MDkCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEHzAdAgEBBBhvqwNJNOTA/Jrmf1tWWanX0f79GH7g
n9Q=
-----END PRIVATE KEY-----";
let key1 = EcKey::private_key_from_pem(private_key_pem.as_bytes()).unwrap();
let key1 = PKey::from_ec_key(key1).unwrap();
let input = "sample";
let expected_output = hex::decode("303502190098C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF021857A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64").unwrap();
let hashed_input = hash(MessageDigest::sha1(), input.as_bytes()).unwrap();
let mut ctx = PkeyCtx::new(&key1).unwrap();
ctx.sign_init().unwrap();
ctx.set_signature_md(Md::sha1()).unwrap();
ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap();
let mut output = vec![];
ctx.sign_to_vec(&hashed_input, &mut output).unwrap();
assert_eq!(output, expected_output);
assert!(ErrorStack::get().errors().is_empty());
}
}