| 1 | //! The asymmetric encryption context. |
| 2 | //! |
| 3 | //! # Examples |
| 4 | //! |
| 5 | //! Encrypt data with RSA |
| 6 | //! |
| 7 | //! ``` |
| 8 | //! use openssl::rsa::Rsa; |
| 9 | //! use openssl::pkey::PKey; |
| 10 | //! use openssl::pkey_ctx::PkeyCtx; |
| 11 | //! |
| 12 | //! let key = Rsa::generate(4096).unwrap(); |
| 13 | //! let key = PKey::from_rsa(key).unwrap(); |
| 14 | //! |
| 15 | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 16 | //! ctx.encrypt_init().unwrap(); |
| 17 | //! |
| 18 | //! let data = b"Some Crypto Text" ; |
| 19 | //! let mut ciphertext = vec![]; |
| 20 | //! ctx.encrypt_to_vec(data, &mut ciphertext).unwrap(); |
| 21 | //! ``` |
| 22 | |
| 23 | #![cfg_attr ( |
| 24 | not(any(boringssl, awslc)), |
| 25 | doc = r#"\ |
| 26 | Generate a CMAC key |
| 27 | |
| 28 | ``` |
| 29 | use openssl::pkey_ctx::PkeyCtx; |
| 30 | use openssl::pkey::Id; |
| 31 | use openssl::cipher::Cipher; |
| 32 | |
| 33 | let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); |
| 34 | ctx.keygen_init().unwrap(); |
| 35 | ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); |
| 36 | ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap(); |
| 37 | let cmac_key = ctx.keygen().unwrap(); |
| 38 | ```"# |
| 39 | )] |
| 40 | |
| 41 | //! |
| 42 | //! Sign and verify data with RSA |
| 43 | //! |
| 44 | //! ``` |
| 45 | //! use openssl::pkey_ctx::PkeyCtx; |
| 46 | //! use openssl::pkey::PKey; |
| 47 | //! use openssl::rsa::Rsa; |
| 48 | //! |
| 49 | //! // Generate a random RSA key. |
| 50 | //! let key = Rsa::generate(4096).unwrap(); |
| 51 | //! let key = PKey::from_rsa(key).unwrap(); |
| 52 | //! |
| 53 | //! let text = b"Some Crypto Text" ; |
| 54 | //! |
| 55 | //! // Create the signature. |
| 56 | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 57 | //! ctx.sign_init().unwrap(); |
| 58 | //! let mut signature = vec![]; |
| 59 | //! ctx.sign_to_vec(text, &mut signature).unwrap(); |
| 60 | //! |
| 61 | //! // Verify the signature. |
| 62 | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 63 | //! ctx.verify_init().unwrap(); |
| 64 | //! let valid = ctx.verify(text, &signature).unwrap(); |
| 65 | //! assert!(valid); |
| 66 | //! ``` |
| 67 | #[cfg (not(any(boringssl, awslc)))] |
| 68 | use crate::cipher::CipherRef; |
| 69 | use crate::error::ErrorStack; |
| 70 | use crate::md::MdRef; |
| 71 | use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private}; |
| 72 | use crate::rsa::Padding; |
| 73 | use crate::sign::RsaPssSaltlen; |
| 74 | use crate::{cvt, cvt_p}; |
| 75 | use foreign_types::{ForeignType, ForeignTypeRef}; |
| 76 | #[cfg (not(any(boringssl, awslc)))] |
| 77 | use libc::c_int; |
| 78 | #[cfg (ossl320)] |
| 79 | use libc::c_uint; |
| 80 | use openssl_macros::corresponds; |
| 81 | use std::convert::TryFrom; |
| 82 | #[cfg (ossl320)] |
| 83 | use std::ffi::CStr; |
| 84 | use std::ptr; |
| 85 | |
| 86 | /// HKDF modes of operation. |
| 87 | #[cfg (any(ossl111, libressl360))] |
| 88 | pub struct HkdfMode(c_int); |
| 89 | |
| 90 | #[cfg (any(ossl111, libressl360))] |
| 91 | impl HkdfMode { |
| 92 | /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up |
| 93 | /// for HKDF will perform an extract followed by an expand operation in one go. The derived key |
| 94 | /// returned will be the result after the expand operation. The intermediate fixed-length |
| 95 | /// pseudorandom key K is not returned. |
| 96 | pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND); |
| 97 | |
| 98 | /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation. |
| 99 | /// The value returned will be the intermediate fixed-length pseudorandom key K. |
| 100 | /// |
| 101 | /// The digest, key and salt values must be set before a key is derived or an error occurs. |
| 102 | pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY); |
| 103 | |
| 104 | /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation. |
| 105 | /// The input key should be set to the intermediate fixed-length pseudorandom key K returned |
| 106 | /// from a previous extract operation. |
| 107 | /// |
| 108 | /// The digest, key and info values must be set before a key is derived or an error occurs. |
| 109 | pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY); |
| 110 | } |
| 111 | |
| 112 | /// Nonce type for ECDSA and DSA. |
| 113 | #[cfg (ossl320)] |
| 114 | #[derive (Debug, PartialEq)] |
| 115 | pub struct NonceType(c_uint); |
| 116 | |
| 117 | #[cfg (ossl320)] |
| 118 | impl NonceType { |
| 119 | /// This is the default mode. It uses a random value for the nonce k as defined in FIPS 186-4 Section 6.3 |
| 120 | /// “Secret Number Generation”. |
| 121 | pub const RANDOM_K: Self = NonceType(0); |
| 122 | |
| 123 | /// Uses a deterministic value for the nonce k as defined in RFC #6979 (See Section 3.2 “Generation of k”). |
| 124 | pub const DETERMINISTIC_K: Self = NonceType(1); |
| 125 | } |
| 126 | |
| 127 | generic_foreign_type_and_impl_send_sync! { |
| 128 | type CType = ffi::EVP_PKEY_CTX; |
| 129 | fn drop = ffi::EVP_PKEY_CTX_free; |
| 130 | |
| 131 | /// A context object which can perform asymmetric cryptography operations. |
| 132 | pub struct PkeyCtx<T>; |
| 133 | /// A reference to a [`PkeyCtx`]. |
| 134 | pub struct PkeyCtxRef<T>; |
| 135 | } |
| 136 | |
| 137 | impl<T> PkeyCtx<T> { |
| 138 | /// Creates a new pkey context using the provided key. |
| 139 | #[corresponds (EVP_PKEY_CTX_new)] |
| 140 | #[inline ] |
| 141 | pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> { |
| 142 | unsafe { |
| 143 | let ptr: *mut EVP_PKEY_CTX = cvt_p(ffi::EVP_PKEY_CTX_new(k:pkey.as_ptr(), e:ptr::null_mut()))?; |
| 144 | Ok(PkeyCtx::from_ptr(ptr)) |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | impl PkeyCtx<()> { |
| 150 | /// Creates a new pkey context for the specified algorithm ID. |
| 151 | #[corresponds (EVP_PKEY_CTX_new_id)] |
| 152 | #[inline ] |
| 153 | pub fn new_id(id: Id) -> Result<Self, ErrorStack> { |
| 154 | unsafe { |
| 155 | let ptr: *mut EVP_PKEY_CTX = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), e:ptr::null_mut()))?; |
| 156 | Ok(PkeyCtx::from_ptr(ptr)) |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | impl<T> PkeyCtxRef<T> |
| 162 | where |
| 163 | T: HasPublic, |
| 164 | { |
| 165 | /// Prepares the context for encryption using the public key. |
| 166 | #[corresponds (EVP_PKEY_encrypt_init)] |
| 167 | #[inline ] |
| 168 | pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> { |
| 169 | unsafe { |
| 170 | cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?; |
| 171 | } |
| 172 | |
| 173 | Ok(()) |
| 174 | } |
| 175 | |
| 176 | /// Prepares the context for signature verification using the public key. |
| 177 | #[corresponds (EVP_PKEY_verify_init)] |
| 178 | #[inline ] |
| 179 | pub fn verify_init(&mut self) -> Result<(), ErrorStack> { |
| 180 | unsafe { |
| 181 | cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?; |
| 182 | } |
| 183 | |
| 184 | Ok(()) |
| 185 | } |
| 186 | |
| 187 | /// Prepares the context for signature recovery using the public key. |
| 188 | #[corresponds (EVP_PKEY_verify_recover_init)] |
| 189 | #[inline ] |
| 190 | pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> { |
| 191 | unsafe { |
| 192 | cvt(ffi::EVP_PKEY_verify_recover_init(self.as_ptr()))?; |
| 193 | } |
| 194 | |
| 195 | Ok(()) |
| 196 | } |
| 197 | |
| 198 | /// Encrypts data using the public key. |
| 199 | /// |
| 200 | /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
| 201 | /// returned. |
| 202 | #[corresponds (EVP_PKEY_encrypt)] |
| 203 | #[inline ] |
| 204 | pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
| 205 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
| 206 | unsafe { |
| 207 | cvt(ffi::EVP_PKEY_encrypt( |
| 208 | self.as_ptr(), |
| 209 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 210 | &mut written, |
| 211 | from.as_ptr(), |
| 212 | from.len(), |
| 213 | ))?; |
| 214 | } |
| 215 | |
| 216 | Ok(written) |
| 217 | } |
| 218 | |
| 219 | /// Like [`Self::encrypt`] but appends ciphertext to a [`Vec`]. |
| 220 | pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
| 221 | let base = out.len(); |
| 222 | let len = self.encrypt(from, None)?; |
| 223 | out.resize(base + len, 0); |
| 224 | let len = self.encrypt(from, Some(&mut out[base..]))?; |
| 225 | out.truncate(base + len); |
| 226 | Ok(len) |
| 227 | } |
| 228 | |
| 229 | /// Verifies the signature of data using the public key. |
| 230 | /// |
| 231 | /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error |
| 232 | /// occurred. |
| 233 | /// |
| 234 | /// # Note |
| 235 | /// |
| 236 | /// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the |
| 237 | /// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do |
| 238 | /// that. |
| 239 | #[corresponds (EVP_PKEY_verify)] |
| 240 | #[inline ] |
| 241 | pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> { |
| 242 | unsafe { |
| 243 | let r = ffi::EVP_PKEY_verify( |
| 244 | self.as_ptr(), |
| 245 | sig.as_ptr(), |
| 246 | sig.len(), |
| 247 | data.as_ptr(), |
| 248 | data.len(), |
| 249 | ); |
| 250 | // `EVP_PKEY_verify` is not terribly consistent about how it, |
| 251 | // reports errors. It does not clearly distinguish between 0 and |
| 252 | // -1, and may put errors on the stack in both cases. If there's |
| 253 | // errors on the stack, we return `Err()`, else we return |
| 254 | // `Ok(false)`. |
| 255 | if r <= 0 { |
| 256 | let errors = ErrorStack::get(); |
| 257 | if !errors.errors().is_empty() { |
| 258 | return Err(errors); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | Ok(r == 1) |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /// Recovers the original data signed by the private key. You almost |
| 267 | /// always want `verify` instead. |
| 268 | /// |
| 269 | /// Returns the number of bytes written to `to`, or the number of bytes |
| 270 | /// that would be written, if `to` is `None. |
| 271 | #[corresponds (EVP_PKEY_verify_recover)] |
| 272 | #[inline ] |
| 273 | pub fn verify_recover( |
| 274 | &mut self, |
| 275 | sig: &[u8], |
| 276 | to: Option<&mut [u8]>, |
| 277 | ) -> Result<usize, ErrorStack> { |
| 278 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
| 279 | unsafe { |
| 280 | cvt(ffi::EVP_PKEY_verify_recover( |
| 281 | self.as_ptr(), |
| 282 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 283 | &mut written, |
| 284 | sig.as_ptr(), |
| 285 | sig.len(), |
| 286 | ))?; |
| 287 | } |
| 288 | |
| 289 | Ok(written) |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | impl<T> PkeyCtxRef<T> |
| 294 | where |
| 295 | T: HasPrivate, |
| 296 | { |
| 297 | /// Prepares the context for decryption using the private key. |
| 298 | #[corresponds (EVP_PKEY_decrypt_init)] |
| 299 | #[inline ] |
| 300 | pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> { |
| 301 | unsafe { |
| 302 | cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?; |
| 303 | } |
| 304 | |
| 305 | Ok(()) |
| 306 | } |
| 307 | |
| 308 | /// Prepares the context for signing using the private key. |
| 309 | #[corresponds (EVP_PKEY_sign_init)] |
| 310 | #[inline ] |
| 311 | pub fn sign_init(&mut self) -> Result<(), ErrorStack> { |
| 312 | unsafe { |
| 313 | cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?; |
| 314 | } |
| 315 | |
| 316 | Ok(()) |
| 317 | } |
| 318 | |
| 319 | /// Sets the peer key used for secret derivation. |
| 320 | #[corresponds (EVP_PKEY_derive_set_peer)] |
| 321 | pub fn derive_set_peer<U>(&mut self, key: &PKeyRef<U>) -> Result<(), ErrorStack> |
| 322 | where |
| 323 | U: HasPublic, |
| 324 | { |
| 325 | unsafe { |
| 326 | cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?; |
| 327 | } |
| 328 | |
| 329 | Ok(()) |
| 330 | } |
| 331 | |
| 332 | /// Decrypts data using the private key. |
| 333 | /// |
| 334 | /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
| 335 | /// returned. |
| 336 | #[corresponds (EVP_PKEY_decrypt)] |
| 337 | #[inline ] |
| 338 | pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
| 339 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
| 340 | unsafe { |
| 341 | cvt(ffi::EVP_PKEY_decrypt( |
| 342 | self.as_ptr(), |
| 343 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 344 | &mut written, |
| 345 | from.as_ptr(), |
| 346 | from.len(), |
| 347 | ))?; |
| 348 | } |
| 349 | |
| 350 | Ok(written) |
| 351 | } |
| 352 | |
| 353 | /// Like [`Self::decrypt`] but appends plaintext to a [`Vec`]. |
| 354 | pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
| 355 | let base = out.len(); |
| 356 | let len = self.decrypt(from, None)?; |
| 357 | out.resize(base + len, 0); |
| 358 | let len = self.decrypt(from, Some(&mut out[base..]))?; |
| 359 | out.truncate(base + len); |
| 360 | Ok(len) |
| 361 | } |
| 362 | |
| 363 | /// Signs the contents of `data`. |
| 364 | /// |
| 365 | /// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
| 366 | /// returned. |
| 367 | /// |
| 368 | /// # Note |
| 369 | /// |
| 370 | /// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of |
| 371 | /// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that. |
| 372 | #[corresponds (EVP_PKEY_sign)] |
| 373 | #[inline ] |
| 374 | pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
| 375 | let mut written = sig.as_ref().map_or(0, |b| b.len()); |
| 376 | unsafe { |
| 377 | cvt(ffi::EVP_PKEY_sign( |
| 378 | self.as_ptr(), |
| 379 | sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 380 | &mut written, |
| 381 | data.as_ptr(), |
| 382 | data.len(), |
| 383 | ))?; |
| 384 | } |
| 385 | |
| 386 | Ok(written) |
| 387 | } |
| 388 | |
| 389 | /// Like [`Self::sign`] but appends the signature to a [`Vec`]. |
| 390 | pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
| 391 | let base = sig.len(); |
| 392 | let len = self.sign(data, None)?; |
| 393 | sig.resize(base + len, 0); |
| 394 | let len = self.sign(data, Some(&mut sig[base..]))?; |
| 395 | sig.truncate(base + len); |
| 396 | Ok(len) |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | impl<T> PkeyCtxRef<T> { |
| 401 | /// Prepares the context for shared secret derivation. |
| 402 | #[corresponds (EVP_PKEY_derive_init)] |
| 403 | #[inline ] |
| 404 | pub fn derive_init(&mut self) -> Result<(), ErrorStack> { |
| 405 | unsafe { |
| 406 | cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; |
| 407 | } |
| 408 | |
| 409 | Ok(()) |
| 410 | } |
| 411 | |
| 412 | /// Prepares the context for key generation. |
| 413 | #[corresponds (EVP_PKEY_keygen_init)] |
| 414 | #[inline ] |
| 415 | pub fn keygen_init(&mut self) -> Result<(), ErrorStack> { |
| 416 | unsafe { |
| 417 | cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?; |
| 418 | } |
| 419 | |
| 420 | Ok(()) |
| 421 | } |
| 422 | |
| 423 | /// Sets which algorithm was used to compute the digest used in a |
| 424 | /// signature. With RSA signatures this causes the signature to be wrapped |
| 425 | /// in a `DigestInfo` structure. This is almost always what you want with |
| 426 | /// RSA signatures. |
| 427 | #[corresponds (EVP_PKEY_CTX_set_signature_md)] |
| 428 | #[inline ] |
| 429 | pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> { |
| 430 | unsafe { |
| 431 | cvt(ffi::EVP_PKEY_CTX_set_signature_md( |
| 432 | self.as_ptr(), |
| 433 | md.as_ptr(), |
| 434 | ))?; |
| 435 | } |
| 436 | Ok(()) |
| 437 | } |
| 438 | |
| 439 | /// Returns the RSA padding mode in use. |
| 440 | /// |
| 441 | /// This is only useful for RSA keys. |
| 442 | #[corresponds (EVP_PKEY_CTX_get_rsa_padding)] |
| 443 | #[inline ] |
| 444 | pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> { |
| 445 | let mut pad = 0; |
| 446 | unsafe { |
| 447 | cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?; |
| 448 | } |
| 449 | |
| 450 | Ok(Padding::from_raw(pad)) |
| 451 | } |
| 452 | |
| 453 | /// Sets the RSA padding mode. |
| 454 | /// |
| 455 | /// This is only useful for RSA keys. |
| 456 | #[corresponds (EVP_PKEY_CTX_set_rsa_padding)] |
| 457 | #[inline ] |
| 458 | pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { |
| 459 | unsafe { |
| 460 | cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( |
| 461 | self.as_ptr(), |
| 462 | padding.as_raw(), |
| 463 | ))?; |
| 464 | } |
| 465 | |
| 466 | Ok(()) |
| 467 | } |
| 468 | |
| 469 | /// Sets the RSA PSS salt length. |
| 470 | /// |
| 471 | /// This is only useful for RSA keys. |
| 472 | #[corresponds (EVP_PKEY_CTX_set_rsa_pss_saltlen)] |
| 473 | #[inline ] |
| 474 | pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { |
| 475 | unsafe { |
| 476 | cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( |
| 477 | self.as_ptr(), |
| 478 | len.as_raw(), |
| 479 | )) |
| 480 | .map(|_| ()) |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | /// Sets the RSA MGF1 algorithm. |
| 485 | /// |
| 486 | /// This is only useful for RSA keys. |
| 487 | #[corresponds (EVP_PKEY_CTX_set_rsa_mgf1_md)] |
| 488 | #[inline ] |
| 489 | pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { |
| 490 | unsafe { |
| 491 | cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( |
| 492 | self.as_ptr(), |
| 493 | md.as_ptr(), |
| 494 | ))?; |
| 495 | } |
| 496 | |
| 497 | Ok(()) |
| 498 | } |
| 499 | |
| 500 | /// Sets the RSA OAEP algorithm. |
| 501 | /// |
| 502 | /// This is only useful for RSA keys. |
| 503 | #[corresponds (EVP_PKEY_CTX_set_rsa_oaep_md)] |
| 504 | #[cfg (any(ossl102, libressl310, boringssl, awslc))] |
| 505 | #[inline ] |
| 506 | pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { |
| 507 | unsafe { |
| 508 | cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( |
| 509 | self.as_ptr(), |
| 510 | md.as_ptr() as *mut _, |
| 511 | ))?; |
| 512 | } |
| 513 | |
| 514 | Ok(()) |
| 515 | } |
| 516 | |
| 517 | /// Sets the RSA OAEP label. |
| 518 | /// |
| 519 | /// This is only useful for RSA keys. |
| 520 | #[corresponds (EVP_PKEY_CTX_set0_rsa_oaep_label)] |
| 521 | #[cfg (any(ossl102, libressl310, boringssl, awslc))] |
| 522 | pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { |
| 523 | use crate::LenType; |
| 524 | let len = LenType::try_from(label.len()).unwrap(); |
| 525 | |
| 526 | unsafe { |
| 527 | let p = ffi::OPENSSL_malloc(label.len() as _); |
| 528 | ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len()); |
| 529 | |
| 530 | let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( |
| 531 | self.as_ptr(), |
| 532 | p as *mut _, |
| 533 | len, |
| 534 | )); |
| 535 | if r.is_err() { |
| 536 | ffi::OPENSSL_free(p); |
| 537 | } |
| 538 | r?; |
| 539 | } |
| 540 | |
| 541 | Ok(()) |
| 542 | } |
| 543 | |
| 544 | /// Sets the cipher used during key generation. |
| 545 | #[cfg (not(any(boringssl, awslc)))] |
| 546 | #[corresponds (EVP_PKEY_CTX_ctrl)] |
| 547 | #[inline ] |
| 548 | pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> { |
| 549 | unsafe { |
| 550 | cvt(ffi::EVP_PKEY_CTX_ctrl( |
| 551 | self.as_ptr(), |
| 552 | -1, |
| 553 | ffi::EVP_PKEY_OP_KEYGEN, |
| 554 | ffi::EVP_PKEY_CTRL_CIPHER, |
| 555 | 0, |
| 556 | cipher.as_ptr() as *mut _, |
| 557 | ))?; |
| 558 | } |
| 559 | |
| 560 | Ok(()) |
| 561 | } |
| 562 | |
| 563 | /// Sets the key MAC key used during key generation. |
| 564 | #[cfg (not(any(boringssl, awslc)))] |
| 565 | #[corresponds (EVP_PKEY_CTX_ctrl)] |
| 566 | #[inline ] |
| 567 | pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { |
| 568 | let len = c_int::try_from(key.len()).unwrap(); |
| 569 | |
| 570 | unsafe { |
| 571 | cvt(ffi::EVP_PKEY_CTX_ctrl( |
| 572 | self.as_ptr(), |
| 573 | -1, |
| 574 | ffi::EVP_PKEY_OP_KEYGEN, |
| 575 | ffi::EVP_PKEY_CTRL_SET_MAC_KEY, |
| 576 | len, |
| 577 | key.as_ptr() as *mut _, |
| 578 | ))?; |
| 579 | } |
| 580 | |
| 581 | Ok(()) |
| 582 | } |
| 583 | |
| 584 | /// Sets the digest used for HKDF derivation. |
| 585 | /// |
| 586 | /// Requires OpenSSL 1.1.0 or newer. |
| 587 | #[corresponds (EVP_PKEY_CTX_set_hkdf_md)] |
| 588 | #[cfg (any(ossl110, boringssl, libressl360, awslc))] |
| 589 | #[inline ] |
| 590 | pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { |
| 591 | unsafe { |
| 592 | cvt(ffi::EVP_PKEY_CTX_set_hkdf_md( |
| 593 | self.as_ptr(), |
| 594 | digest.as_ptr(), |
| 595 | ))?; |
| 596 | } |
| 597 | |
| 598 | Ok(()) |
| 599 | } |
| 600 | |
| 601 | /// Sets the HKDF mode of operation. |
| 602 | /// |
| 603 | /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`]. |
| 604 | /// |
| 605 | /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct |
| 606 | /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input |
| 607 | /// secrets for one operation into the other. |
| 608 | /// |
| 609 | /// Requires OpenSSL 1.1.1 or newer. |
| 610 | #[corresponds (EVP_PKEY_CTX_set_hkdf_mode)] |
| 611 | #[cfg (any(ossl111, libressl360))] |
| 612 | #[inline ] |
| 613 | pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> { |
| 614 | unsafe { |
| 615 | cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?; |
| 616 | } |
| 617 | |
| 618 | Ok(()) |
| 619 | } |
| 620 | |
| 621 | /// Sets the input material for HKDF generation as the "key". |
| 622 | /// |
| 623 | /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]). |
| 624 | /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies |
| 625 | /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead |
| 626 | /// specifies the pseudorandom key (PRK) for HKDF-Expand. |
| 627 | /// |
| 628 | /// Requires OpenSSL 1.1.0 or newer. |
| 629 | #[corresponds (EVP_PKEY_CTX_set1_hkdf_key)] |
| 630 | #[cfg (any(ossl110, boringssl, libressl360, awslc))] |
| 631 | #[inline ] |
| 632 | pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { |
| 633 | #[cfg (not(any(boringssl, awslc)))] |
| 634 | let len = c_int::try_from(key.len()).unwrap(); |
| 635 | #[cfg (any(boringssl, awslc))] |
| 636 | let len = key.len(); |
| 637 | |
| 638 | unsafe { |
| 639 | cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( |
| 640 | self.as_ptr(), |
| 641 | key.as_ptr(), |
| 642 | len, |
| 643 | ))?; |
| 644 | } |
| 645 | |
| 646 | Ok(()) |
| 647 | } |
| 648 | |
| 649 | /// Sets the salt value for HKDF generation. |
| 650 | /// |
| 651 | /// If performing HKDF-Expand only, this parameter is ignored. |
| 652 | /// |
| 653 | /// Requires OpenSSL 1.1.0 or newer. |
| 654 | #[corresponds (EVP_PKEY_CTX_set1_hkdf_salt)] |
| 655 | #[cfg (any(ossl110, boringssl, libressl360, awslc))] |
| 656 | #[inline ] |
| 657 | pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { |
| 658 | #[cfg (not(any(boringssl, awslc)))] |
| 659 | let len = c_int::try_from(salt.len()).unwrap(); |
| 660 | #[cfg (any(boringssl, awslc))] |
| 661 | let len = salt.len(); |
| 662 | |
| 663 | unsafe { |
| 664 | cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( |
| 665 | self.as_ptr(), |
| 666 | salt.as_ptr(), |
| 667 | len, |
| 668 | ))?; |
| 669 | } |
| 670 | |
| 671 | Ok(()) |
| 672 | } |
| 673 | |
| 674 | /// Appends info bytes for HKDF generation. |
| 675 | /// |
| 676 | /// If performing HKDF-Extract only, this parameter is ignored. |
| 677 | /// |
| 678 | /// Requires OpenSSL 1.1.0 or newer. |
| 679 | #[corresponds (EVP_PKEY_CTX_add1_hkdf_info)] |
| 680 | #[cfg (any(ossl110, boringssl, libressl360, awslc))] |
| 681 | #[inline ] |
| 682 | pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { |
| 683 | #[cfg (not(any(boringssl, awslc)))] |
| 684 | let len = c_int::try_from(info.len()).unwrap(); |
| 685 | #[cfg (any(boringssl, awslc))] |
| 686 | let len = info.len(); |
| 687 | |
| 688 | unsafe { |
| 689 | cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( |
| 690 | self.as_ptr(), |
| 691 | info.as_ptr(), |
| 692 | len, |
| 693 | ))?; |
| 694 | } |
| 695 | |
| 696 | Ok(()) |
| 697 | } |
| 698 | |
| 699 | /// Derives a shared secret between two keys. |
| 700 | /// |
| 701 | /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned. |
| 702 | #[corresponds (EVP_PKEY_derive)] |
| 703 | pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
| 704 | let mut len = buf.as_ref().map_or(0, |b| b.len()); |
| 705 | unsafe { |
| 706 | cvt(ffi::EVP_PKEY_derive( |
| 707 | self.as_ptr(), |
| 708 | buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
| 709 | &mut len, |
| 710 | ))?; |
| 711 | } |
| 712 | |
| 713 | Ok(len) |
| 714 | } |
| 715 | |
| 716 | /// Like [`Self::derive`] but appends the secret to a [`Vec`]. |
| 717 | pub fn derive_to_vec(&mut self, buf: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
| 718 | let base = buf.len(); |
| 719 | let len = self.derive(None)?; |
| 720 | buf.resize(base + len, 0); |
| 721 | let len = self.derive(Some(&mut buf[base..]))?; |
| 722 | buf.truncate(base + len); |
| 723 | Ok(len) |
| 724 | } |
| 725 | |
| 726 | /// Generates a new public/private keypair. |
| 727 | #[corresponds (EVP_PKEY_keygen)] |
| 728 | #[inline ] |
| 729 | pub fn keygen(&mut self) -> Result<PKey<Private>, ErrorStack> { |
| 730 | unsafe { |
| 731 | let mut key = ptr::null_mut(); |
| 732 | cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?; |
| 733 | Ok(PKey::from_ptr(key)) |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | /// Sets the nonce type for a private key context. |
| 738 | /// |
| 739 | /// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979). |
| 740 | /// |
| 741 | /// This is only useful for DSA and ECDSA. |
| 742 | /// Requires OpenSSL 3.2.0 or newer. |
| 743 | #[cfg (ossl320)] |
| 744 | #[corresponds (EVP_PKEY_CTX_set_params)] |
| 745 | pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> { |
| 746 | let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type \0" ).unwrap(); |
| 747 | let mut nonce_type = nonce_type.0; |
| 748 | unsafe { |
| 749 | let param_nonce = |
| 750 | ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type); |
| 751 | let param_end = ffi::OSSL_PARAM_construct_end(); |
| 752 | |
| 753 | let params = [param_nonce, param_end]; |
| 754 | cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?; |
| 755 | } |
| 756 | Ok(()) |
| 757 | } |
| 758 | |
| 759 | /// Gets the nonce type for a private key context. |
| 760 | /// |
| 761 | /// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979). |
| 762 | /// |
| 763 | /// This is only useful for DSA and ECDSA. |
| 764 | /// Requires OpenSSL 3.2.0 or newer. |
| 765 | #[cfg (ossl320)] |
| 766 | #[corresponds (EVP_PKEY_CTX_get_params)] |
| 767 | pub fn nonce_type(&mut self) -> Result<NonceType, ErrorStack> { |
| 768 | let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type \0" ).unwrap(); |
| 769 | let mut nonce_type: c_uint = 0; |
| 770 | unsafe { |
| 771 | let param_nonce = |
| 772 | ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type); |
| 773 | let param_end = ffi::OSSL_PARAM_construct_end(); |
| 774 | |
| 775 | let mut params = [param_nonce, param_end]; |
| 776 | cvt(ffi::EVP_PKEY_CTX_get_params( |
| 777 | self.as_ptr(), |
| 778 | params.as_mut_ptr(), |
| 779 | ))?; |
| 780 | } |
| 781 | Ok(NonceType(nonce_type)) |
| 782 | } |
| 783 | } |
| 784 | |
| 785 | #[cfg (test)] |
| 786 | mod test { |
| 787 | use super::*; |
| 788 | #[cfg (not(any(boringssl, awslc)))] |
| 789 | use crate::cipher::Cipher; |
| 790 | use crate::ec::{EcGroup, EcKey}; |
| 791 | use crate::hash::{hash, MessageDigest}; |
| 792 | use crate::md::Md; |
| 793 | use crate::nid::Nid; |
| 794 | use crate::pkey::PKey; |
| 795 | use crate::rsa::Rsa; |
| 796 | use crate::sign::Verifier; |
| 797 | |
| 798 | #[test ] |
| 799 | fn rsa() { |
| 800 | let key = include_bytes!("../test/rsa.pem" ); |
| 801 | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
| 802 | let pkey = PKey::from_rsa(rsa).unwrap(); |
| 803 | |
| 804 | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
| 805 | ctx.encrypt_init().unwrap(); |
| 806 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 807 | |
| 808 | let pt = "hello world" .as_bytes(); |
| 809 | let mut ct = vec![]; |
| 810 | ctx.encrypt_to_vec(pt, &mut ct).unwrap(); |
| 811 | |
| 812 | ctx.decrypt_init().unwrap(); |
| 813 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 814 | |
| 815 | let mut out = vec![]; |
| 816 | ctx.decrypt_to_vec(&ct, &mut out).unwrap(); |
| 817 | |
| 818 | assert_eq!(pt, out); |
| 819 | } |
| 820 | |
| 821 | #[test ] |
| 822 | #[cfg (any(ossl102, libressl310, boringssl, awslc))] |
| 823 | fn rsa_oaep() { |
| 824 | let key = include_bytes!("../test/rsa.pem" ); |
| 825 | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
| 826 | let pkey = PKey::from_rsa(rsa).unwrap(); |
| 827 | |
| 828 | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
| 829 | ctx.encrypt_init().unwrap(); |
| 830 | ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); |
| 831 | ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); |
| 832 | ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); |
| 833 | |
| 834 | let pt = "hello world" .as_bytes(); |
| 835 | let mut ct = vec![]; |
| 836 | ctx.encrypt_to_vec(pt, &mut ct).unwrap(); |
| 837 | |
| 838 | ctx.decrypt_init().unwrap(); |
| 839 | ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); |
| 840 | ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); |
| 841 | ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); |
| 842 | |
| 843 | let mut out = vec![]; |
| 844 | ctx.decrypt_to_vec(&ct, &mut out).unwrap(); |
| 845 | |
| 846 | assert_eq!(pt, out); |
| 847 | } |
| 848 | |
| 849 | #[test ] |
| 850 | fn rsa_sign() { |
| 851 | let key = include_bytes!("../test/rsa.pem" ); |
| 852 | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
| 853 | let pkey = PKey::from_rsa(rsa).unwrap(); |
| 854 | |
| 855 | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
| 856 | ctx.sign_init().unwrap(); |
| 857 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 858 | ctx.set_signature_md(Md::sha384()).unwrap(); |
| 859 | |
| 860 | let msg = b"hello world" ; |
| 861 | let digest = hash(MessageDigest::sha384(), msg).unwrap(); |
| 862 | let mut signature = vec![]; |
| 863 | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
| 864 | |
| 865 | let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); |
| 866 | verifier.update(msg).unwrap(); |
| 867 | assert!(matches!(verifier.verify(&signature), Ok(true))); |
| 868 | } |
| 869 | |
| 870 | #[test ] |
| 871 | fn rsa_sign_pss() { |
| 872 | let key = include_bytes!("../test/rsa.pem" ); |
| 873 | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
| 874 | let pkey = PKey::from_rsa(rsa).unwrap(); |
| 875 | |
| 876 | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
| 877 | ctx.sign_init().unwrap(); |
| 878 | ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); |
| 879 | ctx.set_signature_md(Md::sha384()).unwrap(); |
| 880 | ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap(); |
| 881 | |
| 882 | let msg = b"hello world" ; |
| 883 | let digest = hash(MessageDigest::sha384(), msg).unwrap(); |
| 884 | let mut signature = vec![]; |
| 885 | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
| 886 | |
| 887 | let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); |
| 888 | verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); |
| 889 | verifier |
| 890 | .set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)) |
| 891 | .unwrap(); |
| 892 | verifier.update(msg).unwrap(); |
| 893 | assert!(matches!(verifier.verify(&signature), Ok(true))); |
| 894 | } |
| 895 | |
| 896 | #[test ] |
| 897 | fn derive() { |
| 898 | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
| 899 | let key1 = EcKey::generate(&group).unwrap(); |
| 900 | let key1 = PKey::from_ec_key(key1).unwrap(); |
| 901 | let key2 = EcKey::generate(&group).unwrap(); |
| 902 | let key2 = PKey::from_ec_key(key2).unwrap(); |
| 903 | |
| 904 | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
| 905 | ctx.derive_init().unwrap(); |
| 906 | ctx.derive_set_peer(&key2).unwrap(); |
| 907 | |
| 908 | let mut buf = vec![]; |
| 909 | ctx.derive_to_vec(&mut buf).unwrap(); |
| 910 | } |
| 911 | |
| 912 | #[test ] |
| 913 | #[cfg (not(any(boringssl, awslc)))] |
| 914 | fn cmac_keygen() { |
| 915 | let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); |
| 916 | ctx.keygen_init().unwrap(); |
| 917 | ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); |
| 918 | ctx.set_keygen_mac_key(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d" ).unwrap()) |
| 919 | .unwrap(); |
| 920 | ctx.keygen().unwrap(); |
| 921 | } |
| 922 | |
| 923 | #[test ] |
| 924 | #[cfg (any(ossl110, boringssl, libressl360, awslc))] |
| 925 | fn hkdf() { |
| 926 | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
| 927 | ctx.derive_init().unwrap(); |
| 928 | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
| 929 | ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" ).unwrap()) |
| 930 | .unwrap(); |
| 931 | ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c" ).unwrap()) |
| 932 | .unwrap(); |
| 933 | ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9" ).unwrap()) |
| 934 | .unwrap(); |
| 935 | let mut out = [0; 42]; |
| 936 | ctx.derive(Some(&mut out)).unwrap(); |
| 937 | |
| 938 | assert_eq!( |
| 939 | &out[..], |
| 940 | hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" ) |
| 941 | .unwrap() |
| 942 | ); |
| 943 | } |
| 944 | |
| 945 | #[test ] |
| 946 | #[cfg (any(ossl111, libressl360))] |
| 947 | fn hkdf_expand() { |
| 948 | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
| 949 | ctx.derive_init().unwrap(); |
| 950 | ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap(); |
| 951 | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
| 952 | ctx.set_hkdf_key( |
| 953 | &hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) |
| 954 | .unwrap(), |
| 955 | ) |
| 956 | .unwrap(); |
| 957 | ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9" ).unwrap()) |
| 958 | .unwrap(); |
| 959 | let mut out = [0; 42]; |
| 960 | ctx.derive(Some(&mut out)).unwrap(); |
| 961 | |
| 962 | assert_eq!( |
| 963 | &out[..], |
| 964 | hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865" ) |
| 965 | .unwrap() |
| 966 | ); |
| 967 | } |
| 968 | |
| 969 | #[test ] |
| 970 | #[cfg (any(ossl111, libressl360))] |
| 971 | fn hkdf_extract() { |
| 972 | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
| 973 | ctx.derive_init().unwrap(); |
| 974 | ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap(); |
| 975 | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
| 976 | ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" ).unwrap()) |
| 977 | .unwrap(); |
| 978 | ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c" ).unwrap()) |
| 979 | .unwrap(); |
| 980 | let mut out = vec![]; |
| 981 | ctx.derive_to_vec(&mut out).unwrap(); |
| 982 | |
| 983 | assert_eq!( |
| 984 | &out[..], |
| 985 | hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) |
| 986 | .unwrap() |
| 987 | ); |
| 988 | } |
| 989 | |
| 990 | #[test ] |
| 991 | fn verify_fail() { |
| 992 | let key1 = Rsa::generate(4096).unwrap(); |
| 993 | let key1 = PKey::from_rsa(key1).unwrap(); |
| 994 | |
| 995 | let data = b"Some Crypto Text" ; |
| 996 | |
| 997 | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
| 998 | ctx.sign_init().unwrap(); |
| 999 | let mut signature = vec![]; |
| 1000 | ctx.sign_to_vec(data, &mut signature).unwrap(); |
| 1001 | |
| 1002 | let bad_data = b"Some Crypto text" ; |
| 1003 | |
| 1004 | ctx.verify_init().unwrap(); |
| 1005 | let valid = ctx.verify(bad_data, &signature); |
| 1006 | assert!(matches!(valid, Ok(false) | Err(_))); |
| 1007 | assert!(ErrorStack::get().errors().is_empty()); |
| 1008 | } |
| 1009 | |
| 1010 | #[test ] |
| 1011 | fn verify_fail_ec() { |
| 1012 | let key1 = |
| 1013 | EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); |
| 1014 | let key1 = PKey::from_ec_key(key1).unwrap(); |
| 1015 | |
| 1016 | let data = b"Some Crypto Text" ; |
| 1017 | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
| 1018 | ctx.verify_init().unwrap(); |
| 1019 | assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_))); |
| 1020 | assert!(ErrorStack::get().errors().is_empty()); |
| 1021 | } |
| 1022 | |
| 1023 | #[test ] |
| 1024 | fn test_verify_recover() { |
| 1025 | let key = Rsa::generate(2048).unwrap(); |
| 1026 | let key = PKey::from_rsa(key).unwrap(); |
| 1027 | |
| 1028 | let digest = [ |
| 1029 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
| 1030 | 24, 25, 26, 27, 28, 29, 30, 31, |
| 1031 | ]; |
| 1032 | |
| 1033 | let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 1034 | ctx.sign_init().unwrap(); |
| 1035 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 1036 | ctx.set_signature_md(Md::sha256()).unwrap(); |
| 1037 | let mut signature = vec![]; |
| 1038 | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
| 1039 | |
| 1040 | // Attempt recovery of just the digest. |
| 1041 | let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 1042 | ctx.verify_recover_init().unwrap(); |
| 1043 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 1044 | ctx.set_signature_md(Md::sha256()).unwrap(); |
| 1045 | let length = ctx.verify_recover(&signature, None).unwrap(); |
| 1046 | let mut result_buf = vec![0; length]; |
| 1047 | let length = ctx |
| 1048 | .verify_recover(&signature, Some(&mut result_buf)) |
| 1049 | .unwrap(); |
| 1050 | assert_eq!(length, digest.len()); |
| 1051 | // result_buf contains the digest |
| 1052 | assert_eq!(result_buf[..length], digest); |
| 1053 | |
| 1054 | // Attempt recovery of teh entire DigestInfo |
| 1055 | let mut ctx = PkeyCtx::new(&key).unwrap(); |
| 1056 | ctx.verify_recover_init().unwrap(); |
| 1057 | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
| 1058 | let length = ctx.verify_recover(&signature, None).unwrap(); |
| 1059 | let mut result_buf = vec![0; length]; |
| 1060 | let length = ctx |
| 1061 | .verify_recover(&signature, Some(&mut result_buf)) |
| 1062 | .unwrap(); |
| 1063 | // 32-bytes of SHA256 digest + the ASN.1 DigestInfo structure == 51 bytes |
| 1064 | assert_eq!(length, 51); |
| 1065 | // The digest is the end of the DigestInfo structure. |
| 1066 | assert_eq!(result_buf[length - digest.len()..length], digest); |
| 1067 | } |
| 1068 | |
| 1069 | #[test ] |
| 1070 | #[cfg (ossl320)] |
| 1071 | fn set_nonce_type() { |
| 1072 | let key1 = |
| 1073 | EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); |
| 1074 | let key1 = PKey::from_ec_key(key1).unwrap(); |
| 1075 | |
| 1076 | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
| 1077 | ctx.sign_init().unwrap(); |
| 1078 | ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap(); |
| 1079 | let nonce_type = ctx.nonce_type().unwrap(); |
| 1080 | assert_eq!(nonce_type, NonceType::DETERMINISTIC_K); |
| 1081 | assert!(ErrorStack::get().errors().is_empty()); |
| 1082 | } |
| 1083 | |
| 1084 | // Test vector from |
| 1085 | // https://github.com/openssl/openssl/blob/openssl-3.2.0/test/recipes/30-test_evp_data/evppkey_ecdsa_rfc6979.txt |
| 1086 | #[test ] |
| 1087 | #[cfg (ossl320)] |
| 1088 | fn ecdsa_deterministic_signature() { |
| 1089 | let private_key_pem = "-----BEGIN PRIVATE KEY----- |
| 1090 | MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDJr6nYRbp1FmtcIVdnsdaTTlDD2zbo |
| 1091 | mxJ7imIrEg9nIQ== |
| 1092 | -----END PRIVATE KEY-----" ; |
| 1093 | |
| 1094 | let key1 = EcKey::private_key_from_pem(private_key_pem.as_bytes()).unwrap(); |
| 1095 | let key1 = PKey::from_ec_key(key1).unwrap(); |
| 1096 | let input = "sample" ; |
| 1097 | let expected_output = hex::decode("3044022061340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D3202206D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB" ).unwrap(); |
| 1098 | |
| 1099 | let hashed_input = hash(MessageDigest::sha1(), input.as_bytes()).unwrap(); |
| 1100 | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
| 1101 | ctx.sign_init().unwrap(); |
| 1102 | ctx.set_signature_md(Md::sha1()).unwrap(); |
| 1103 | ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap(); |
| 1104 | |
| 1105 | let mut output = vec![]; |
| 1106 | ctx.sign_to_vec(&hashed_input, &mut output).unwrap(); |
| 1107 | assert_eq!(output, expected_output); |
| 1108 | assert!(ErrorStack::get().errors().is_empty()); |
| 1109 | } |
| 1110 | } |
| 1111 | |