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