diff --git a/.typos.toml b/.typos.toml index 3323627e..607ec726 100644 --- a/.typos.toml +++ b/.typos.toml @@ -1,3 +1,6 @@ [default.extend-identifiers] # typ stands for type, but it's a reserved identifier typ = "typ" + +[files] +extend-exclude = ["tests/examples/pkcs1v15_ir/cases.json"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d091bdb..7744c999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- PKCS#1 v1.5 decryption now uses deterministic implicit rejection for + padding-invalid ciphertexts while preserving `Err` for publicly invalid + ciphertexts and non-padding failures. +- SHA-256 is now an unconditional internal dependency for PKCS#1 v1.5 implicit + rejection. The public `sha2` feature remains for compatibility and continues + to gate the SHA-2 reexport and PKCS#1 v1.5 signature OID impls. + ## 0.9.8 (2025-03-12) ### Added - Doc comments to specify the `rand` version ([#473]) diff --git a/Cargo.lock b/Cargo.lock index 281f57f3..4ad5d52f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -777,6 +777,7 @@ dependencies = [ "digest", "hex", "hex-literal", + "hmac", "pkcs1", "pkcs8", "proptest", diff --git a/Cargo.toml b/Cargo.toml index dbed5ef6..34cdf9d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,9 @@ const-oid = { version = "0.10", default-features = false } crypto-bigint = { version = "0.7", default-features = false, features = ["zeroize", "alloc"] } crypto-primes = { version = "0.7", default-features = false } digest = { version = "0.11", default-features = false, features = ["alloc", "oid"] } +hmac = { version = "0.13", default-features = false } rand_core = { version = "0.10", default-features = false } +sha2 = { version = "0.11", default-features = false, features = ["oid"] } signature = { version = "3.0.0-rc.10", default-features = false, features = ["alloc", "digest", "rand_core"] } zeroize = { version = "1.8", features = ["alloc"] } @@ -28,7 +30,6 @@ pkcs1 = { version = "0.8.0-rc.4", optional = true, default-features = false, fea pkcs8 = { version = "0.11.0-rc.10", optional = true, default-features = false, features = ["alloc", "pem"] } serdect = { version = "0.4", optional = true } sha1 = { version = "0.11", optional = true, default-features = false, features = ["oid"] } -sha2 = { version = "0.11", optional = true, default-features = false, features = ["oid"] } spki = { version = "0.8", optional = true, default-features = false, features = ["alloc"] } serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] } @@ -59,6 +60,7 @@ hazmat = [] getrandom = ["crypto-bigint/getrandom", "crypto-common"] serde = ["encoding", "dep:serde", "dep:serdect", "crypto-bigint/serde"] pkcs5 = ["pkcs8/encryption"] +sha2 = [] [package.metadata.docs.rs] features = ["std", "serde", "hazmat", "sha2"] diff --git a/src/algorithms/pad.rs b/src/algorithms/pad.rs index c84ab127..eabb2cd8 100644 --- a/src/algorithms/pad.rs +++ b/src/algorithms/pad.rs @@ -18,6 +18,24 @@ fn left_pad(input: &[u8], padded_len: usize) -> Result> { Ok(out) } +/// Converts input to an exact modulus-width big-endian encoding. +/// +/// This normalizes only by the public storage width of the integer: if the +/// backing representation is wider than `k`, only the public over-width prefix +/// is dropped. The returned buffer is always exactly `k` octets long. +#[inline] +pub(crate) fn i2osp_modulus_width(input: &BoxedUint, k: usize) -> Zeroizing> { + let bytes = Zeroizing::new(input.to_be_bytes()); + let copy_len = bytes.len().min(k); + let src_start = bytes.len().saturating_sub(k); + + debug_assert!(bytes[..src_start].iter().all(|&byte| byte == 0)); + + let mut out = Zeroizing::new(vec![0u8; k]); + out[k - copy_len..].copy_from_slice(&bytes[src_start..]); + out +} + /// Converts input to the new vector of the given length, using BE and with 0s left padded. /// In some cases BoxedUint might already have leading zeroes, this function removes them /// before padding again. @@ -60,4 +78,29 @@ mod tests { let padded = left_pad(&input, INPUT_LEN - 1); assert!(padded.is_err()); } + + #[test] + fn test_i2osp_modulus_width_exact_width() { + let input = BoxedUint::from_be_slice(&[0x12, 0x34], 128).unwrap(); + let padded = i2osp_modulus_width(&input, 2); + + assert_eq!(padded.as_slice(), &[0x12, 0x34]); + } + + #[test] + fn test_i2osp_modulus_width_left_pads_to_modulus_width() { + let input = BoxedUint::from_be_slice(&[0x12, 0x34], 128).unwrap(); + let padded = i2osp_modulus_width(&input, 4); + + assert_eq!(padded.as_slice(), &[0x00, 0x00, 0x12, 0x34]); + } + + #[test] + fn test_i2osp_modulus_width_odd_modulus_width() { + let input = BoxedUint::from_be_slice(&[0x01], 2049).unwrap(); + let padded = i2osp_modulus_width(&input, 257); + + assert_eq!(padded.len(), 257); + assert_eq!(padded[256], 0x01); + } } diff --git a/src/algorithms/pkcs1v15.rs b/src/algorithms/pkcs1v15.rs index 346d7947..28879231 100644 --- a/src/algorithms/pkcs1v15.rs +++ b/src/algorithms/pkcs1v15.rs @@ -6,15 +6,20 @@ //! //! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2 -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use const_oid::AssociatedOid; -use crypto_bigint::{Choice, CtAssign, CtEq, CtSelect}; -use digest::Digest; +use crypto_bigint::{BoxedUint, Choice, CtEq}; +use digest::{Digest, KeyInit}; +use hmac::{Hmac, Mac}; use rand_core::TryCryptoRng; +use sha2::Sha256; use zeroize::Zeroizing; +use crate::algorithms::pad::i2osp_modulus_width; use crate::errors::{Error, Result}; +type HmacSha256 = Hmac; + /// Fills the provided slice with random values, which are guaranteed /// to not be zero. #[inline] @@ -61,59 +66,181 @@ where /// Removes the encryption padding scheme from PKCS#1 v1.5. /// -/// Note that whether this function returns an error or not discloses secret -/// information. If an attacker can cause this function to run repeatedly and -/// learn whether each instance returned an error then they can decrypt and -/// forge signatures as if they had the private key. See -/// `decrypt_session_key` for a way of solving this problem. #[inline] -pub(crate) fn pkcs1v15_encrypt_unpad(em: Vec, k: usize) -> Result> { - let (valid, out, index) = decrypt_inner(em, k)?; - if valid == 0 { +pub(crate) fn pkcs1v15_encrypt_unpad( + em: &[u8], + d: &BoxedUint, + ciphertext: &[u8], +) -> Result> { + if em.len() < 11 { return Err(Error::Decryption); } - Ok(out[index as usize..].to_vec()) + let k = em.len(); + let kdk = derive_kdk(d, k, ciphertext)?; + let candidate_lengths = irprf_sha256_hmac_256(&kdk, b"length")?; + let alt_len = select_alt_len_ct(&candidate_lengths, (k - 11) as u32); + let alt_message = irprf_sha256_hmac(&kdk, b"message", k)?; + let scan = scan_pkcs1v15_encryption_block(em); + + Ok(select_message_ct( + em, + alt_message.as_ref(), + scan.real_len, + alt_len, + scan.valid, + )) } -/// Removes the PKCS1v15 padding It returns one or zero in valid that indicates whether the -/// plaintext was correctly structured. In either case, the plaintext is -/// returned in em so that it may be read independently of whether it was valid -/// in order to maintain constant memory access patterns. If the plaintext was -/// valid then index contains the index of the original message in em. #[inline] -fn decrypt_inner(em: Vec, k: usize) -> Result<(u8, Vec, u32)> { - if k < 11 { +fn derive_kdk(d: &BoxedUint, k: usize, ciphertext: &[u8]) -> Result> { + if ciphertext.len() > k { return Err(Error::Decryption); } - let first_byte_is_zero = em[0].ct_eq(&0u8); - let second_byte_is_two = em[1].ct_eq(&2u8); + let d_bytes = i2osp_modulus_width(d, k); + let dh = Sha256::digest(d_bytes.as_slice()); + let mut padded_ciphertext = Zeroizing::new(vec![0u8; k]); + padded_ciphertext[k - ciphertext.len()..].copy_from_slice(ciphertext); + + let mut mac = HmacSha256::new_from_slice(dh.as_ref()).map_err(|_| Error::Internal)?; + mac.update(padded_ciphertext.as_slice()); + + let mut kdk = Zeroizing::new([0u8; 32]); + kdk.copy_from_slice(&mac.finalize().into_bytes()); + Ok(kdk) +} + +#[inline] +fn irprf_sha256_hmac(kdk: &[u8; 32], label: &[u8], out_len: usize) -> Result>> { + if out_len >= 8192 { + return Err(Error::ModulusTooLarge); + } + + let bit_len = out_len.checked_mul(8).ok_or(Error::ModulusTooLarge)?; + let bit_len = u16::try_from(bit_len).map_err(|_| Error::ModulusTooLarge)?; + let mut out = Zeroizing::new(Vec::with_capacity(out_len + 32)); + let mut counter = 0u16; + + while out.len() < out_len { + let mut mac = HmacSha256::new_from_slice(kdk).map_err(|_| Error::Internal)?; + mac.update(&counter.to_be_bytes()); + mac.update(label); + mac.update(&bit_len.to_be_bytes()); + out.extend_from_slice(&mac.finalize().into_bytes()); + counter = counter.checked_add(1).ok_or(Error::Internal)?; + } + + out.truncate(out_len); + Ok(out) +} + +#[inline] +fn irprf_sha256_hmac_256(kdk: &[u8; 32], label: &[u8]) -> Result> { + let out = irprf_sha256_hmac(kdk, label, 256)?; + let mut fixed = Zeroizing::new([0u8; 256]); + fixed.copy_from_slice(out.as_ref()); + Ok(fixed) +} + +#[derive(Clone, Copy, Debug)] +struct ScanResult { + valid: Choice, + real_len: u32, +} + +#[inline] +fn select_alt_len_ct(cl: &[u8; 256], max_msg_len: u32) -> u32 { + let max_bits = u32::BITS - max_msg_len.leading_zeros(); + let mask = if max_bits == 0 { + 0 + } else if max_bits >= u32::BITS { + u32::MAX + } else { + (1u32 << max_bits) - 1 + }; - // The remainder of the plaintext must be a string of non-zero random - // octets, followed by a 0, followed by the message. - // looking_for_index: 1 iff we are still looking for the zero. - // index: the offset of the first zero byte. - let mut looking_for_index = Choice::TRUE; - let mut index = 0u32; + cl.chunks_exact(2).fold(0u32, |selected, candidate| { + let candidate = u16::from_be_bytes([candidate[0], candidate[1]]) as u32 & mask; + let within_range = Choice::from_u32_le(candidate, max_msg_len); + within_range.select_u32(selected, candidate) + }) +} - for (i, el) in em.iter().enumerate().skip(2) { - let equals0 = el.ct_eq(&0u8); - index.ct_assign(&(i as u32), looking_for_index & equals0); - looking_for_index &= !equals0; +#[inline] +fn scan_pkcs1v15_encryption_block(em: &[u8]) -> ScanResult { + if em.len() < 11 { + return ScanResult { + valid: Choice::FALSE, + real_len: 0, + }; } - // The PS padding must be at least 8 bytes long, and it starts two - // bytes into em. - // TODO: WARNING: THIS MUST BE CONSTANT TIME CHECK: - // Ref: https://github.com/dalek-cryptography/subtle/issues/20 - // This is currently copy & paste from the constant time impl in - // go, but very likely not sufficient. - let valid_ps = Choice::from_u8_lsb((((2i32 + 8i32 - index as i32 - 1i32) >> 31) & 1) as u8); - let valid = first_byte_is_zero & second_byte_is_two & !looking_for_index & valid_ps; - index = u32::ct_select(&0, &(index + 1), valid); + let prefix_ok = em[0].ct_eq(&0u8) & em[1].ct_eq(&2u8); + let mut searching = Choice::TRUE; + let mut found_sep = Choice::FALSE; + let mut sep_index = 0u32; + + for (i, byte) in em.iter().enumerate().skip(2) { + let is_zero = byte.ct_eq(&0u8); + let capture = searching & is_zero; + sep_index = capture.select_u32(sep_index, i as u32); + found_sep |= is_zero; + searching &= !is_zero; + } + + let real_len = found_sep.select_u32(0, em.len() as u32 - (sep_index + 1)); + let ps_len = found_sep.select_u32(0, sep_index.wrapping_sub(2)); + let valid = prefix_ok & found_sep & Choice::from_u32_le(8, ps_len); + + ScanResult { valid, real_len } +} + +#[inline] +fn clamp_len(len: u32, max_msg_len: u32) -> u32 { + Choice::from_u32_lt(max_msg_len, len).select_u32(len, max_msg_len) +} + +#[inline] +fn gather_message_byte_ct(tail: &[u8], start: u32, len: u32, index: u32) -> u8 { + let mut selected = 0u8; + let in_range = Choice::from_u32_lt(index, len); + let target = start.wrapping_add(index); - Ok((valid.to_u8(), em, index)) + for (source_index, &byte) in tail.iter().enumerate() { + let source_index = source_index as u32; + let take = in_range & source_index.ct_eq(&target); + selected = take.select_u8(selected, byte); + } + + selected +} + +#[inline] +fn select_message_ct(em: &[u8], am: &[u8], real_len: u32, alt_len: u32, valid: Choice) -> Vec { + debug_assert_eq!(em.len(), am.len()); + debug_assert!(em.len() >= 11); + + let max_msg_len = (em.len() - 11) as u32; + let real_len = clamp_len(real_len, max_msg_len); + let alt_len = clamp_len(alt_len, max_msg_len); + let selected_len = valid.select_u32(alt_len, real_len) as usize; + let tail = max_msg_len as usize; + let em_tail = &em[11..]; + let am_tail = &am[11..]; + let em_start = max_msg_len.wrapping_sub(real_len); + let am_start = max_msg_len.wrapping_sub(alt_len); + let mut out = vec![0u8; tail]; + + for (i, out_byte) in out.iter_mut().enumerate() { + let index = i as u32; + let em_byte = gather_message_byte_ct(em_tail, em_start, real_len, index); + let am_byte = gather_message_byte_ct(am_tail, am_start, alt_len, index); + *out_byte = valid.select_u8(am_byte, em_byte); + } + + out.truncate(selected_len); + out } #[inline] @@ -210,4 +337,73 @@ mod tests { let res = pkcs1v15_encrypt_pad(&mut rng, &message, k); assert_eq!(res, Err(Error::MessageTooLong)); } + + #[test] + fn test_select_alt_len_ct_uses_last_candidate_within_range() { + let mut cl = [0xffu8; 256]; + cl[0..2].copy_from_slice(&15u16.to_be_bytes()); + cl[2..4].copy_from_slice(&9u16.to_be_bytes()); + cl[4..6].copy_from_slice(&3u16.to_be_bytes()); + + assert_eq!(select_alt_len_ct(&cl, 10), 3); + } + + #[test] + fn test_select_alt_len_ct_handles_full_u32_mask() { + let cl = [0xffu8; 256]; + + assert_eq!(select_alt_len_ct(&cl, u32::MAX), 0xffff); + } + + #[test] + fn test_irprf_sha256_hmac_rejects_8192_octets() { + let kdk = [0u8; 32]; + + assert_eq!( + irprf_sha256_hmac(&kdk, b"message", 8192), + Err(Error::ModulusTooLarge) + ); + } + + #[test] + fn test_scan_pkcs1v15_encryption_block_valid() { + let em = [ + 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xaa, + ]; + let scan = scan_pkcs1v15_encryption_block(&em); + + assert!(bool::from(scan.valid)); + assert_eq!(scan.real_len, 1); + } + + #[test] + fn test_scan_pkcs1v15_encryption_block_missing_separator() { + let em = [ + 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + ]; + let scan = scan_pkcs1v15_encryption_block(&em); + + assert!(!bool::from(scan.valid)); + assert_eq!(scan.real_len, 0); + } + + #[test] + fn test_select_message_ct_returns_valid_message_bytes() { + let em = [0u8, 2, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0xaa, 0xbb]; + let am = [0u8, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0xcc, 0xdd]; + + let out = select_message_ct(&em, &am, 2, 2, Choice::TRUE); + + assert_eq!(out, vec![0xaa, 0xbb]); + } + + #[test] + fn test_select_message_ct_returns_rejection_symbol_bytes() { + let em = [0u8, 2, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0xaa, 0xbb]; + let am = [0u8, 2, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0xcc, 0xdd]; + + let out = select_message_ct(&em, &am, 2, 2, Choice::FALSE); + + assert_eq!(out, vec![0xcc, 0xdd]); + } } diff --git a/src/pkcs1v15.rs b/src/pkcs1v15.rs index 92ebee18..17b74163 100644 --- a/src/pkcs1v15.rs +++ b/src/pkcs1v15.rs @@ -6,11 +6,15 @@ //! PKCS#1 v1.5 padding has a longstanding history of issues generally classed as //! [Bleichenbacher Attacks] which were originally discovered in 1998 but keep reappearing in //! various forms again and again over the course of decades, including most recently in the 2023 -//! [Marvin Attack], which the `rsa` crate is [still vulnerable] to. +//! [Marvin Attack]. //! //! These attacks can result in complete plaintext recovery for encryption, or signature forgery, //! leading to a total failure of either confidentiality or integrity. //! +//! This crate's PKCS#1 v1.5 decrypt path uses deterministic implicit rejection for +//! padding-invalid but otherwise publicly valid ciphertexts so they no longer surface a distinct +//! padding error. Publicly invalid ciphertexts and non-padding failures still return `Err`. +//! //! Unless explicitly needed for compatibility reasons, we recommend against using PKCS#1 v1.5, //! and suggest using [PSS][`super::pss`] or [OAEP][`super::oaep`] instead (if there is a //! requirement to use RSA). @@ -18,7 +22,6 @@ //! //! [Bleichenbacher Attacks]: https://en.wikipedia.org/wiki/Adaptive_chosen-ciphertext_attack#Practical_attacks //! [Marvin Attack]: https://people.redhat.com/~hkario/marvin/ -//! [still vulnerable]: https://github.com/RustCrypto/RSA/issues/626 //! //! # Usage //! @@ -44,12 +47,12 @@ use crypto_bigint::BoxedUint; use digest::Digest; use rand_core::TryCryptoRng; -use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad}; +use crate::algorithms::pad::{i2osp_modulus_width, uint_to_be_pad, uint_to_zeroizing_be_pad}; use crate::algorithms::pkcs1v15::*; use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt}; use crate::errors::{Error, Result}; use crate::key::{self, RsaPrivateKey, RsaPublicKey}; -use crate::traits::{PaddingScheme, PublicKeyParts, SignatureScheme}; +use crate::traits::{PaddingScheme, PrivateKeyParts, PublicKeyParts, SignatureScheme}; /// Encryption using PKCS#1 v1.5 padding. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] @@ -163,11 +166,17 @@ fn encrypt( /// /// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks. /// -/// Note that whether this function returns an error or not discloses secret -/// information. If an attacker can cause this function to run repeatedly and -/// learn whether each instance returned an error then they can decrypt and -/// forge signatures as if they had the private key. See -/// `decrypt_session_key` for a way of solving this problem. +/// Invalid PKCS#1 v1.5 padding no longer returns a distinct padding error. +/// Instead, this function returns a deterministic pseudorandom rejection +/// symbol derived from the private exponent and the provided ciphertext. +/// +/// `Err` is still returned for publicly invalid ciphertexts, such as wrong +/// ciphertext length or ciphertext representatives outside the RSA modulus, +/// and for non-padding failures such as blinding RNG failure or CRT +/// verification failure. +/// +/// PKCS#1 v1.5 encryption remains a legacy compatibility mode. Prefer OAEP +/// for new designs. #[inline] fn decrypt( rng: Option<&mut R>, @@ -176,11 +185,17 @@ fn decrypt( ) -> Result> { key::check_public(priv_key)?; - let ciphertext = BoxedUint::from_be_slice(ciphertext, priv_key.n_bits_precision())?; - let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?; - let em = uint_to_zeroizing_be_pad(em, priv_key.size())?; + let k = priv_key.size(); + if k < 11 || ciphertext.len() != k { + return Err(Error::Decryption); + } + + let ciphertext_int = BoxedUint::from_be_slice(ciphertext, priv_key.n_bits_precision()) + .map_err(|_| Error::Decryption)?; + let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext_int)?; + let em = i2osp_modulus_width(&em, k); - pkcs1v15_encrypt_unpad(em, priv_key.size()) + pkcs1v15_encrypt_unpad(em.as_slice(), priv_key.d(), ciphertext) } /// Calculates the signature of hashed using diff --git a/src/pkcs1v15/decrypting_key.rs b/src/pkcs1v15/decrypting_key.rs index d3ae9ee3..45c01fac 100644 --- a/src/pkcs1v15/decrypting_key.rs +++ b/src/pkcs1v15/decrypting_key.rs @@ -12,6 +12,11 @@ use zeroize::ZeroizeOnDrop; /// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.2]. /// +/// Padding-invalid ciphertexts return the deterministic rejection symbol +/// produced by the shared PKCS#1 v1.5 decrypt path instead of a distinct +/// padding error. Publicly invalid ciphertexts and non-padding failures still +/// return `Err`. +/// /// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2 #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -20,7 +25,7 @@ pub struct DecryptingKey { } impl DecryptingKey { - /// Create a new verifying key from an RSA public key. + /// Create a new decrypting key from an RSA private key. pub fn new(key: RsaPrivateKey) -> Self { Self { inner: key } } diff --git a/tests/examples/pkcs1v15_ir/cases.json b/tests/examples/pkcs1v15_ir/cases.json new file mode 100644 index 00000000..d2b9179f --- /dev/null +++ b/tests/examples/pkcs1v15_ir/cases.json @@ -0,0 +1,272 @@ +{ + "families": [ + { + "id": "k2048", + "modulus_bits": 2048, + "section": "B.1. 2048-bit key", + "cases": [ + { + "title": "Valid", + "ciphertext_hex": "8bfe264e85d3bdeaa6b8851b8e3b956ee3d226fd3f69063a86880173a273d9f283b2eebdd1ed35f7e02d91c571981b6737d5320bd8396b0f3ad5b019daec1b0aab3cbbc026395f4fd14f13673f2dfc81f9b660ec26ac381e6db3299b4e460b43fab9955df2b3cfaa20e900e19c856238fd371899c2bf2ce8c868b76754e5db3b036533fd603746be13c10d4e3e6022ebc905d20c2a7f32b215a4cd53b3f44ca1c327d2c2b651145821c08396c89071f665349c25e44d2733cd9305985ceef6430c3cf57af5fa224089221218fa34737c79c446d28a94c41c96e4e92ac53fbcf384dea8419ea089f8784445a492c812eb0d409467f75afd7d4d1078886205a066", + "expected_hex": "6c6f72656d20697073756d20646f6c6f722073697420616d6574" + }, + { + "title": "Valid empty", + "ciphertext_hex": "443ad9c5f00a1f4e9601717d274aacc93a824cb4d99b3c6a42e2b017e52e018443bd77d34a80703cd9b6acf523cd3b2cd1fea31940a68fba828836f1c3ed2fef071e95e0922ff0f47d0e81dacc13ecdeda3db6476f41e5b3f9ccfcfdf91558007b68ffbbe5e93bb088f1e4f0bb39bc7d8600b38930ecd00a341d8cc76955837efff0f0797c4b46fb1b375bba49bcdc877f39aaadb045c56b836072383eec6627ae280ad4f9a45d6e5b4cc7cf61d42b194ff0b9c9167c621e5380d8333e3b7f20c8d564c9ec6c2805f77c0146adea2f688a943b67ce8889f4a6353e6396d551c36a6dbf19359a825d14b69ccc4fd747cf14a1ca8578d7f0a67dc14b37f5e17ca3", + "expected_hex": "" + }, + { + "title": "Valid with ciphertext starting with a zero byte", + "ciphertext_hex": "00a2e8f114ea8d05d12dc843e3cc3b2edc8229ff2a028bda29ba9d55e3cd02911902fef1f42a075bf05e8016e8567213d6f260fa49e360779dd81aeea3e04c2cb567e0d72b98bf754014561b7511e083d20e0bfb9cd23f8a0d3c88900c49d2fcd5843ff0765607b2026f28202a87aa94678aed22a0c20724541394cd8f44e373eba1d2bae98f516c1e2ba3d86852d064f856b1daf24795e767a2b90396e50743e3150664afab131fe40ea405dcf572dd1079af1d3f0392ccadcca0a12740dbb213b925ca2a06b1bc1383e83a658c82ba2e7427342379084d5f66b544579f07664cb26edd4f10fd913fdbc0de05ef887d4d1ec1ac95652397ea7fd4e4759fda8b", + "expected_hex": "6c6f72656d20697073756d" + }, + { + "title": "Invalid decrypting to empty", + "ciphertext_hex": "20aaa8adbbc593a924ba1c5c7990b5c2242ae4b99d0fe636a19a4cf754edbcee774e472fe028160ed42634f8864900cb514006da642cae6ae8c7d087caebcfa6dad1551301e130344989a1d462d4164505f6393933450c67bc6d39d8f5160907cabc251b737925a1cf21e5c6aa5781b7769f6a2a583d97cce008c0f8b6add5f0b2bd80bee60237aa39bb20719fe75749f4bc4e42466ef5a861ae3a92395c7d858d430bfe38040f445ea93fa2958b503539800ffa5ce5f8cf51fa8171a91f36cb4f4575e8de6b4d3f096ee140b938fd2f50ee13f0d050222e2a72b0a3069ff3a6738e82c87090caa5aed4fcbe882c49646aa250b98f12f83c8d528113614a29e7", + "expected_hex": "" + }, + { + "title": "Invalid decrypting to max size", + "ciphertext_hex": "48cceab10f39a4db32f60074feea473cbcdb7accf92e150417f76b44756b190e843e79ec12aa85083a21f5437e7bad0a60482e601198f9d86923239c8786ee728285afd0937f7dde12717f28389843d7375912b07b991f4fdb0190fced8ba665314367e8c5f9d2981d0f5128feeb46cb50fc237e64438a86df198dd0209364ae3a842d77532b66b7ef263b83b1541ed671b120dfd660462e2107a4ee7b964e734a7bd68d90dda61770658a3c242948532da32648687e0318286473f675b412d6468f013f14d760a358dfcad3cda2afeec5e268a37d250c37f722f468a70dfd92d7294c3c1ee1e7f8843b7d16f9f37ef35748c3ae93aa155cdcdfeb4e78567303", + "expected_hex": "22d850137b9eebe092b24f602dc5bb7918c16bd89ddbf20467b119d205f9c2e4bd7d2592cf1e532106e0f33557565923c73a02d4f09c0c22bea89148183e60317f7028b3aa1f261f91c979393101d7e15f4067e63979b32751658ef769610fe97cf9cef3278b3117d384051c3b1d82c251c2305418c8f6840530e631aad63e70e20e025bcd8efb54c92ec6d3b106a2f8e64eeff7d38495b0fc50c97138af4b1c0a67a1c4e27b077b8439332edfa8608dfeae653cd6a628ac550395f7e74390e42c11682234870925eeaa1fa71b76cf1f2ee3bda69f6717033ff8b7c95c9799e7a3bea5e7e4a1c359772fb6b1c6e6c516661dfe30c3" + }, + { + "title": "Invalid with null padded ciphertext", + "ciphertext_hex": "006f89db685c0a132700c6a17f88a37a6635d0ab89de4c45dc09736c891ca5bf3401ce34c6e5d51e94ed2f518857ddc12d9f9f9e68e01cdc30d86ae5dd83988c0c46a8e39daa1b328a23def551d67fa1964fb15242c83ddd7dd5b1aec720a391d0b86cb16cf4d3c466850c3df88a3ed85993900d1287a0c90c4b04d34ba29e59967661f3f10e0c998f64e14e777e8e81371eca5318b4e0b53414292130c821477c51e2bff844836ab10dff293d82e4f40d345968ef268c92ed0bc238f31d50f4d3f759c23964923e135d15527556410fbd2c451d6a2aa852dc88b01139c6fdd826736d8cd3780601b2977b09c080bd8c0fa471606ad59f053ad33d9eeb905f20", + "expected_hex": "2b5dd72df3cae37f1aef" + }, + { + "title": "Invalid with second to last length", + "ciphertext_hex": "1439e08c3f84c1a7fec74ce07614b20e01f6fa4e8c2a6cffdc3520d8889e5d9a950c6425798f85d4be38d300ea5695f13ecd4cb389d1ff5b82484b494d6280ab7fa78e645933981cb934cce8bfcd114cc0e6811eefa47aae20af638a1cd163d2d3366186d0a07df0c81f6c9f3171cf3561472e98a6006bf75ddb457bed036dcce199369de7d94ef2c68e8467ee0604eea2b3009479162a7891ba5c40cab17f49e1c438cb6eaea4f76ce23cce0e483ff0e96fa790ea15be67671814342d0a23f4a20262b6182e72f3a67cd289711503c85516a9ed225422f98b116f1ab080a80abd6f0216df88d8cfd67c139243be8dd78502a7aaf6bc99d7da71bcdf627e7354", + "expected_hex": "0f9b" + }, + { + "title": "Invalid first byte of padding", + "ciphertext_hex": "9b2ec9c0c917c98f1ad3d0119aec6be51ae3106e9af1914d48600ab6a2c0c0c8ae02a2dc3039906ff3aac904af32ec798fd65f3ad1afa2e69400e7c1de81f5728f3b3291f38263bc7a90a0563e43ce7a0d4ee9c0d8a716621ca5d3d081188769ce1b131af7d35b13dea99153579c86db31fe07d5a2c14d621b77854e48a8df41b5798563af489a291e417b6a334c63222627376118c02c53b6e86310f728734ffc86ef9d7c8bf56c0c841b24b82b59f51aee4526ba1c4268506d301e4ebc498c6aebb6fd5258c876bf900bac8ca4d309dd522f6a6343599a8bc3760f422c10c72d0ad527ce4af1874124ace3d99bb74db8d69d2528db22c3a37644640f95c05f", + "expected_hex": "a1f8c9255c35cfba403ccc" + }, + { + "title": "Invalid second byte of padding", + "ciphertext_hex": "782c2b59a21a511243820acedd567c136f6d3090c115232a82a5efb0b178285f55b5ec2d2bac96bf00d6592ea7cdc3341610c8fb07e527e5e2d20cfaf2c7f23e375431f45e998929a02f25fd95354c33838090bca838502259e92d86d568bc2cdb132fab2a399593ca60a015dc2bb1afcd64fef8a3834e17e5358d822980dc446e845b3ab4702b1ee41fe5db716d92348d5091c15d35a110555a35deb4650a5a1d2c98025d42d4544f8b32aa6a5e02dc02deaed9a7313b73b49b0d4772a3768b0ea0db5846ace6569cae677bf67fb0acf3c255dc01ec8400c963b6e49b1067728b4e563d7e1e1515664347b92ee64db7efb5452357a02fff7fcb7437abc2e579", + "expected_hex": "e6d700309ca0ed62452254" + }, + { + "title": "Invalid with zero length PS", + "ciphertext_hex": "0096136621faf36d5290b16bd26295de27f895d1faa51c800dafce73d001d60796cd4e2ac3fa2162131d859cd9da5a0c8a42281d9a63e5f353971b72e36b5722e4ac444d77f892a5443deb3dca49fa732fe855727196e23c26eeac55eeced8267a209ebc0f92f4656d64a6c13f7f7ce544ebeb0f668fe3a6c0f189e4bcd5ea12b73cf63e0c8350ee130dd62f01e5c97a1e13f52fde96a9a1bc9936ce734fdd61f27b18216f1d6de87f49cf4f2ea821fb8efd1f92cdad529baf7e31aff9bff4074f2cad2b4243dd15a711adcf7de900851fbd6bcb53dac399d7c880531d06f25f7002e1aaf1722765865d2c2b902c7736acd27bc6cbd3e38b560e2eecf7d4b576", + "expected_hex": "ba27b1842e7c21c0e7ef6a" + }, + { + "title": "Invalid with null byte at the eighth byte of padding", + "ciphertext_hex": "a7a340675a82c30e22219a55bc07cdf36d47d01834c1834f917f18b517419ce9de2a96460e745024436470ed85e94297b283537d52189c406a3f533cb405cc6a9dba46b482ce98b6e3dd52d8fce2237425617e38c11fbc46b61897ef200d01e4f25f5f6c4c5b38cd0de38ba11908b86595a8036a08a42a3d05b79600a97ac18ba368a08d6cf6ccb624f6e8002afc75599fba4de3d4f3ba7d208391ebe8d21f8282b18e2c10869eb2702e68f9176b42b0ddc9d763f0c86ba0ff92c957aaeab76d9ab8da52ea297ec11d92d770146faa1b300e0f91ef969b53e7d2907ffc984e9a9c9d11fb7d6cba91972059b46506b035efec6575c46d7114a6b935864858445f", + "expected_hex": "63cb0bf65fc8255dd29e17" + }, + { + "title": "Invalid with padding separator missing", + "ciphertext_hex": "3d1b97e7aa34eaf1f4fc171ceb11dcfffd9a46a5b6961205b10b302818c1fcc9f4ec78bf18ea0cee7e9fa5b16fb4c611463b368b3312ac11cf9c06b7cf72b54e284848a508d3f02328c62c2999d0fb60929f81783c7a256891bc2ff4d91df2af96a24fc5701a1823af939ce6dbdc510608e3d41eec172ad2d51b9fc61b4217c923cadcf5bac321355ef8be5e5f090cdc2bd0c697d9058247db3ad613fdce87d2955a6d1c948a5160f93da21f731d74137f5d1f53a1923adb513d2e6e1589d44cc079f4c6ddd471d38ac82d20d8b1d21f8d65f3b6907086809f4123e08d86fb38729585de026a485d8f0e703fd4772f6668febf67df947b82195fa3867e3a3065", + "expected_hex": "6f09a0b62699337c497b0b" + } + ] + }, + { + "id": "k2049", + "modulus_bits": 2049, + "section": "B.2. 2049-bit key", + "cases": [ + { + "title": "Valid", + "ciphertext_hex": "013300edbf0bb3571e59889f7ed76970bf6d57e1c89bbb6d1c3991d9df8e65ed54b556d928da7d768facb395bbcc81e9f8573b45cf8195dbd85d83a59281cddf4163aec11b53b4140053e3bd109f787a7c3cec31d535af1f50e0598d85d96d91ea01913d07097d25af99c67464ebf2bb396fb28a9233e56f31f7e105d71a23e9ef3b736d1e80e713d1691713df97334779552fc94b40dd733c7251bc522b673d3ec9354af3dd4ad44fa71c0662213a57ada1d75149697d0eb55c053aaed5ffd0b815832f454179519d3736fb4faf808416071db0d0f801aca8548311ee708c131f4be658b15f6b54256872c2903ac708bd43b017b073b5707bc84c2cd9da70e967", + "expected_hex": "6c6f72656d20697073756d" + }, + { + "title": "Valid empty", + "ciphertext_hex": "00cc52e83755a4526fea5e62450450638430a84a5878fd12c2a571f33c55729cfab6e35c2e1703c452cff65731249460919aeb1b40084bdef573407851e48b3c72923e48d5c4f3e80990c462bc291a3e635515636ab9ebeb317ca0d75b04b80c17e2f4851f8929f72c9bea4ec4a6a1fbc5155837813567062d6b4b2a6b6e40be545d25da39b08c52f3543e2f2cdfa314832dcbf475fcbb8d3565a64bb09b55f922e6ec6cd8bb5203a11e2fa0c1b383674c4f0b63acd78f3690e3a16ad1b71f6cfe48c56533e2ae42b1393b2d156c2323272490a574ce4f14055249b6a34c3e08d4a417039450910ec34bd5f08eb06078f51bdd6e50334ee64c9695a5bde52938e3", + "expected_hex": "" + }, + { + "title": "Valid with ciphertext starting with a zero byte", + "ciphertext_hex": "0002aadf846a329fadc6760980303dbd87bfadfa78c2015ce4d6c5782fd9d3f1078bd3c0a2c5bfbdd1c024552e5054d98b5bcdc94e476dd280e64d650089326542ce7c61d4f1ab40004c2e6a88a883613568556a10f3f9edeab67ae8dddc1e6b0831c2793d2715de943f7ce34c5c05d1b09f14431fde566d17e76c9feee90d86a2c158616ec81dda0c642f58c0ba8fa4495843124a7235d46fb4069715a51bf710fd024259131ba94da73597ace494856c94e7a3ec261545793b0990279b15fa91c7fd13dbfb1df2f221dab9fa9f7c1d21e48aa49f6aaecbabf5ee76dc6c2af2317ffb4e303115386a97f8729afc3d0c89419669235f1a3a69570e0836c79fc162", + "expected_hex": "6c6f72656d20697073756d" + }, + { + "title": "Invalid decrypting to empty", + "ciphertext_hex": "0128a1f7837e53b21ee37f0b4d08c76180305d5d854a1bcf3885471610646795f1e4c85ce7fce0f71ac3504598afdfc26792dea8ac55c7da10f96d26236ae652b282459d679ec84847d523f07213e81d1c713fb159eded43112eab68b610e3f871d9c0009fde783ad7bcdca5568f7a86a716be6b96219c34b061f68718abad7c947ed107097dc68341b865d73f2e857a345f5cf05c53bb2899d2895565009125c7b5fe1c35a73c03bb0f59e7faf381c784988bb71194307ee9a8ac122990fabb5cc1fd877aaa79039ac163d084c7ee1642aaf05befb9d7ed0e29558f11f0708c8e83f804f92fd41310a6fd21d91c3ceb88ceee3e424a3fcdda57fe3abb8b7bae7d", + "expected_hex": "" + }, + { + "title": "Invalid decrypting to max size", + "ciphertext_hex": "013a60aa202dedad2d9e78c0c99077ccc17b7d0533aeaf184dcb8c9a81ca4de5715ada598d59b926606dcb005935421f6ebfd32e62802f0e2de8df08f1ae00e4aced6ebf361a38df817c892309bd07c92c4f2f7be89f286f99711372e3dd959ccb0a150b28578f29040b39ecf989c26eb77a3480c2d4d363b9563a70f0a0789cc4300af1e600de39dae4a49335d35ac0156f5395ebebf35531c819c9cf498a97e67ee2299d84564444f7bcd51f9f08d6bac0872439ad57eb9a8134dc665add1f813d5031484c905a433c115bf889dc46ac672a8898fe235bf463b1b46345299b6f100b48fa954fc262ce58e83f95955b321c1e86bbfe398b588dd5c75c2c68532b", + "expected_hex": "5c5345594cec69769af002af6513415a0848a4d45601c44b9e84b6e0a42c1356cfc20604df8d334de53fafc6de2125f2eae2ec9864b0b0d03ef1539017ecf312460cbb3c7c49fe124cf1becce8903f227ec85daaae73fe256acdf39f47b46c14fbd289d7f9b9e22ee0e7c5d77cbbf22a2f9fbf4e26c5999a7b8335f6478912edfb77a373a82dabbc8233e585ea5ddfef3d0d872a4a007018005014a8873495951210a4b90209b8286466030e56b1050ed600c777b4dbdb64f86516ef269a3ba77285f9be9afebcaad35226f7b3296932baf8dbfea3d77eb6520da203ffc0672232761e2a8a05186181b8dd1f77f069f7af8de118aa18" + }, + { + "title": "Invalid with null padded ciphertext", + "ciphertext_hex": "000a56cfd7abf21e2c65a28b8145fee663818b6cd218601e9e62bed7de5ac74ceb07b435b305c99e3e286152036086b4a13eb26164f6f4bf79ac7d6c3fbcdcd74c6dc324c04949a0c88cbf616626cb171a4e333a0e124524b44f78e2d8100c03e231791523b7d76db2d464e6b5e64244e04ad21128a5feb56092b4ceda35ebfb84f7fafa8e1c098d9923d66e541b36307574db8912630fcf734af7bcd4118f1f700804c5001a5950780188fc7862384fb3fc0708eaf3cb2b119177bb6928758fa75e644d258ac02748dcae7a78ec6c8679598fa9deee4663f1efe27efe8bd15572ff40676b95469aaa42eab4226d86c1160343255cce4fb7728f7349da27ed096b", + "expected_hex": "fc874af235e261083c2c" + }, + { + "title": "Invalid with second to last length", + "ciphertext_hex": "011644d88f2955389b6d215fc3acd733265d82348fa15178d99e38fd2842030d4e31d1ab15b0f00a80add1a9bfe112f9c42e827c487193c360dc5888c8c42d5459b1f2c1952dca679ded08f190b6a78bbb6ea00438ebb8b03dc56e45cb36bee49a385c71fbf9bbcceda7b130ad6cee2106eff34dd224fba8e9990edf893ae52b0910cdadf44bf29812a98bb9dc1638815112950bb9e7bad11c610d6406dd2d1c36cddd639e024205a1a2bd82ec97059ef61b5226e3246ca672962194d1222cc032003fe34bf5ca0227f1c86439dcfba5203cf57099884276b0fbbf9b9cec93392673d8290a1a3452f3791c3881c9be6a1eef23841a8a5fde255cbbd3c4fc33827c", + "expected_hex": "9b9b496e44544456e70d9be86bd398dae00c7c05d6ea76c45d12f050b1c61c219b2fe47749451e44d96d11916f6ec4cf9eea67cb" + }, + { + "title": "Invalid first byte of padding", + "ciphertext_hex": "002c9ddc36ba4cf0038692b2d3a1c61a4bb3786a97ce2e46a3ba74d03158aeef456ce0f4db04dda3fe062268a1711250a18c69778a6280d88e133a16254e1f0e30ce8dac9b57d2e39a2f7d7be3ee4e08aec2fdbe8dadad7fdbf442a29a8fb40857407bf6be35596b8eefb5c2b3f58b894452c2dc54a6123a1a38d642e23751746597e08d71ac92704adc17803b19e131b4d1927881f43b0200e6f95658f559f912c889b4cd51862784364896cd6e8618f485a992f82997ad6a0917e32ae5872eaf850092b2d6c782ad35f487b79682333c1750c685d7d32ab3e1538f31dcaa5e7d5d2825875242c83947308dcf63ba4bfff20334c9c140c837dbdbae7a8dee72ff", + "expected_hex": "f6d0f5b78082fe61c04674" + }, + { + "title": "Invalid second byte of padding", + "ciphertext_hex": "00c5d77826c1ab7a34d6390f9d342d5dbe848942e2618287952ba0350d7de6726112e9cebc391a0fae1839e2bf168229e3e0d71d4161801509f1f28f6e1487ca52df05c466b6b0a6fbbe57a3268a970610ec0beac39ec0fa67babce1ef2a86bf77466dc127d7d0d2962c20e66593126f276863cd38dc6351428f884c1384f67cad0a0ffdbc2af16711fb68dc559b96b37b4f04cd133ffc7d79c43c42ca4948fa895b9daeb853150c8a5169849b730cc77d68b0217d6c0e3dbf38d751a1998186633418367e7576530566c23d6d4e0da9b038d0bb5169ce40133ea076472d055001f0135645940fd08ea44269af2604c8b1ba225053d6db9ab43577689401bdc0f3", + "expected_hex": "1ab287fcef3ff17067914d" + }, + { + "title": "Invalid with zero length PS", + "ciphertext_hex": "011e24da411e182d85e7c350a7dbff898c3e17bee1573fe3d0c0d3be53a384a65d597d52247e56d10b01cf1a51533e47c37f38bc62490e449b5f4ea35aec422a63142c95da26e800e14504ce704edc7e38faaff697b74814c14d19f7f6f4d942c1db61eca70266748ed83195bffa2eb85f49047a7bc7aae7f927ff445f15136b28b4cad396312ae09a62ef894688ad50bc53d6977236b76d30c9bb2dacd0d58300f2b3dc69a7c3212c6dcf6db583c59d94e7550ecc871991139259a9a001451635c777c7ac46db113a2460f157f9f830c186f0a0c47ca3012c8d309bea899852febe76b87874292b8230be9de5c88fb94a0f19b2df71ca1efeb5f772b2d9b38016", + "expected_hex": "5659f49338cfcd423dfcce" + }, + { + "title": "Invalid with null byte at the eighth byte of padding", + "ciphertext_hex": "014b47d00714b92e98eacd73b07816ef530f8355fca68de6ba56828afab9d43b96fcb11bee0e900e966a51705b95e82599f3df202d51d520c96adf32e1c0758a7e0a8694699af8cfd9ed2850678f70e952f029a4b461ac8a8e049ef9ffc483ebdc9a525bae3ddf8d69f8f711d30135fd9cce0c3d09d1a75c5b837d9f0d86827a5f9edccd56af835572ba099a44a69277f31999753cd9887fe46ae7c7eb98d5894692847179dac0ba305ed584f2887f7a6e88c843e6f0d4e99ffdcf51e266198301dab2bcb7b07944207c71a89f1449f3690cf09b9f15a5588a2c16d18ef437876285e9d04fd01ff30dea46a3eb17151e63b784548f1c65eeb08bec9901b9353432", + "expected_hex": "c917a56bd800b8d9578657" + }, + { + "title": "Invalid with padding separator missing", + "ciphertext_hex": "01541f0012b2dfd2d2b91cd22570dd577af0d27c29baa4d7a3cec2ddf8cdb957257d8d436455d331e35730d1df7058cbb01649beb236154858843e2e14ae54fd53496883163b8cb30fea540778726453204a846b04535878bebe9e60f8783b77e5dfd4d346cd688aa2ee9e0ba9ac2bfd16005de994ea4a9c40adbafcf79dac4859480a8e6e6849077b07f5e3dce8b97f678fc4b1da7e72004cfae36f01cb23f69180a46e3b9488f3b595e83510c9c4b298c953971d82610562976271e756f97ef317b440271be9847178a482098447516ea29bd599592dbf22e35c91f8e2155bd2f6289bac31c4c608b80bc208608a17cc45f7cff774549782882cf72baf0feb2f", + "expected_hex": "a4e88815652839f2482a8f" + } + ] + }, + { + "id": "k3072", + "modulus_bits": 3072, + "section": "B.3. 3072-bit key", + "cases": [ + { + "title": "Valid", + "ciphertext_hex": "6c60845a854b4571f678941ae35a2ac03f67c21e21146f9db1f2306be9f136453b86ad55647d4f7b5c9e62197aaff0c0e40a3b54c4cde14e774b1c5959b6c2a2302896ffae1f73b00b862a20ff4304fe06cea7ff30ecb3773ca9af27a0b54547350d7c07dfb0a39629c7e71e83fc5af9b2adbaf898e037f1de696a3f328cf45af7ec9aff7173854087fb8fbf34be981efbd8493f9438d1b2ba2a86af082662aa46ae9adfbec51e5f3d9550a4dd1dcb7c8969c9587a6edc82a8cabbc785c40d9fbd12064559fb769450ac3e47e87bc046148130d7eaa843e4b3ccef3675d0630500803cb7ffee3882378c1a404e850c3e20707bb745e42b13c18786c4976076ed9fa8fd0ff15e571bef02cbbe2f90c908ac3734a433b73e778d4d17fcc28f49185ebc6e8536a06d293202d94496453bfdf1c2c7833a3f99fa38ca8a81f42eaa529d603b890308a319c0ab63a35ff8ebac965f6278f5a7e5d622be5d5fe55f0ca3ec993d55430d2bf59c5d3e860e90c16d91a04596f6fdf60d89ed95d88c036dde", + "expected_hex": "666f7274792074776f" + }, + { + "title": "Valid empty", + "ciphertext_hex": "4a454e0dbba01df544fd2fec0099ffd533301e1a4481597f83b8587ff638c029ab434c59ce72bc4b13d0d4901945ad8cef4ef913626b09c9cad69336a9e409e85f59b0d60df25267443009e8e53b4aeed87c5301649db5f7b38d688850f5a408b1c6608af1428f5e8b9262a8638cf89c28babf7df6d3d55101ff18ebf1bdf3c92e66b5ca279f6f4f759d4163f42e49bd836474ca3d48f4a40a5a2974e64c99d2ee282e1b089aa6b360c4c815f743dda33ac12dfb0fe7a2653d753ee5cd8a4129790ca888767f4128d61340bdecc579c3f9f36b1b256b51c1a66c46149f963bc8fd0771ad2cb4b23054f5cc5fcf5534bc97de55bcc831894baaca7c40d46e056a836523c52a84de3d7642ff4ce02f508b7ca1f485a028ca34f4c57417023cb72487ee5fa60fc9caadf29b3fe3ef632abf89baae921fd43ca275b3026e286720f23422203eec63a9b737f9d18987736abf241c46b748a60f68a8dddfc9664312b36ec52b8a7ce8060b830a4de5f2475e14ed0570c631d608935e75da9b091084db", + "expected_hex": "" + }, + { + "title": "Valid with ciphertext starting with a zero byte", + "ciphertext_hex": "00f4d565a3286784dbb85327db8807ae557ead229f92aba945cecda5225f606a7d6130edeeb6f26724d1eff1110f9eb18dc3248140ee3837e6688391e78796c526791384f045e21b6b853fb6342a11f309eb77962f37ce23925af600847fbd30e6e07e57de50b606e6b7f288cc777c1a6834f27e6edace508452128916eef7788c8bb227e3548c6a761cc4e9dd1a3584176dc053ba3500adb1d5e1611291654f12dfc5722832f635db3002d73f9defc310ace62c63868d341619c7ee15b20243b3371e05078e11219770c701d9f341af35df1bc729de294825ff2e416aa11526612852777eb131f9c45151eb144980d70608d2fc4043477368369aa0fe487a48bd57e66b00c3c58f941549f5ec050fca64449debe7a0c4ac51e55cb71620a70312aa4bd85fac1410c9c7f9d6ec610b7d11bf8faeffa20255d1a1bead9297d0aa8765cd2805847d639bc439f4a6c896e2008f746f9590ff4596de5ddde000ed666c452c978043ff4298461eb5a26d5e63d821438627f91201924bf7f2aeee1727", + "expected_hex": "666f7274792074776f" + }, + { + "title": "Invalid decrypting to empty", + "ciphertext_hex": "5e956cd9652f4a2ece902931013e09662b6a9257ad1e987fb75f73a0606df2a4b04789770820c2e02322c4e826f767bd895734a01e20609c3be4517a7a2a589ea1cdc137beb73eb38dac781b52e863de9620f79f9b90fd5b953651fcbfef4a9f1cc07421d511a87dd6942caab6a5a0f4df473e62defb529a7de1509ab99c596e1dff1320402298d8be73a896cc86c38ae3f2f576e9ea70cc28ad575cb0f854f0be43186baa9c18e29c47c6ca77135db79c811231b7c1730955887d321fdc06568382b86643cf089b10e35ab23e827d2e5aa7b4e99ff2e914f302351819eb4d1693243b35f8bf1d42d08f8ec4acafa35f747a4a975a28643ec630d8e4fa5be59d81995660a14bb64c1fea5146d6b11f92da6a3956dd5cb5e0d747cf2ea23f81617769185336263d46ef4c144b754de62a6337342d6c85a95f19f015724546ee3fc4823eca603dbc1dc01c2d5ed50bd72d8e96df2dc048edde0081284068283fc5e73a6139851abf2f29977d0b3d160c883a42a37efba1be05c1a0b1741d7ddf59", + "expected_hex": "" + }, + { + "title": "Invalid decrypting to max size", + "ciphertext_hex": "1715065322522dff85049800f6a29ab5f98c465020467414b2a44127fe9446da47fa18047900f99afe67c2df6f50160bb8e90bff296610fde632b3859d4d0d2e644f23835028c46cca01b84b88231d7e03154edec6627bcba23de76740d839851fa12d74c8f92e540c73fe837b91b7d699b311997d5f0f7864c486d499c3a79c111faaacbe4799597a25066c6200215c3d158f3817c1aa57f18bdaad0be1658da9da93f5cc6c3c4dd72788af57adbb6a0c26f42d32d95b8a4f95e8c6feb2f8a5d53b19a50a0b7cbc25e055ad03e5ace8f3f7db13e57759f67b65d143f08cca15992c6b2aae643390483de111c2988d4e76b42596266005103c8de6044fb7398eb3c28a864fa672de5fd8774510ff45e05969a11a4c7d3f343e331190d2dcf24fb9154ba904dc94af98afc5774a9617d0418fe6d13f8245c7d7626c176138dd698a23547c25f27c2b98ea4d8a45c7842b81888e4cc14e5b72e9cf91f56956c93dbf2e5f44a8282a7813157fc481ff1371a0f66b31797e81ebdb09a673d4db96d6", + "expected_hex": "7b036fcd6243900e4236c894e2462c17738acc87e01a76f4d95cb9a328d9acde81650283b8e8f60a217e3bdee835c7b222ad4c85d0acdb9a309bd2a754609a65dec50f3aa04c6d5891034566b9563d42668ede1f8992b17753a2132e28970584e255efc8b45a41c5dbd7567f014acec5fe6fdb6d484790360a913ebb9defcd74ff377f2a8ba46d2ed85f733c9a3da08eb57ecedfafda806778f03c66b2c5d2874cec1c291b2d49eb194c7b5d0dd2908ae90f4843268a2c45563092ade08acb6ab481a08176102fc803fbb2f8ad11b0e1531bd37df543498daf180b12017f4d4d426ca29b4161075534bfb914968088a9d13785d0adc0e2580d3548494b2a9e91605f2b27e6cc701c796f0de7c6f471f6ab6cb9272a1ed637ca32a60d117505d82af3c1336104afb537d01a8f70b510e1eebf4869cb976c419473795a66c7f5e6e20a8094b1bb603a74330c537c5c0698c31538bd2e138c1275a1bdf24c5fa8ab3b7b526324e7918a382d1363b3d463764222150e04" + }, + { + "title": "Invalid with null padded ciphertext", + "ciphertext_hex": "00128e116c0d348217c1d5756611be833caec3bd19f3d2ed383c4523ef3d8a5cd1130bdb3fcd3ba1c0265322fc98c767b3b971054f5e3067a32b4878bbf7e17db80a855427e2e7d2ec26294b79edbb6352c7812270040e3cbaf560de1486171da649af786551ae0e5b6ef1fa1e22196c1c3039a50cfe09620da09716e75e9a9b5ad164953c5a7e48f77ef9e0f59e962cf3985dc572ded966e8241632a9a5a4203500a50d70491d80846b72019c456bfbdf7f15f740af0c2ef2a46787c54dcd90a0e91257642f2c10b21052024b1d28ad14d78c0d9702a14b9ab9552f023bfb716f9c9a1f691959057f52b197086fb9bc24d45e2b063ffb235b54d3ab7575c7f3e411398ddb30945c15f3f5d5ebbe302f22f60047d139d402f5b8a959421d1946cf748c84065c5d0f0302f7ade6335014ab4467698ad827684d2bdeeb4757d276f131340438506473f271c3fe24ca58e1c60dcc17aff8b0373637d897f627ea571da148a81d399ced9d65a4564bb6d23fbf4c14674d7551283a4293de51a1516a", + "expected_hex": "732f025d1adea74649b4" + }, + { + "title": "Invalid with second to last length", + "ciphertext_hex": "7db0390d75fcf9d4c59cf27b264190d856da9abd11e92334d0e5f71005cfed865a711dfa28b791188374b61916dbc11339bf14b06f5f3f68c206c5607380e13da3129bfb744157e1527dd6fdf6651248b028a496ae1b97702d44706043cdaa7a59c0f41367303f21f268968bf3bd2904db3ae5239b55f8b438d93d7db9d1666c071c0857e2ec37757463769c54e51f052b2a71b04c2869e9e7049a1037b8429206c99726f07289bac18363e7eb2a5b417f47c37a55090cda676517b3549c873f2fe95da9681752ec9864b069089a2ed2f340c8b04ee00079055a817a3355b46ac7dc00d17f4504ccfbcfcadb0c04cb6b22069e179385ae1eafabad5521bac2b8a8ee1dfff59a22eb3fdacfc87175d10d7894cfd869d056057dd9944b869c1784fcc27f731bc46171d39570fbffbadf082d33f6352ecf44aca8d9478e53f5a5b7c852b401e8f5f74da49da91e65bdc97765a9523b7a0885a6f8afe5759d58009fbfa837472a968e6ae92026a5e0202a395483095302d6c3985b5f5831c521a271", + "expected_hex": "56a3bea054e01338be9b7d7957539c" + }, + { + "title": "Invalid first byte of padding", + "ciphertext_hex": "6db80adb5ff0a768caf1378ecc382a694e7d1bde2eff4ba12c48aaf794ded7a994a5b2b57acec20dbec4ae385c9dd531945c0f197a5496908725fc99d88601a17d3bb0b2d38d2c1c3100f39955a4cb3dbed5a38bf900f23d91e173640e4ec655c84fdfe71fcdb12a386108fcf718c9b7af37d39703e882436224c877a2235e8344fba6c951eb7e2a4d1d1de81fb463ac1b880f6cc0e59ade05c8ce35179ecd09546731fc07b141d3d6b342a97ae747e61a9130f72d37ac5a2c30215b6cbd66c7db893810df58b4c457b4b54f34428247d584e0fa71062446210db08254fb9ead1ba1a393c724bd291f0cf1a7143f32df849051dc896d7d176fef3b57ab6dffd626d0c3044e9edb2e3d012ace202d2581df01bec7e9aa0727a6650dd373d374f0bc0f4a611f8139dfe97d63e70c6188f4df5b672e47c51d8aa567097293fbff127c75ec690b43407578b73c85451710a0cece58fd497d7f7bd36a8a92783ef7dc6265dff52aac8b70340b996508d39217f2783ce6fc91a1cc94bb2ac487b84f62", + "expected_hex": "6d8d3a094ff3afff4c" + }, + { + "title": "Invalid second byte of padding", + "ciphertext_hex": "417328c034458563079a4024817d0150340c34e25ae16dcad690623f702e5c748a6ebb3419ff48f486f83ba9df35c05efbd7f40613f0fc996c53706c30df6bba6dcd4a40825f96133f3c21638a342bd4663dffbd0073980dac47f8c1dd8e97ce1412e4f91f2a8adb1ac2b1071066efe8d718bbb88ca4a59bd61500e826f2365255a409bece0f972df97c3a55e09289ef5fa815a2353ef393fd1aecfc888d611c16aec532e5148be15ef1bf2834b8f75bb26db08b66d2baad6464f8439d1986b533813321dbb180080910f233bcc4dd784fb21871aef41be08b7bfad4ecc3b68f228cb5317ac6ec1227bc7d0e452037ba918ee1da9fdb8393ae93b1e937a8d4691a17871d5092d2384b6190a53df888f65b951b05ed4ad57fe4b0c6a47b5b22f32a7f23c1a234c9feb5d8713d949686760680da4db454f4acad972470033472b9864d63e8d23eefc87ebcf464ecf33f67fbcdd48eab38c5292586b36aef5981ed2fa07b2f9e23fc57d9eb71bfff4111c857e9fff23ceb31e72592e70c874b4936", + "expected_hex": "c6ae80ffa80bc184b0" + }, + { + "title": "Invalid with zero length PS", + "ciphertext_hex": "8542c626fe533467acffcd4e617692244c9b5a3bf0a215c5d64891ced4bf4f9591b4b2aedff9843057986d81631b0acb3704ec2180e5696e8bd15b217a0ec36d2061b0e2182faa3d1c59bd3f9086a10077a3337a3f5da503ec3753535ffd25b837a12f2541afefd0cffb0224b8f874e4bed13949e105c075ed44e287c5ae03b155e06b90ed247d2c07f1ef3323e3508cce4e4074606c54172ad74d12f8c3a47f654ad671104bf7681e5b061862747d9afd37e07d8e0e2291e01f14a95a1bb4cbb47c304ef067595a3947ee2d722067e38a0f046f43ec29cac6a8801c6e3e9a2331b1d45a7aa2c6af3205be382dd026e389614ee095665a611ab2e8dced2ee1c9d08ac9de11aef5b3803fc9a9ce8231ec87b5fed386fb92ee3db995a89307bcba844bd0a691c29ae51216e949dfc813133cb06a07265fd807bcb3377f6adb0a481d9b7f442003115895939773e6b95371c4febef29edae946fa245e7c50729e2e558cfaad773d1fd5f67b457a6d9d17a847c6fcbdb103a86f35f228cefc06cea0", + "expected_hex": "a8a9301daa01bb25c7" + }, + { + "title": "Invalid with null byte at the eighth byte of padding", + "ciphertext_hex": "449dfa237a70a99cb0351793ec8677882021c2aa743580bf6a0ea672055cffe8303ac42855b1d1f3373aae6af09cb9074180fc963e9d1478a4f98b3b4861d3e7f0aa8560cf603711f139db77667ca14ba3a1acdedfca9ef4603d6d7eb0645bfc805304f9ad9d77d34762ce5cd84bd3ec9d35c30e3be72a1e8d355d5674a141b5530659ad64ebb6082e6f73a80832ab6388912538914654d34602f4b3b1c78589b4a5d964b2efcca1dc7004c41f6cafcb5a7159a7fc7c0398604d0edbd4c8f4f04067da6a153a05e7cbeea13b5ee412400ef7d4f3106f4798da707ec37a11286df2b7a204856d5ff773613fd1e453a7114b78e347d3e8078e1cb3276b3562486ba630bf719697e0073a123c3e60ebb5c7a1ccff4279faffa2402bc1109f8d559d6766e73591943dfcf25ba10c3762f02af85187799b8b4b135c3990793a6fd32642f1557405ba55cc7cf7336a0e967073c5fa50743f9cc5e3017c172d9898d2af83345e71b3e0c22ab791eacb6484a32ec60ebc226ec9deaee91b1a0560c2b571", + "expected_hex": "6c716fe01d44398018" + }, + { + "title": "Invalid with padding separator missing", + "ciphertext_hex": "a7a5c99e50da48769ecb779d9abe86ef9ec8c38c6f43f17c7f2d7af608a4a1bd6cf695b47e97c191c61fb5a27318d02f495a176b9fae5a55b5d3fabd1d8aae4957e3879cb0c60f037724e11be5f30f08fc51c033731f14b44b414d11278cd3dba7e1c8bfe208d2b2bb7ec36366dacb6c88b24cd79ab394adf19dbbc21dfa5788bacbadc6a62f79cf54fd8cf585c615b5c0eb94c35aa9de25321c8ffefb8916bbaa2697cb2dd82ee98939df9b6704cee77793edd2b4947d82e00e5749664970736c59a84197bd72b5c71e36aae29cd39af6ac73a368edbc1ca792e1309f442aafcd77c992c88f8e4863149f221695cb7b0236e75b2339a02c4ea114854372c306b9412d8eedb600a31532002f2cea07b4df963a093185e4607732e46d753b540974fb5a5c3f9432df22e85bb17611370966c5522fd23f2ad3484341ba7fd8885fc8e6d379a611d13a2aca784fba2073208faad2137bf1979a0fa146c1880d4337db3274269493bab44a1bcd0681f7227ffdf589c2e925ed9d36302509d1109ba4", + "expected_hex": "aa2de6cde4e2442884" + } + ] + }, + { + "id": "k4096", + "modulus_bits": 4096, + "section": "B.4. 4096-bit key", + "cases": [ + { + "title": "Valid", + "ciphertext_hex": "041f9bbe8372454ffadce0befc99ad4bd01cdbe016dffb5d0d84ee879e7ff64a25dced4d504f48a14b700a34a1c148e4b4028eecc9158cf5e3469daad1dddb2157b176dcf5716627aebd6072b965cfb67b42b149e88c0a8dc54703ec244637b3039b80c06d1d4968aeb838f3afcd3dc675fc90736cf0f0adaba182e27a19a7294cef500ed1fcca324c3ffa6ff02bd749a4a66f18da138d53ff549c4e6b3fff0b9ee2029ea8293fcd72a03e1dee4445629979be7fd65e5dbe5e6e77ec2aa87879a01c3e2502af0cc4bc04b637d17b175d92b4dcd70cfe83b6c1d4f91c61e911b81cb6d60b99146f17937d127054521b132acb9ca95cbc6f80cd926d709bd7219d48ce7378e4416328a49be6c773dbdeb00ce23dc91f25f4807526cf4de8dd3fbb13ae1011eefe3a2aad9982f6c9268883b4633057d119c97c1178aae671859af0a488ab7b841c6583572d1261137a4292ba1c1caa4baf808be42075940d7e612efa56ac9a7ffff3e7dbf10b6193ea14c4841fc5c43e031a69ddbd79118ccd92b16a6ef66c7404c001ebc6402301a90248eb6562b7a2f549f52c058109dd5f2617877719ad13e81d19425a4cd5cf9e56e8538f5cb09b6f7ab646910b8c2ff6bf8cf17abdb4758bfba80df9f643950a6d4a8f60c6872700e5919d36503486667e4328a6b74b774eb483a9922706baa7f456644781cc0d78add9024e28da2d5e9d81", + "expected_hex": "6c6f72656d20697073756d" + }, + { + "title": "Valid empty", + "ciphertext_hex": "31529676f990b750e8b742babe933346bd77610e7ea74a6b815bb06ee3c91a376848a4d8b148c2882d65ca0213e68600354b68b7790110ed744e34786fa5f7b703144a12f7f7a4d5402ef048f248fec83dede7f931bcb872054fd25cfe4279840352f2c495bcb511cf20269d8177baba474e790a2d16b655c4e07b28ad6a61e81ce5db3845cb5395aa4affa413e3f1bdecf3fa0aa3073b40d23e9bb0aa7cf3595bd73d1d38a2661d70a8e4ef525fd446f496ddbe5413657c06d51464977421e057387a92a5b9428d02d1a8fb0d50a1623e1b1d0685c371db24b63dd6a4aebf0e31c637997ae26dbd3441b9f7dce164d948a156aee8c9dc4049286244c85178f7b4f49d3ba0870f7c71f8f546a902a559fd860ed61e550c4143907d118a15f317e9ccd84ce3893db372fff1d9a9e5182258d9f9d840a6b75b1618ce4999734d147f5334763c0b87ca1c8e57c6f923cff9c7107eea45cf5d4fae0ec0b94e892a6f6790b07f9e24bff041620b1fb47bcefb956ba61949fea02db6ec785b4070e84f390234d83d17dbf89819d5c6b52a488f36cd9f8d81e1811bbadbd6756b9ec5fbdcc1d32728efc8ef4318463996c0f829f9064436580f9502af97b1e40c854b0ef0a20da4368e5b94327b62c27a8a1cf6103bc780e06e5ee5232624fe5bee59fe79a3956a7d782380a3398eab6d11f618fc2c698eb28a6029f846c378ecf2d102", + "expected_hex": "" + }, + { + "title": "Valid with ciphertext starting with a zero byte", + "ciphertext_hex": "00c40ab6440e544ced2c0bbd3f6db05fd0068eb8e9ed83099cf5843ea3d2cfd6adf7ede1c61f1974a5696f503205346b51d7b00eca20432f0082abf2a3cd67433c5f860b32f1f6fe9985dcec65e7f19949999e142bc76ce5b2dcb80615d379e9715ac24ef77fbbe3d969131c0f39666b3ad641fac669d53542ae9389d86f6f28fe63ba272b1f6bd015b4187b6e2014fb74fc32bf4a2e48abfbfc0470956c73791c1d81db6c024f4d1cc81ba01be114b41ddb95572a832086c33fcaf90b32358b5b13ef0bea74a6dd01d5c351a231d4e7d15d121cffff023e0c2bdac11c982fb2419955a495e8dac3d84cbd8d71ac380072a02bb026ed61151f0d202b3133e6030a2db7560ca926de3927f1ed578522edac441071498b4565fb0c8071886b79fc9e8d8c14bec1d7a6106441c16e9b2bd3090dad1fe82d0e43f40b036f00506cea36af61d5f10aac0d0591c12107ceb8999787e34943974025b9c47d16cb523a58c5828da975fa74e431ace2dcf934e21613f877f65c67b729ca79ee25f27ea07a74ff38c3b25bcaf22dfe2e9e5d0adecaa01d98d55b5cd0b20f80e672d1bedf4acda32184db0f5ce89dd64f538f038cbefb625347ef77a16ab9d48dbee9549f1c8d55b5470a5c6693bec146f0190bbca5b93a66667150a661851add729b24dca78a1f051093ecd40a0ac43a593101f579597b7638065bdff4191bdc0cae12c052", + "expected_hex": "6c6f72656d20697073756d" + }, + { + "title": "Invalid decrypting to empty", + "ciphertext_hex": "577d6457be536bf1fac80993f5f76e797607227a42e325deb246bf8bf475e1d1819c5dfb6d288eb131ead32238b7a8796b76517e78f979b34f5c2272ae4d40e60b265ad3c897ecc4d26587c8ac32db431ed8d2996d64edadf7719baa4b4292b34e042f26693c90f04addffe8ba0e3c3f1cbabafbfd2e3a6bcd9203e9a1cebb1c968caa73430556ea5743ecfa49edab656bfeadf7c114105f3e222fe60983d55bc48cb738c5a307353281c573be6ffc69630185ae6de695c35fbf8cbc24b5590f5e511adb68a38a37bc6dc74a5052e5063f20c30d2f331dafb07797f9e577cb3d18280f318fe2a6116cef6846b7a8384663a5aaac32693b9b159f506d8812f76a1ee405abb1e5e439a0aee4d1b51f435ea2d043fe4f4ef1a6ccf069201ceb7978139eed579b01bcb5b4e525cce6b179f72fcb6aabbd916538d580ce3e1ed57a4d3433efd826fffd75d8fdc43de69afab66dc32a4f4f81b14c0650a097709265e26b57f233008013b275e7b58817b02f4473a99bb48ec7d9562bc78d1f032340d3083b762f19fb204be7f26d7ceef6c7ff712479a6cdf18123586b87c2751493f1bb2585626b1aa486a2ec50a197728cf24d3968e6d9b9bdfedfda91db292abdeffda2334c85fd359e65e7e662193b6feb5df6d70c7727880150c785d809ba3ffce3b2701aad313da60cd4affe85e85d32c4fe271b0b107e529a22cffbb01871c8", + "expected_hex": "" + }, + { + "title": "Invalid decrypting to max size", + "ciphertext_hex": "09be60b83b63aa1f2398c6ccd7ba602917dfffbc1a2ee01094221ef7140ba8b364b4979b7d068be084d34b70309bc48103d9e7dc76c042d1063ce6d7239d3542ad511da821c6ad53dcaefdd9e950de889d1d462a5a8bcdda4e2ac579c0dc12ab684a16a3c4075ec5062db79f95e5b436a8927fe7e3a795152cb6407faedf088ae4531cca8482348a3c44267b1ea46fa3bfcb4754be735e434c4ef17b84f6fd6c184e8c4adf91fbf00be6a6ff86351e6fd76c8929ef7fae14113370cbe6ba0181ef6970855a2cfde5b366a44bf0575e7e5d5354676b5429a6916bb7065c23417442150f8fa23a1ae284a27008980691eb886b693adb1bf4d38faae5037007900e47124a695c67b51fe9e1e66153cb32fae0e7370151024fe49b2781e50ac5a31d1c7de58923c0360ae61f4a3bcfd7839a104c23d95ddeb76bcaf2b1956f81c355aeb11a46b48762baf072318727e56d4e682a3b71898d3725b00a334c94cb1adccea81525b28c2a1c2b82950b93786ea5b893ffe6dc0932a95b064c838d6f04eaa8334f92b0dec8c7bbc1a5900d7e7680c24e66867ec2b837e30be18083c6fb2bfc67ace569989171f05d312ce97307b477379837351e9199528e88671a93e55868a577fb9eae76a2cbf3cc62c6aaabbee88cf6638012554ba92772e923fbe531fe8aa2036ee7230954ffa24e802a399f531c8cad0a78262442c92089f06b06c7", + "expected_hex": "7a57bf4c557abe6bdd45ed471260ec2749e66710b707ff4e4761738dbe2cdc19267aec5070d2472f53ba0c86e8b607566c871b6c3de28772aa197e369fad293f8218fd32178ecebe60cc7926e093bbdd629ed6a6a29b4a905eefe443f3621d89582a41bac7d4f6b77f9c935681e892d17b2261151a4b4244506cfc49ba578b975840d88f637321d20c25950640d2b43aa660611cc07d016534324b84bada224485488af08a8d54af1698babccd76b87218b074987273dd3746eacd2dee8068d0c4f5e8f219689d55deea3cccb86e52599cebf3777cab3bfc2da5ae31c90199739ba5d5e01816f8f8a21c7f6b6acdada8a2b2ab4f32502d6296a365267a76837878d204a1b8cc5299708e9eb1b44d9663c75c9b8c17dd8f1a9f04109087e22329769fcc5fa65506a0f6294d8bf4a362559c497a36b2a5c55ee12213bd9c42a2dc0f6f35176e194641dcfbb334b13924e6883b4f68c88d016ecdc67bafdeff4b2e4122777726e06b0e37642d42090be622288ce11a8af4261b5d186092002e7d71cb43fc2182e4d341c610e6860904cbc526e74292aa1df81dd08d87b51a953c0be511346d604aa3a8e87f943db3e951a69cc4dcd1b996d3d8ab595aa9b7ca591ae2e9b49798a9b98aa1c1c233f938937c88ad675e6297f36ba0fb161a8b42e9ee9a98d8b781165ed75d30cc55d88e6df5c688c32390" + }, + { + "title": "Invalid with null padded ciphertext", + "ciphertext_hex": "00cd3bf408c742514e30ebfd001708e01f42de439a09d0d4b10044628becd8bc690c45b967a6a900d6259c7d7d20ad49810c270d2fe1b75ffaa84f50071f64d1696bce76e96dbcf2af054d77ded54c742aa38fadba52eebf7a5c8b6dbbf01f28b3ebf4e9b3ca453c92ca8b65771c23671b9da85c51e7a2987395de45b125353d430820b4c90b0ab9fc29e1c576a0ec35828c99c9880e208ecddf80bdaa9c3474561e4c5bf67bf5d144b173f4f28edd1064a9dd8cf5f40b7c35e7e4dbeb370ccabf06efb54e243645b902871a804c27904a620f31ef321af4d1589ca359de889524dfb43ddad51ab50617ab79a50a2d20e2325a05c9963602f2a1d7feaffc80d2b8b88cbd3673531c399342f0bf1c04521d9a441c06593d9e95771129da942d83bb81c627a50c8baafc2a731d97f2e1f638217f9f7b18f2644578fde5073a54a8988fda357c64398a95965a7dd35ffdd7eb7495d4d1c9a950a0cd208a68371829420633cb25e9da9e22b215e50f6ec2714f94ce6abb9a94fbbf6cd18f2fd5bfb78076034b88186957428fe0ea5e1dec7be31d753f155e2a8f7f4854a726612f43ef91f88124011cd32f6841a347dc0411d708db65492ec277b81a335b76a862302acebf7db7cac724144c975ed4d91412eeec4cac3b2409696e3678cffcb7756bde795c55f72da44f325b71dd6ac4e3c1ef512ee8ff24ab316507c6ac60031569", + "expected_hex": "59ccd9c2cfe740e9287b" + }, + { + "title": "Invalid with second to last length", + "ciphertext_hex": "09f010936fd77967dd2aa090be72ecdd8cb2b2a9fb954e644f08a1c1fd5450007ece0b4e8e992831534309419c034b1c4b369269b808a890eac31d5bbfe73737fd716e117e19638064292539e84dae20ec1d98ecd104e6c88d39d3544d5c43c9fd4e9f4361c67116516fc2569f96e5df50a63e949d92009a7c865c7dd70ea89c0002dd697dcd0e0304f8fa0738a3681322e672a9748f9d9eb1b7b8c1646a7bf2a1967b2aa9793ae0ecdbaa2d601350fd931ea164bc02a33a9c22cee47f2d536d92e465180b44e310bf044eec49cc54972d22e735123fbee76496a4c768acef8966ae9e0ed46b753ec47e20a89af0ccf78c266aeb63aeb99d80e4c34bc4608e164aeffd93e886accd426e9e1cfee4f912f235940a9b8d4554953bee8753b8fe05606fe5f46da70394b10f7e71dba3c10becf85a1f4ee619d421ef69fca837d8b1b42598dea0232668b9c42223d77bae7fbe79a9dbf057eeaa51fceac114661a3b572130776c36cfff9f134b08907ab2a6f927145806a779bc55bfb4215cb8c85decaec5b15cd0a4be691b13e068a2381c33fb5adbdb564fd8be0938fdd710590c08f95aa4ea90cc2cea195ef7a344e14715beff2186ad7d898e8f904861ab9133817a13d8a6af23f83a89e5e1e7f8e163d6190e91a09c11939e3a7d48990b8e3b5c0e01b773ba683f7df73b2f88746593c010cd9cab2ea3d9af5ebf30fba1ef0c", + "expected_hex": "0cfdf702efa4dc6bc686" + }, + { + "title": "Invalid first byte of padding", + "ciphertext_hex": "0eb5e0c87c4ffffb760c8fac2a7f5b06f46301ab5b8374a59cc7006aa16e7f38f27d957a4b475b41975246ffb5f2387ffdb62565411733331a4522a07a70bd40ffe23f28f457be55a6cd1b6aab8c7127ec4b0c9d653c3d979fbd371854a80727c0546d9852ccd6220b32a9081f6687fd2262dc806e55964ac799cfba56c0be1a9fb3d4f46161cc5f251ddf3579a87c48c086da786d953829e513a525a87d889661606593600109a98159a91b606f138b9da1b2d427418d50647476fbdd17b52111ca1a2ff9896167277d158d82ade196ad52ea6d381a63748e0068b160331c9cb27c20afbeb696c1db16ea145e96a6e54a825c87c10f85b0d92fc299e254aa7f74c73f17bc704407c31dba9fbda37e31f1231d06744beacb82a0130a9e7d004bed7e7036e33f1c89bd8ed0833def8e946efb53a9ea4abda91f1e1ed44e884d8e45ea692e8f7e2b0f698024c8ed7ade62b251dcb91b249e937a85f823e6978e01e8f7e9ed9c53f2f16d99afe58d3b77b3818aba64e139b3fcb0174542f348f9d2c47dc9d78902a28e1a6613397a0f5938b860a3f6cd44e3b74a37ccdeda248cdeee4a39497d76722e6860127eefdd80f447e69279bf177c1cd6c27ddd3f2f89924f21775df4824ece7f2a6f16266772a13669bfc04aa3b998ad03de17bbc27e629a495052e3e7f0b7b1c06dd4b429585a663172ba20527ad5186447bb74b5f368", + "expected_hex": "8bf3b682d8b950055940" + }, + { + "title": "Invalid second byte of padding", + "ciphertext_hex": "714102bbe701855ec564853befd91262dc4cfbb3c417113c0c650b49c6878b101a76ba4822bde7ca538a2726c6eb9272a3dbda84119ec107d86d2b3a49d82de9d176824f1c2d9cd9b432064c45dbfc60f1e71ec2772aef2669e756cae67ed757b528cccc4ac6f1437a2d4bbedefece1bb5c21381eb4aebc1670c5bd65d408a19c1329b9d9d236939da58a1285357e910edc83d428d1e5315c81cb070aecc24be7fde807ce5d4f50dbe14478334c26be91ed4cb7335c63561b1a8c8c67e40844b465fcf7df6e0df031572682427c62d3cd0c650ec5ef3875fd420516c5cb8089a34757c81360dda37f7fbbd5ea9c8a54ff29f702741a0d496e268a8934b32cd16bea2aa2628397097df0ba08545b9b23bc103a08077745239de34eec09f63fdcbf3aece33a796adbd8dba0705ee3a1092d51f18f195e896b9c35b1a185752c62755c4d9bf2069db141fddc6755c6927cae8d2811aef492f8324ca555b51a4eaf73001ddf88918798df67138a5475fd881b79a158dbe7dd61f241680039a7ae3128a7b925ec7577cddbe116940e2f50ffa3ed36aee7e46ed6dc5b26e7c5f1d16cdc199140742d3fe6bb7d2d4b74d0be675a3388c6fd6d09112dfdea93a701486e38f28add60fb674ac141b389eb4e09153167596a96d2e6618d98593278d22f5605041882743ebafbeb18cdae093609ae6852498bedd8fb6b0a18ce358bfc9d6f2", + "expected_hex": "630fbcef34c1b72f790d" + }, + { + "title": "Invalid with zero length PS", + "ciphertext_hex": "1dd961276ba110ba4fdaf4f177780cbcb6373d2ae6769417a32c9b02eb00a48b427e7e6edefac562fc42c5e2216c885af0f76bcfaf3da4db54ce9db0e22c498c71e146561c1bbf7ff6246ffc6b0bfcd107830790c07ed9aeda70f2ead9e957992e3ed781e054f336e2ab08110f14ca3be11b92d77b0048c334d97d61c8bc4d82db9c7236973d9ba4da066643440333b5a9e905e799f966c9164907866d9e6af2d7f83466fe8409f24d5c9b3a06614af620087e838039355e65bde8f3ab7a8e06943613e00fd143e21ec2684ac07e1dfdef85da32188a97e7585a667f896941116250f30e31bc0e2b20e536366e225759b12cdd578df18799dfee20b529189ad49789f60ce3649431889d740641df90d1dc372a62b4d77f9f5f9677b4f96770b07107ef37afe4e4dd6af4838ae18b61ce953eedcfc95d081951cbe0b097c6c334489cf46fbba26009d7ebc8ecaa0b155ac60e1f40cc381cd9c85ac7fb25f8458d964bd6e1fc85d6e18bc0fa5491c6995fa7225dcfe43d6a12bde24343d16ce42146cf26a5ec1fd7fae5d829e1f274819a10445ac106f5a517ab89e62455c02469271812be18e972af7d5ba3079dc427f1b7ff7eda2d0cba55f28edef280f5d9243466d1c6f9c4b671777c75c9464e571e7115d97d0d86712781e6346a4472c98da976032ff1073850e7304b6bb4b60b019a7bd870c8d3fb26b212ddfd889b9fae", + "expected_hex": "778f208b90bef0f260a8" + }, + { + "title": "Invalid with null byte at the eighth byte of padding", + "ciphertext_hex": "3d4477615f8b49c9453d31a5d5a228610d6d3e476737c163725106fa386440ff23a9139f57977c09a1e885ddf2f180ddf0f0b0502ef60f0ff53d2ba444f0322820f11acdd70e48543bd8ddd40d00ad9214d03487b265910cf423dea905af908836bf56ef872493b686aa15731714d1f0280e5cddad24ada53374c8aad063184d62bbdc00efd4839b8f06de6c258d26149480b2fad6fcb2fc97cd78fb60305aa254cf1186fa134741a2340dc1d5243423c82c442f3afd915241f317607a2e223664601932e7b967d6793a7fde2819d475e2b8ab0117e3cc4854063a0c1ff1f5cd9c9dc3e6c993d8861c11ee7155dd0ba2d4f47ff0ffc9c7fc8a891284789e5988806fe7b5f5ec5783861fef756ef7339380215de11337ec8f2379b293c3cacf2f81691c1ad75c9223a6c8edfb0451373d0b759d9d701f547b3c46d3fe1f3d24d33447a52bb55b9dd7050c41d11f3108ddccd5738a072905eb48067350e76a65f0d274b0f4bde004cb673b715d4ab01dded4b6b7f69e133135ffcad4b1776e3610830ae55a98d23610256865e305153ad7319ff905c16453297f5ebe64b8857bff69c750d338368f6a55d73ae363a516fa4bf719cd01d46b609c134e3508d9616f495ff2c869db7ad146376b102529c26407d8ffdedbfb005b7b220e0dcb089da3682c9af7c278472cc19b6523b09661fe6f165bd7b7765ca2524eefa3526397b0", + "expected_hex": "364cfecf7e70a0829f28" + }, + { + "title": "Invalid with padding separator missing", + "ciphertext_hex": "44c5b648e960aed2ad38497b6af118577a7978db288c0019cb6f8818578021ca0d782c4e87bd6c3a73ef89e379311f0d449410c336bffdc9d970f995e7b5978910c230b1ef11c06cc5de6ee79ca2f85f6f14e5c42cbb8269d40c032b91783755fbfa7b87f16790bfea91933c67d2499a3d815cb70142285449757e606a438752b803b0928c28dab4fd21125e5b79af04fe912fb444d32039e9e0e10210fbe0174f43e2833ab862e4370b007025a919cf7b9c11241cf95ab10a9baa44a7ce7fa6e802c5b8e5c466dba52704fc2325317526f36d25842e130fcdbbc3c631a1e4c67d23ffcb2218065863c178526616e8429916dff9101baf71857901bdaf305d269c944994f9cf0e02a5499432324b90a62c3c78bd7a7821420a11c43d0a80ee3968ab8a363d6e6476f5424ae98bd59352aa9842e8f42cb0a34da68eac9dd16cf704573007efc4b3fc97161c342c836ff781c331c306f61052d3877ab190e307f4f8d63c3bc8f6ab9a6920f9d1b9be482d3096b0b02447f53b0f974693e2a49b733684d8e33d7dfbb60d3b1aae02c222c395209b1e2647e7fcbf3c44cdee9c73329ce9ed255e011847d6d2e119d252d57c72572b2a309472f059cdae1f24e9cf1ffddebc70b8b252229c7c0adfa763bda2243840bc9a553b6a4ea7737c0a002261b36e198fca4314f659ca1071aceb2668079d663e4ed40e15e10d764aa8cb0c68", + "expected_hex": "750d91268328712552cd" + } + ] + } + ] +} diff --git a/tests/examples/pkcs1v15_ir/k2048.pem b/tests/examples/pkcs1v15_ir/k2048.pem new file mode 100644 index 00000000..e9faf257 --- /dev/null +++ b/tests/examples/pkcs1v15_ir/k2048.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIzIOXFAmNpWyq +I2QPk9yJl8FjcpaPwbDG31ETwclOiyHkitIpfmVBkBG05tj15zsbeLJXQAMh0e9r +YC1OyM6NFByUkF60rTBmOaSSBlNLbn8mB0I+l9/9EzyI1yE5ne+8fpbM3L1/Oq4f +6JJxK/tJKYF9URZmRAofrLeiCPXqFlkQrdij8tSXICNgzLYyAk8NBxacGRjzFveU +sUOu9U7IdSKkwCl4+WiZgL/79knDB+gYGb/4hAljjUi9lL4VK1n/ZJ+gvWKdD/oY +E8Or9LVr08LqVGXf+hRYkpKp2KJK0mvn7gUQdBtjgtQ8g9W/pApGYT0GK+RFUX28 +rwy04adpAgMBAAECggEAFFUBDg8tWHZjpmam/xzNu/Dt2BAGRtAqAjkikImSxK05 +5VZZKXJu9lCMOnEVjvC2/3UdOdB1gLstLwYyEEQtBgP/UNu9ezX+LJuxmkehr4Wk +wkkB4CyotYt5GbIO3zKqz79RrbS8S2G5t+loyqTVcPcO8Y2AYyKIk+R9Q578p5Ml +m88s0Qij2GiM3weOeseZlp8jOdLB9SK5aWhGKakzuq7CaBYl6rhPTlb0RH6diPua +GZz3ECPg4lexREGzPITTvGfKgDHSYSYYEDp6CkCEQmL3XYiQzWFuUfkDVIj9bgmd +6P9tZaT/EYJUgHyfWNL7uouhUdyMaL40nJd6IE4EwQKBgQD49a1rqCiTG+pFm4o/ +bcBB0jSCQJwlcelj8x90hgKiVjcbOIPtRZ7PlwUmRZ7dFuBVIvWkXZR1Gy7C2vJy +x/iBalLADRgIAXFjTaiZ15cyIvUbk3YwVIaWqffYwkpZSXwe/NRVz7l+6G0rbTSX +KzMv2jA/BJmbTra1zAuzPndh3QKBgQDOei47SakLljMKEtxoK9+9+66N1twDthR6 +771XV0Pw9tpNhiNQYbca/ZytLTQCXlashrD3dD6zXhrLyiN4lUJEZbcG7SIXXlcY +yMcLZwPqj2tRD5Rb5I5aNrs8PJFzK1id/AXXLYCQMZRFK9ohNIZH7HKUPxGoRuYv +rr6OtTaw/QKBgHb+FfGK4jnN8d9rRFykvGu5aNeIwhkzpPXc0oADPWcSBizAim3y +BMH70L5GMHRD5t1KZFY3VCnU4DjKJW+vHJvekcaxe3b4GZX5HEjLvrx78ONJTAg1 +nk6M1qWH17ltYiH9fg+1xVdfCC7ld2l5gHGyu7SjIjgVG0cxS7ZUeQMRAoGBAJmI +SLBVSZoQCcvH0pSzax/98gIObnNkBT6U3hoADck0BYf34nJ29ozfYI11O2M3ewO2 +9AhNLAJ8SziWCmIzup7Zc4t28Q6nW+RWB4v3AfZ8xrPz/cGG5kM2x2s3LoCRDsgL +CtzCPQL7muEEhqKCSAdbTqflbd/POILkUVYUcaKRAoGAZDv3RkKffYNmegZTAhNH +77/AXmNR+CGp3rtg4OzN5QBa2ensMeVY9+ksKTKOdFadfO98dMq8KzVe1AGhoJFL +Tjy7BkhOWBlgURae0UyqLvpuoETgVNJhRMwWKcVQEFWKBOEz9Et8JE2sJb+RPFe4 +kO5J9UglnNY0BP72hZ3Pl1o= +-----END PRIVATE KEY----- diff --git a/tests/examples/pkcs1v15_ir/k2049.pem b/tests/examples/pkcs1v15_ir/k2049.pem new file mode 100644 index 00000000..c5b67e47 --- /dev/null +++ b/tests/examples/pkcs1v15_ir/k2049.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQFV+IlVahd18cen +eGpQsYvCjJ6Ybt5WZ8qzm4QSTpDrp1wdsIOsPkQ7upTcI1YPdeOoFpOipDvcdCbY +xOr+aMhd4P51f25Ju57UR+YCQwgA27BM6yLn+lehjTOPtmAmzbRn5wzAQOfTZ+9A +PHvx499iRlAJRjHyHq/S+1vJFf8EN5rNERL3MsC0ZgfBeNOKIPUu2lCfL5wEBdUQ +aegMz5QVVNBHBGdQXDz1QeoIl9/J9ADOyymP/HUzctn2kzrxdMxA7ZbUZwMXM7l/ +jN3T+SvDoD6oV2xBfyQAe15PdQEQW1RN6frc3/rfmN+0uwW4GZ8/haz9kfepoJS5 +o4P1BJCXAgMBAAECggEBARnCs/UKetYVJnnX/1EJWKwtjKbwAoWS8zLVWhZzYXio +5n8X5wXOMA4+h1RyUQBgE/l00KPbSe80TKWiajTARQcE0OQi4M4jppQlwV/vtvJu +EG7v9kzIuddELk2k6MhQCOrrNlhZoilPo5N7wmvlYzLn2B4sFg72NcxSiqe+VeYz +pyPbweFrop5SsprvL55WVP3AZmuw/CVKy+gOY4dPD18CB4Ljydz8JSDQycSntjTk +UD+7ST4ar+6z+IvXoTOYcl2ub+OZ53XNXUzwn8g4NHxMmNqxpIg8zmIFE2Fa+qEK +YzaObXt530FmqxYnOe9RWkQC7h4GAcWlW8cd8OMO34ECgYEBiPaTYPAeGNmi3ilS +U9JSwx5Eds6l/3v4QT33/eNWUjzcl2gF+E/A3ex3DfBs7QZcgRNIdUs0avFpdWh3 +/Ts9VoaCyHh9CzFO9qxn1l6BMzmLYqCDwPh2XFrUDVqB+bvc4lJ+1+lQCMsQKctM +q9H56b7fwobJZVIlXafqsZIXjvcCgYEA3sfPEdreg6TEPS+AGX8h/V1G/Ve0MfRP +6Bod439qCR/8BGTtlx3IUIg1rebMX1ZvOWVhOos2eYyS5uI/Uu+QfpVn40G+vFM3 +GJYl+76rHzt7P5L/smgebvWnhKjC1498LYmqqiTSztvQZoHP5lw2x7+jxboTUWIi +LvXC6RTJg2ECgYASCT86c8rt2Q9gowTkVAL4casyyMlVsJr0Y6O+Q3Dy1VhKmrur +af2wMepE+YQGXQRh6ECrIYiGYA43FVRsiwuFrSbTjLQwj1LQf5lEfZHwh/Od00A4 +2y6TjpetBTpx++1ndeHchxjlTmyvfmVGfZy63cfnZchYniyY39wlyk7KgQKBgQCM +zmE0ec+WCPf3bCRc+Ru0ldYeneZIhJBUtN0bQxbz+YFCDcCVeL95Fv5Gkc+ummTm +NAuGAyNFI/Jdd7ZqZvw+5ZOp8Y3qXfY+1fff650gummlvvVZ/7DslNtyX2/26ruj +1JVHwMp08D4B7B5JDROaoKeUe41mLM5KPA8bXoYXQQKBgQD5lZs0xLyozkiIeBsx +sem12K310NPj7VReg2fT+FRbpkQyuIcwNe+IHCvN4A0YCfksQNh4N7XE+az0iza4 +3FOllWGkVlI0AtHo+jrzAOVMkbY+bO4G/m3mZvOSlYKgPh9FTneJ+weBpNb7tSbv +iBYh/R6s0hRm5M3Ziu0Q9OdveQ== +-----END PRIVATE KEY----- diff --git a/tests/examples/pkcs1v15_ir/k3072.pem b/tests/examples/pkcs1v15_ir/k3072.pem new file mode 100644 index 00000000..f635858a --- /dev/null +++ b/tests/examples/pkcs1v15_ir/k3072.pem @@ -0,0 +1,40 @@ +-----BEGIN PRIVATE KEY----- +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 +RiYH7HQtpEgHd3Bk2J0rdOQr +-----END PRIVATE KEY----- diff --git a/tests/examples/pkcs1v15_ir/k4096.pem b/tests/examples/pkcs1v15_ir/k4096.pem new file mode 100644 index 00000000..fd2b2499 --- /dev/null +++ b/tests/examples/pkcs1v15_ir/k4096.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +q4gl5hM8H5F0iWcKq25nZYHamz7f +-----END PRIVATE KEY----- diff --git a/tests/pkcs1v15_implicit_rejection.rs b/tests/pkcs1v15_implicit_rejection.rs new file mode 100644 index 00000000..f8dcbad0 --- /dev/null +++ b/tests/pkcs1v15_implicit_rejection.rs @@ -0,0 +1,101 @@ +#![cfg(feature = "encoding")] + +#[path = "support/pkcs1v15_ir.rs"] +mod support; + +use rand::rngs::ChaCha8Rng; +use rand_core::SeedableRng; +use rsa::{ + pkcs1v15::DecryptingKey, + traits::{Decryptor, PublicKeyParts, RandomizedDecryptor}, + Error, Pkcs1v15Encrypt, +}; + +#[test] +fn wrong_length_ciphertexts_still_error() { + let corpus = support::load_corpus(); + let family = corpus.family("k2048"); + let private_key = support::load_private_key("k2048"); + let mut ciphertext = family.case("Valid").ciphertext(); + ciphertext.pop(); + + assert_eq!( + private_key.decrypt(Pkcs1v15Encrypt, &ciphertext), + Err(Error::Decryption) + ); +} + +#[test] +fn out_of_range_ciphertexts_still_error() { + let private_key = support::load_private_key("k2048"); + let modulus_bytes = private_key.n_bytes(); + let mut ciphertext = vec![0u8; private_key.size()]; + ciphertext[private_key.size() - modulus_bytes.len()..].copy_from_slice(&modulus_bytes); + + assert_eq!( + private_key.decrypt(Pkcs1v15Encrypt, &ciphertext), + Err(Error::Decryption) + ); +} + +#[test] +fn implicit_rejection_is_deterministic_with_and_without_blinding() { + let corpus = support::load_corpus(); + let family = corpus.family("k2048"); + let private_key = support::load_private_key("k2048"); + + for case in family.invalid_cases() { + let expected = private_key + .decrypt(Pkcs1v15Encrypt, &case.ciphertext()) + .unwrap(); + let mut rng = ChaCha8Rng::from_seed([7; 32]); + let blinded = private_key + .decrypt_blinded(&mut rng, Pkcs1v15Encrypt, &case.ciphertext()) + .unwrap(); + + assert_eq!(expected, case.expected(), "{}", case.title); + assert_eq!(blinded, case.expected(), "{}", case.title); + } +} + +#[test] +fn different_invalid_ciphertexts_produce_distinct_rejection_symbols() { + let corpus = support::load_corpus(); + let family = corpus.family("k2048"); + let private_key = support::load_private_key("k2048"); + let first = family.case("Invalid first byte of padding"); + let second = family.case("Invalid second byte of padding"); + + let first_output = private_key + .decrypt(Pkcs1v15Encrypt, &first.ciphertext()) + .unwrap(); + let second_output = private_key + .decrypt(Pkcs1v15Encrypt, &second.ciphertext()) + .unwrap(); + + assert_ne!(first_output, second_output); +} + +#[test] +fn decrypting_key_matches_shared_decrypt_path_for_invalid_padding() { + let corpus = support::load_corpus(); + let family = corpus.family("k2048"); + let private_key = support::load_private_key("k2048"); + let decrypting_key = DecryptingKey::new(private_key.clone()); + let case = family.case("Invalid with padding separator missing"); + let expected = private_key + .decrypt(Pkcs1v15Encrypt, &case.ciphertext()) + .unwrap(); + let mut rng = ChaCha8Rng::from_seed([9; 32]); + + assert_eq!( + decrypting_key.decrypt(&case.ciphertext()).unwrap(), + expected + ); + assert_eq!( + decrypting_key + .decrypt_with_rng(&mut rng, &case.ciphertext()) + .unwrap(), + expected + ); +} diff --git a/tests/pkcs1v15_implicit_rejection_vectors.rs b/tests/pkcs1v15_implicit_rejection_vectors.rs new file mode 100644 index 00000000..595171a1 --- /dev/null +++ b/tests/pkcs1v15_implicit_rejection_vectors.rs @@ -0,0 +1,33 @@ +#![cfg(feature = "encoding")] + +#[path = "support/pkcs1v15_ir.rs"] +mod support; + +use rsa::{Pkcs1v15Encrypt, RsaPrivateKey}; + +#[test] +fn appendix_b_vectors_match_draft_08() { + let corpus = support::load_corpus(); + assert_eq!(corpus.families.len(), 4); + + for family in &corpus.families { + assert_eq!(family.cases.len(), 12, "{}", family.section); + + let private_key: RsaPrivateKey = support::load_private_key(&family.id); + + for case in &family.cases { + let decrypted = private_key + .decrypt(Pkcs1v15Encrypt, &case.ciphertext()) + .unwrap_or_else(|e| { + panic!("{} {}: decrypt failed: {e}", family.section, case.title) + }); + assert_eq!( + decrypted, + case.expected(), + "{} {}", + family.section, + case.title + ); + } + } +} diff --git a/tests/support/pkcs1v15_ir.rs b/tests/support/pkcs1v15_ir.rs new file mode 100644 index 00000000..9b333d4d --- /dev/null +++ b/tests/support/pkcs1v15_ir.rs @@ -0,0 +1,83 @@ +#![allow(dead_code)] + +use pkcs8::DecodePrivateKey; +use rsa::RsaPrivateKey; +use serde::Deserialize; + +const CASES_JSON: &str = include_str!("../examples/pkcs1v15_ir/cases.json"); +const K2048_PEM: &str = include_str!("../examples/pkcs1v15_ir/k2048.pem"); +const K2049_PEM: &str = include_str!("../examples/pkcs1v15_ir/k2049.pem"); +const K3072_PEM: &str = include_str!("../examples/pkcs1v15_ir/k3072.pem"); +const K4096_PEM: &str = include_str!("../examples/pkcs1v15_ir/k4096.pem"); + +#[derive(Debug, Deserialize)] +pub(crate) struct Corpus { + pub(crate) families: Vec, +} + +#[derive(Debug, Deserialize)] +pub(crate) struct Family { + pub(crate) id: String, + pub(crate) section: String, + pub(crate) cases: Vec, +} + +#[derive(Debug, Deserialize)] +pub(crate) struct Case { + pub(crate) title: String, + ciphertext_hex: String, + expected_hex: String, +} + +impl Corpus { + pub(crate) fn family(&self, id: &str) -> &Family { + self.families + .iter() + .find(|family| family.id == id) + .unwrap_or_else(|| panic!("missing family fixture: {id}")) + } +} + +impl Family { + pub(crate) fn case(&self, title: &str) -> &Case { + self.cases + .iter() + .find(|case| case.title == title) + .unwrap_or_else(|| panic!("missing case fixture: {} / {title}", self.id)) + } + + pub(crate) fn invalid_cases(&self) -> impl Iterator { + self.cases + .iter() + .filter(|case| case.title.starts_with("Invalid")) + } +} + +impl Case { + pub(crate) fn ciphertext(&self) -> Vec { + hex::decode(&self.ciphertext_hex) + .unwrap_or_else(|e| panic!("invalid ciphertext_hex for case '{}': {e}", self.title)) + } + + pub(crate) fn expected(&self) -> Vec { + hex::decode(&self.expected_hex) + .unwrap_or_else(|e| panic!("invalid expected_hex for case '{}': {e}", self.title)) + } +} + +pub(crate) fn load_corpus() -> Corpus { + serde_json::from_str(CASES_JSON).expect("failed to parse tests/examples/pkcs1v15_ir/cases.json") +} + +pub(crate) fn load_private_key(id: &str) -> RsaPrivateKey { + let pem = match id { + "k2048" => K2048_PEM, + "k2049" => K2049_PEM, + "k3072" => K3072_PEM, + "k4096" => K4096_PEM, + _ => panic!("missing PEM fixture: {id}"), + }; + + RsaPrivateKey::from_pkcs8_pem(pem) + .unwrap_or_else(|e| panic!("failed to parse PKCS#8 fixture '{id}': {e}")) +}