rsa/padding.rs
1//! Supported padding schemes.
2
3use alloc::boxed::Box;
4use alloc::string::{String, ToString};
5use core::fmt;
6
7use digest::{Digest, DynDigest};
8use pkcs8::AssociatedOid;
9
10use crate::pkcs1v15;
11
12/// Available padding schemes.
13pub enum PaddingScheme {
14 /// Encryption and Decryption using PKCS1v15 padding.
15 PKCS1v15Encrypt,
16
17 /// Sign and Verify using PKCS1v15 padding.
18 PKCS1v15Sign {
19 /// Length of hash to use.
20 hash_len: Option<usize>,
21
22 /// Prefix.
23 prefix: Box<[u8]>,
24 },
25
26 /// Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
27 ///
28 /// - `digest` is used to hash the label. The maximum possible plaintext length is `m = k - 2 * h_len - 2`,
29 /// where `k` is the size of the RSA modulus.
30 /// - `mgf_digest` specifies the hash function that is used in the [MGF1](https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.2).
31 /// - `label` is optional data that can be associated with the message.
32 ///
33 /// The two hash functions can, but don't need to be the same.
34 ///
35 /// A prominent example is the [`AndroidKeyStore`](https://developer.android.com/guide/topics/security/cryptography#oaep-mgf1-digest).
36 /// It uses SHA-1 for `mgf_digest` and a user-chosen SHA flavour for `digest`.
37 OAEP {
38 /// Digest type to use.
39 digest: Box<dyn DynDigest + Send + Sync>,
40
41 /// Digest to use for Mask Generation Function (MGF).
42 mgf_digest: Box<dyn DynDigest + Send + Sync>,
43
44 /// Optional label.
45 label: Option<String>,
46 },
47
48 /// Sign and Verify using PSS padding.
49 PSS {
50 /// Digest type to use.
51 digest: Box<dyn DynDigest + Send + Sync>,
52
53 /// Salt length.
54 salt_len: Option<usize>,
55 },
56}
57
58impl fmt::Debug for PaddingScheme {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 PaddingScheme::PKCS1v15Encrypt => write!(f, "PaddingScheme::PKCS1v15Encrypt"),
62 PaddingScheme::PKCS1v15Sign { prefix, .. } => {
63 write!(f, "PaddingScheme::PKCS1v15Sign({:?})", prefix)
64 }
65 PaddingScheme::OAEP { ref label, .. } => {
66 // TODO: How to print the digest name?
67 write!(f, "PaddingScheme::OAEP({:?})", label)
68 }
69 PaddingScheme::PSS { ref salt_len, .. } => {
70 // TODO: How to print the digest name?
71 write!(f, "PaddingScheme::PSS(salt_len: {:?})", salt_len)
72 }
73 }
74 }
75}
76
77impl PaddingScheme {
78 /// Create new PKCS#1 v1.5 encryption padding.
79 pub fn new_pkcs1v15_encrypt() -> Self {
80 PaddingScheme::PKCS1v15Encrypt
81 }
82
83 /// Create new PKCS#1 v1.5 padding for computing a raw signature.
84 ///
85 /// This sets `hash_len` to `None` and uses an empty `prefix`.
86 pub fn new_pkcs1v15_sign_raw() -> Self {
87 PaddingScheme::PKCS1v15Sign {
88 hash_len: None,
89 prefix: Box::new([]),
90 }
91 }
92
93 /// Create new PKCS#1 v1.5 padding for the given digest.
94 ///
95 /// The digest must have an [`AssociatedOid`]. Make sure to enable the `oid`
96 /// feature of the relevant digest crate.
97 pub fn new_pkcs1v15_sign<D>() -> Self
98 where
99 D: Digest + AssociatedOid,
100 {
101 PaddingScheme::PKCS1v15Sign {
102 hash_len: Some(<D as Digest>::output_size()),
103 prefix: pkcs1v15::generate_prefix::<D>().into_boxed_slice(),
104 }
105 }
106
107 /// Create a new OAEP `PaddingScheme`, using `T` as the hash function for the default (empty) label, and `U` as the hash function for MGF1.
108 /// If a label is needed use `PaddingScheme::new_oaep_with_label` or `PaddingScheme::new_oaep_with_mgf_hash_with_label`.
109 ///
110 /// # Example
111 /// ```
112 /// use sha1::Sha1;
113 /// use sha2::Sha256;
114 /// use rsa::{BigUint, RsaPublicKey, PaddingScheme, PublicKey};
115 /// use base64ct::{Base64, Encoding};
116 ///
117 /// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
118 /// let e = Base64::decode_vec("AQAB").unwrap();
119 ///
120 /// let mut rng = rand::thread_rng();
121 /// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
122 /// let padding = PaddingScheme::new_oaep_with_mgf_hash::<Sha256, Sha1>();
123 /// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
124 /// ```
125 pub fn new_oaep_with_mgf_hash<
126 T: 'static + Digest + DynDigest + Send + Sync,
127 U: 'static + Digest + DynDigest + Send + Sync,
128 >() -> Self {
129 PaddingScheme::OAEP {
130 digest: Box::new(T::new()),
131 mgf_digest: Box::new(U::new()),
132 label: None,
133 }
134 }
135
136 /// Create a new OAEP `PaddingScheme`, using `T` as the hash function for both the default (empty) label and for MGF1.
137 ///
138 /// # Example
139 /// ```
140 /// use sha1::Sha1;
141 /// use sha2::Sha256;
142 /// use rsa::{BigUint, RsaPublicKey, PaddingScheme, PublicKey};
143 /// use base64ct::{Base64, Encoding};
144 ///
145 /// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
146 /// let e = Base64::decode_vec("AQAB").unwrap();
147 ///
148 /// let mut rng = rand::thread_rng();
149 /// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
150 /// let padding = PaddingScheme::new_oaep::<Sha256>();
151 /// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
152 /// ```
153 pub fn new_oaep<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
154 PaddingScheme::OAEP {
155 digest: Box::new(T::new()),
156 mgf_digest: Box::new(T::new()),
157 label: None,
158 }
159 }
160
161 /// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for the label, and `U` as the hash function for MGF1.
162 pub fn new_oaep_with_mgf_hash_with_label<
163 T: 'static + Digest + DynDigest + Send + Sync,
164 U: 'static + Digest + DynDigest + Send + Sync,
165 S: AsRef<str>,
166 >(
167 label: S,
168 ) -> Self {
169 PaddingScheme::OAEP {
170 digest: Box::new(T::new()),
171 mgf_digest: Box::new(U::new()),
172 label: Some(label.as_ref().to_string()),
173 }
174 }
175
176 /// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for both the label and for MGF1.
177 pub fn new_oaep_with_label<T: 'static + Digest + DynDigest + Send + Sync, S: AsRef<str>>(
178 label: S,
179 ) -> Self {
180 PaddingScheme::OAEP {
181 digest: Box::new(T::new()),
182 mgf_digest: Box::new(T::new()),
183 label: Some(label.as_ref().to_string()),
184 }
185 }
186
187 /// New PSS padding for the given digest.
188 pub fn new_pss<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
189 PaddingScheme::PSS {
190 digest: Box::new(T::new()),
191 salt_len: None,
192 }
193 }
194
195 /// New PSS padding for the given digest with a salt value of the given length.
196 pub fn new_pss_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(len: usize) -> Self {
197 PaddingScheme::PSS {
198 digest: Box::new(T::new()),
199 salt_len: Some(len),
200 }
201 }
202}