1use js::context::JSContext;
6use pkcs8::rand_core::OsRng;
7use rsa::Oaep;
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 ALG_SHA1, ALG_SHA256, ALG_SHA384, ALG_SHA512, ExportedKey, KeyAlgorithmAndDerivatives,
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
42 .label
43 .as_ref()
44 .map(|label| String::from_utf8_lossy(label))
45 .unwrap_or_default();
46
47 let Handle::RsaPublicKey(public_key) = key.handle() else {
55 return Err(Error::Operation(Some(
56 "[[handle]] internal slot of key is not an RSA public key".to_string(),
57 )));
58 };
59 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
60 return Err(Error::Operation(Some(
61 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
62 )));
63 };
64 let padding = match algorithm.hash.name() {
65 ALG_SHA1 => Oaep::new_with_label::<Sha1, _>(label),
66 ALG_SHA256 => Oaep::new_with_label::<Sha256, _>(label),
67 ALG_SHA384 => Oaep::new_with_label::<Sha384, _>(label),
68 ALG_SHA512 => Oaep::new_with_label::<Sha512, _>(label),
69 _ => {
70 return Err(Error::Operation(Some(format!(
71 "Unsupported \"{}\" hash for RSASSA-PKCS1-v1_5",
72 algorithm.hash.name()
73 ))));
74 },
75 };
76 let ciphertext = public_key
77 .encrypt(&mut OsRng, padding, plaintext)
78 .map_err(|_| Error::Operation(Some("RSA-OAEP failed to encrypt plaintext".to_string())))?;
79
80 Ok(ciphertext)
82}
83
84pub(crate) fn decrypt(
86 normalized_algorithm: &SubtleRsaOaepParams,
87 key: &CryptoKey,
88 ciphertext: &[u8],
89) -> Result<Vec<u8>, Error> {
90 if key.Type() != KeyType::Private {
93 return Err(Error::InvalidAccess(Some(
94 "[[type]] internal slot of key is not \"private\"".to_string(),
95 )));
96 }
97
98 let label = normalized_algorithm
101 .label
102 .as_ref()
103 .map(|label| String::from_utf8_lossy(label))
104 .unwrap_or_default();
105
106 let Handle::RsaPrivateKey(private_key) = key.handle() else {
114 return Err(Error::Operation(Some(
115 "[[handle]] internal slot of key is not an RSA private key".to_string(),
116 )));
117 };
118 let KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) = key.algorithm() else {
119 return Err(Error::Operation(Some(
120 "[[algorithm]] internal slot of key is not an RsaHashedKeyAlgorithm".to_string(),
121 )));
122 };
123 let padding = match algorithm.hash.name() {
124 ALG_SHA1 => Oaep::new_with_label::<Sha1, _>(label),
125 ALG_SHA256 => Oaep::new_with_label::<Sha256, _>(label),
126 ALG_SHA384 => Oaep::new_with_label::<Sha384, _>(label),
127 ALG_SHA512 => Oaep::new_with_label::<Sha512, _>(label),
128 _ => {
129 return Err(Error::Operation(Some(format!(
130 "Unsupported \"{}\" hash for RSA-OAEP",
131 algorithm.hash.name()
132 ))));
133 },
134 };
135 let plaintext = private_key
136 .decrypt(padding, ciphertext)
137 .map_err(|_| Error::Operation(Some("RSA-OAEP failed to decrypt ciphertext".to_string())))?;
138
139 Ok(plaintext)
141}
142
143pub(crate) fn generate_key(
145 cx: &mut JSContext,
146 global: &GlobalScope,
147 normalized_algorithm: &SubtleRsaHashedKeyGenParams,
148 extractable: bool,
149 usages: Vec<KeyUsage>,
150) -> Result<CryptoKeyPair, Error> {
151 rsa_common::generate_key(
152 RsaAlgorithm::RsaOaep,
153 cx,
154 global,
155 normalized_algorithm,
156 extractable,
157 usages,
158 )
159}
160
161pub(crate) fn import_key(
163 cx: &mut JSContext,
164 global: &GlobalScope,
165 normalized_algorithm: &SubtleRsaHashedImportParams,
166 format: KeyFormat,
167 key_data: &[u8],
168 extractable: bool,
169 usages: Vec<KeyUsage>,
170) -> Result<DomRoot<CryptoKey>, Error> {
171 rsa_common::import_key(
172 RsaAlgorithm::RsaOaep,
173 cx,
174 global,
175 normalized_algorithm,
176 format,
177 key_data,
178 extractable,
179 usages,
180 )
181}
182
183pub(crate) fn export_key(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
185 rsa_common::export_key(RsaAlgorithm::RsaOaep, format, key)
186}