1use crate::{bb, bits, digest, error, rand};
16
17mod pkcs1;
18mod pss;
19
20pub use self::{
21 pkcs1::{RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512},
22 pss::{RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512},
23};
24pub(super) use pkcs1::RSA_PKCS1_SHA1_FOR_LEGACY_USE_ONLY;
25
26pub trait Padding: 'static + Sync + crate::sealed::Sealed + core::fmt::Debug {
28 fn digest_alg(&self) -> &'static digest::Algorithm;
31}
32
33pub(super) fn encode(
34 encoding: &dyn RsaEncoding,
35 m_hash: digest::Digest,
36 m_out: &mut [u8],
37 mod_bits: bits::BitLength,
38 rng: &dyn rand::SecureRandom,
39) -> Result<(), error::Unspecified> {
40 #[allow(deprecated)]
41 encoding.encode(m_hash, m_out, mod_bits, rng)
42}
43
44#[cfg(feature = "alloc")]
48pub trait RsaEncoding: Padding {
49 #[deprecated(note = "internal API that will be removed")]
50 #[doc(hidden)]
51 fn encode(
52 &self,
53 m_hash: digest::Digest,
54 m_out: &mut [u8],
55 mod_bits: bits::BitLength,
56 rng: &dyn rand::SecureRandom,
57 ) -> Result<(), error::Unspecified>;
58}
59
60pub trait Verification: Padding {
65 fn verify(
66 &self,
67 m_hash: digest::Digest,
68 m: &mut untrusted::Reader,
69 mod_bits: bits::BitLength,
70 ) -> Result<(), error::Unspecified>;
71}
72
73fn mgf1(digest_alg: &'static digest::Algorithm, seed: &[u8], out: &mut [u8]) {
76 let digest_len = digest_alg.output_len();
77
78 for (i, out) in out.chunks_mut(digest_len).enumerate() {
80 let mut ctx = digest::Context::new(digest_alg);
81 ctx.update(seed);
82 ctx.update(&u32::to_be_bytes(i.try_into().unwrap()));
85 let digest = ctx.finish();
86
87 bb::xor_assign_at_start(out, digest.as_ref());
90 }
91}
92
93#[cfg(test)]
94mod test {
95 use super::*;
96 use crate::testutil as test;
97 use crate::{digest, error};
98 use alloc::vec;
99
100 #[test]
101 fn test_pss_padding_verify() {
102 test::run(
103 test_vector_file!("rsa_pss_padding_tests.txt"),
104 |section, test_case| {
105 assert_eq!(section, "");
106
107 let digest_name = test_case.consume_string("Digest");
108 let alg = match digest_name.as_ref() {
109 "SHA256" => &RSA_PSS_SHA256,
110 "SHA384" => &RSA_PSS_SHA384,
111 "SHA512" => &RSA_PSS_SHA512,
112 _ => panic!("Unsupported digest: {}", digest_name),
113 };
114
115 let msg = test_case.consume_bytes("Msg");
116 let msg = untrusted::Input::from(&msg);
117 let m_hash = digest::digest(alg.digest_alg(), msg.as_slice_less_safe());
118
119 let encoded = test_case.consume_bytes("EM");
120 let encoded = untrusted::Input::from(&encoded);
121
122 let _ = test_case.consume_bytes("Salt");
124
125 let bit_len = test_case.consume_usize_bits("Len");
126 let is_valid = test_case.consume_string("Result") == "P";
127
128 let actual_result =
129 encoded.read_all(error::Unspecified, |m| alg.verify(m_hash, m, bit_len));
130 assert_eq!(actual_result.is_ok(), is_valid);
131
132 Ok(())
133 },
134 );
135 }
136
137 #[cfg(feature = "alloc")]
139 #[test]
140 fn test_pss_padding_encode() {
141 test::run(
142 test_vector_file!("rsa_pss_padding_tests.txt"),
143 |section, test_case| {
144 assert_eq!(section, "");
145
146 let digest_name = test_case.consume_string("Digest");
147 let alg = match digest_name.as_ref() {
148 "SHA256" => &RSA_PSS_SHA256,
149 "SHA384" => &RSA_PSS_SHA384,
150 "SHA512" => &RSA_PSS_SHA512,
151 _ => panic!("Unsupported digest: {}", digest_name),
152 };
153
154 let msg = test_case.consume_bytes("Msg");
155 let salt = test_case.consume_bytes("Salt");
156 let encoded = test_case.consume_bytes("EM");
157 let bit_len = test_case.consume_usize_bits("Len");
158 let expected_result = test_case.consume_string("Result");
159
160 if expected_result != "P" {
162 return Ok(());
163 }
164
165 let rng = test::rand::FixedSliceRandom { bytes: &salt };
166
167 let mut m_out = vec![0u8; bit_len.as_usize_bytes_rounded_up()];
168 let digest = digest::digest(alg.digest_alg(), &msg);
169 #[allow(deprecated)]
170 alg.encode(digest, &mut m_out, bit_len, &rng).unwrap();
171 assert_eq!(m_out, encoded);
172
173 Ok(())
174 },
175 );
176 }
177}