script/dom/webcrypto/subtlecrypto/
rsa_oaep_operation.rs1use js::context::JSContext;
6use rsa::oaep::{DecryptingKey, EncryptingKey};
7use rsa::traits::{Decryptor, RandomizedEncryptor};
8use sha1::Sha1;
9use sha2::{Sha256, Sha384, Sha512};
10
11use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
12 CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
13};
14use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::KeyFormat;
15use crate::dom::bindings::error::Error;
16use crate::dom::bindings::root::DomRoot;
17use crate::dom::cryptokey::{CryptoKey, Handle};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::rsa_common::{self, RsaAlgorithm};
20use crate::dom::subtlecrypto::{
21 CryptoAlgorithm, ExportedKey, KeyAlgorithmAndDerivatives, NormalizedAlgorithm,
22 SubtleRsaHashedImportParams, SubtleRsaHashedKeyGenParams, SubtleRsaOaepParams,
23};
24
25pub(crate) fn encrypt(
27 normalized_algorithm: &SubtleRsaOaepParams,
28 key: &CryptoKey,
29 plaintext: &[u8],
30) -> Result<Vec<u8>, Error> {
31 if key.Type() != KeyType::Public {
34 return Err(Error::InvalidAccess(Some(
35 "[[type]] internal slot of key is not \"public\"".to_string(),
36 )));
37 }
38
39 let label = normalized_algorithm.label.as_deref().unwrap_or_default();
42
43 let Handle::RsaPublicKey(public_key) = key.handle() else {
51 return Err(Error::Operation(Some(
52 "[[handle]] internal slot of key is not an RSA public key".to_string(),
53 )));
54 };
55 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
56 return Err(Error::Operation(Some(
57 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
58 )));
59 };
60 let mut rng = rand::rng();
61 let ciphertext = match algorithm.hash.name() {
62 CryptoAlgorithm::Sha1 => {
63 let encryption_key = EncryptingKey::<Sha1>::new_with_label(public_key.clone(), label);
64 encryption_key.encrypt_with_rng(&mut rng, plaintext)
65 },
66 CryptoAlgorithm::Sha256 => {
67 let encryption_key = EncryptingKey::<Sha256>::new_with_label(public_key.clone(), label);
68 encryption_key.encrypt_with_rng(&mut rng, plaintext)
69 },
70 CryptoAlgorithm::Sha384 => {
71 let encryption_key = EncryptingKey::<Sha384>::new_with_label(public_key.clone(), label);
72 encryption_key.encrypt_with_rng(&mut rng, plaintext)
73 },
74 CryptoAlgorithm::Sha512 => {
75 let encryption_key = EncryptingKey::<Sha512>::new_with_label(public_key.clone(), label);
76 encryption_key.encrypt_with_rng(&mut rng, plaintext)
77 },
78 algorithm_hash_name => {
79 return Err(Error::Operation(Some(format!(
80 "Unsupported hash for RSASSA-PKCS1-v1_5: {}",
81 algorithm_hash_name.as_str()
82 ))));
83 },
84 }
85 .map_err(|_| Error::Operation(Some("RSA-OAEP failed to encrypt plaintext".into())))?;
86
87 Ok(ciphertext)
89}
90
91pub(crate) fn decrypt(
93 normalized_algorithm: &SubtleRsaOaepParams,
94 key: &CryptoKey,
95 ciphertext: &[u8],
96) -> Result<Vec<u8>, Error> {
97 if key.Type() != KeyType::Private {
100 return Err(Error::InvalidAccess(Some(
101 "[[type]] internal slot of key is not \"private\"".to_string(),
102 )));
103 }
104
105 let label = normalized_algorithm.label.as_deref().unwrap_or_default();
108
109 let Handle::RsaPrivateKey(private_key) = key.handle() else {
117 return Err(Error::Operation(Some(
118 "[[handle]] internal slot of key is not an RSA private key".to_string(),
119 )));
120 };
121 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
122 return Err(Error::Operation(Some(
123 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
124 )));
125 };
126 let plaintext = match algorithm.hash.name() {
127 CryptoAlgorithm::Sha1 => {
128 let decrypting_key = DecryptingKey::<Sha1>::new_with_label(private_key.clone(), label);
129 decrypting_key.decrypt(ciphertext)
130 },
131 CryptoAlgorithm::Sha256 => {
132 let decrypting_key =
133 DecryptingKey::<Sha256>::new_with_label(private_key.clone(), label);
134 decrypting_key.decrypt(ciphertext)
135 },
136 CryptoAlgorithm::Sha384 => {
137 let decrypting_key =
138 DecryptingKey::<Sha384>::new_with_label(private_key.clone(), label);
139 decrypting_key.decrypt(ciphertext)
140 },
141 CryptoAlgorithm::Sha512 => {
142 let decrypting_key =
143 DecryptingKey::<Sha512>::new_with_label(private_key.clone(), label);
144 decrypting_key.decrypt(ciphertext)
145 },
146 algorithm_hash_name => {
147 return Err(Error::Operation(Some(format!(
148 "Unsupported hash for RSASSA-PKCS1-v1_5: {}",
149 algorithm_hash_name.as_str()
150 ))));
151 },
152 }
153 .map_err(|_| Error::Operation(Some("RSA-OAEP failed to decrypt ciphertext".into())))?;
154
155 Ok(plaintext)
157}
158
159pub(crate) fn generate_key(
161 cx: &mut JSContext,
162 global: &GlobalScope,
163 normalized_algorithm: &SubtleRsaHashedKeyGenParams,
164 extractable: bool,
165 usages: Vec<KeyUsage>,
166) -> Result<CryptoKeyPair, Error> {
167 rsa_common::generate_key(
168 RsaAlgorithm::RsaOaep,
169 cx,
170 global,
171 normalized_algorithm,
172 extractable,
173 usages,
174 )
175}
176
177pub(crate) fn import_key(
179 cx: &mut JSContext,
180 global: &GlobalScope,
181 normalized_algorithm: &SubtleRsaHashedImportParams,
182 format: KeyFormat,
183 key_data: &[u8],
184 extractable: bool,
185 usages: Vec<KeyUsage>,
186) -> Result<DomRoot<CryptoKey>, Error> {
187 rsa_common::import_key(
188 RsaAlgorithm::RsaOaep,
189 cx,
190 global,
191 normalized_algorithm,
192 format,
193 key_data,
194 extractable,
195 usages,
196 )
197}
198
199pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
201 rsa_common::export_key(RsaAlgorithm::RsaOaep, format, key)
202}
203
204pub(crate) fn get_public_key(
207 cx: &mut JSContext,
208 global: &GlobalScope,
209 key: &CryptoKey,
210 algorithm: &KeyAlgorithmAndDerivatives,
211 usages: Vec<KeyUsage>,
212) -> Result<DomRoot<CryptoKey>, Error> {
213 rsa_common::get_public_key(RsaAlgorithm::RsaOaep, cx, global, key, algorithm, usages)
214}