Make it possible to use cmac
This adds Signer::new_without_digest to create Signers which don't have a digest (like cmac, which is based on aes). As openssl supports cmac since version 1.1.0, the functions are behind the ossl110 feature. This allows building CMAC/OMAC1 and the EAX AEAD on top of this library.
This commit is contained in:
parent
66a2ad76b7
commit
0860115156
|
|
@ -221,6 +221,7 @@ pub const PEM_R_NO_START_LINE: c_int = 108;
|
|||
pub const EVP_MAX_MD_SIZE: c_uint = 64;
|
||||
pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption;
|
||||
pub const EVP_PKEY_HMAC: c_int = NID_hmac;
|
||||
pub const EVP_PKEY_CMAC: c_int = NID_cmac;
|
||||
pub const EVP_PKEY_DSA: c_int = NID_dsa;
|
||||
pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement;
|
||||
pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;
|
||||
|
|
@ -233,6 +234,10 @@ pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2;
|
|||
pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5;
|
||||
pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6;
|
||||
|
||||
pub const EVP_PKEY_CTRL_SET_MAC_KEY: c_int = 6;
|
||||
pub const EVP_PKEY_CTRL_CIPHER: c_int = 12;
|
||||
|
||||
pub const EVP_PKEY_OP_KEYGEN: c_int = 1 << 2;
|
||||
pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3;
|
||||
pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4;
|
||||
pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5;
|
||||
|
|
@ -2093,6 +2098,7 @@ extern "C" {
|
|||
) -> *mut EVP_PKEY;
|
||||
|
||||
pub fn EVP_PKEY_CTX_new(k: *mut EVP_PKEY, e: *mut ENGINE) -> *mut EVP_PKEY_CTX;
|
||||
pub fn EVP_PKEY_CTX_new_id(id: c_int, e: *mut ENGINE) -> *mut EVP_PKEY_CTX;
|
||||
pub fn EVP_PKEY_CTX_free(ctx: *mut EVP_PKEY_CTX);
|
||||
pub fn EVP_PKEY_CTX_ctrl(
|
||||
ctx: *mut EVP_PKEY_CTX,
|
||||
|
|
@ -2103,6 +2109,9 @@ extern "C" {
|
|||
p2: *mut c_void,
|
||||
) -> c_int;
|
||||
|
||||
pub fn EVP_PKEY_keygen_init(ctx: *mut EVP_PKEY_CTX) -> c_int;
|
||||
pub fn EVP_PKEY_keygen(ctx: *mut EVP_PKEY_CTX, key: *mut *mut EVP_PKEY) -> c_int;
|
||||
|
||||
pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int;
|
||||
|
||||
pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int;
|
||||
|
|
|
|||
|
|
@ -365,6 +365,68 @@ impl PKey<Private> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new `PKey` containing a CMAC key.
|
||||
///
|
||||
/// CMAC is only supported since the version 1.1.0 of OpenSSL.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// To compute CMAC values, use the `sign` module.
|
||||
#[cfg(any(all(ossl110, feature = "v110"), all(ossl111, feature = "v111")))]
|
||||
pub fn cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result<PKey<Private>, ErrorStack> {
|
||||
unsafe {
|
||||
assert!(key.len() <= c_int::max_value() as usize);
|
||||
let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(
|
||||
ffi::EVP_PKEY_CMAC,
|
||||
ptr::null_mut(),
|
||||
))?;
|
||||
|
||||
let ret = (|| {
|
||||
cvt(ffi::EVP_PKEY_keygen_init(kctx))?;
|
||||
|
||||
// Set cipher for cmac
|
||||
cvt(ffi::EVP_PKEY_CTX_ctrl(
|
||||
kctx,
|
||||
-1,
|
||||
ffi::EVP_PKEY_OP_KEYGEN,
|
||||
ffi::EVP_PKEY_CTRL_CIPHER,
|
||||
0,
|
||||
cipher.as_ptr() as *mut _,
|
||||
))?;
|
||||
|
||||
// Set the key data
|
||||
cvt(ffi::EVP_PKEY_CTX_ctrl(
|
||||
kctx,
|
||||
-1,
|
||||
ffi::EVP_PKEY_OP_KEYGEN,
|
||||
ffi::EVP_PKEY_CTRL_SET_MAC_KEY,
|
||||
key.len() as c_int,
|
||||
key.as_ptr() as *mut _,
|
||||
))?;
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
if let Err(e) = ret {
|
||||
// Free memory
|
||||
ffi::EVP_PKEY_CTX_free(kctx);
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
// Generate key
|
||||
let mut key = ptr::null_mut();
|
||||
let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key));
|
||||
|
||||
// Free memory
|
||||
ffi::EVP_PKEY_CTX_free(kctx);
|
||||
|
||||
if let Err(e) = ret {
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
Ok(PKey::from_ptr(key))
|
||||
}
|
||||
}
|
||||
|
||||
private_key_from_pem! {
|
||||
/// Deserializes a private key from a PEM-encoded key type specific format.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -127,6 +127,26 @@ impl<'a> Signer<'a> {
|
|||
///
|
||||
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
||||
pub fn new<T>(type_: MessageDigest, pkey: &'a PKeyRef<T>) -> Result<Signer<'a>, ErrorStack>
|
||||
where
|
||||
T: HasPrivate,
|
||||
{
|
||||
Self::new_intern(Some(type_), pkey)
|
||||
}
|
||||
|
||||
/// Creates a new `Signer` without a digest.
|
||||
///
|
||||
/// This can be used to create a CMAC.
|
||||
/// OpenSSL documentation at [`EVP_DigestSignInit`].
|
||||
///
|
||||
/// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html
|
||||
pub fn new_without_digest<T>(pkey: &'a PKeyRef<T>) -> Result<Signer<'a>, ErrorStack>
|
||||
where
|
||||
T: HasPrivate,
|
||||
{
|
||||
Self::new_intern(None, pkey)
|
||||
}
|
||||
|
||||
pub fn new_intern<T>(type_: Option<MessageDigest>, pkey: &'a PKeyRef<T>) -> Result<Signer<'a>, ErrorStack>
|
||||
where
|
||||
T: HasPrivate,
|
||||
{
|
||||
|
|
@ -138,7 +158,7 @@ impl<'a> Signer<'a> {
|
|||
let r = ffi::EVP_DigestSignInit(
|
||||
ctx,
|
||||
&mut pctx,
|
||||
type_.as_ptr(),
|
||||
type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()),
|
||||
ptr::null_mut(),
|
||||
pkey.as_ptr(),
|
||||
);
|
||||
|
|
@ -638,6 +658,21 @@ mod test {
|
|||
test_hmac(MessageDigest::sha1(), &tests);
|
||||
}
|
||||
|
||||
#[cfg(ossl110)]
|
||||
#[test]
|
||||
fn test_cmac() {
|
||||
let cipher = ::symm::Cipher::aes_128_cbc();
|
||||
let key = Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap();
|
||||
let pkey = PKey::cmac(&cipher, &key).unwrap();
|
||||
let mut signer = Signer::new_without_digest(&pkey).unwrap();
|
||||
|
||||
let data = b"Hi There";
|
||||
signer.update(data as &[u8]).unwrap();
|
||||
|
||||
let expected = vec![136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19];
|
||||
assert_eq!(signer.sign_to_vec().unwrap(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ec() {
|
||||
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
|
||||
|
|
|
|||
Loading…
Reference in New Issue