1use super::encrypt_digest_into;
2#[cfg(not(feature = "alloc"))]
3use super::Label;
4use crate::traits::{
5 modular::{CtModulusParams, ModulusParams},
6 PublicKeyParts, UnsignedModularInt,
7};
8use crate::{traits::RandomizedEncryptor, GenericRsaPublicKey, Result};
9#[cfg(feature = "alloc")]
10use alloc::{boxed::Box, vec::Vec};
11use core::marker::PhantomData;
12#[cfg(feature = "alloc")]
13use crypto_bigint::{modular::BoxedMontyParams, BoxedUint};
14use digest::{Digest, FixedOutputReset};
15use rand_core::{CryptoRng, TryCryptoRng};
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19#[derive(Debug, Clone)]
23#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
24#[cfg_attr(
25 feature = "serde",
26 serde(bound(
27 serialize = "GenericRsaPublicKey<T, M>: Serialize",
28 deserialize = "GenericRsaPublicKey<T, M>: serde::de::DeserializeOwned"
29 ))
30)]
31pub struct GenericEncryptingKey<D, MGD, T, M>
32where
33 T: UnsignedModularInt,
34 M: ModulusParams<Modulus = T>,
35{
36 inner: GenericRsaPublicKey<T, M>,
37 #[cfg(feature = "alloc")]
38 label: Option<Box<[u8]>>,
39 #[cfg(not(feature = "alloc"))]
40 label: Option<Label>,
41 phantom: PhantomData<D>,
42 mg_phantom: PhantomData<MGD>,
43}
44
45#[cfg(feature = "alloc")]
47pub type EncryptingKey<D, MGD = D> = GenericEncryptingKey<D, MGD, BoxedUint, BoxedMontyParams>;
48
49impl<D, MGD, T, M> GenericEncryptingKey<D, MGD, T, M>
50where
51 T: UnsignedModularInt,
52 M: ModulusParams<Modulus = T>,
53{
54 pub fn new(key: GenericRsaPublicKey<T, M>) -> Self {
56 Self {
57 inner: key,
58 label: None,
59 phantom: Default::default(),
60 mg_phantom: Default::default(),
61 }
62 }
63
64 #[cfg(feature = "alloc")]
66 pub fn new_with_label<S: Into<Box<[u8]>>>(key: GenericRsaPublicKey<T, M>, label: S) -> Self {
67 Self {
68 inner: key,
69 label: Some(label.into()),
70 phantom: Default::default(),
71 mg_phantom: Default::default(),
72 }
73 }
74
75 #[cfg(not(feature = "alloc"))]
77 pub fn new_with_label(key: GenericRsaPublicKey<T, M>, label: Label) -> Self {
78 Self {
79 inner: key,
80 label: Some(label),
81 phantom: Default::default(),
82 mg_phantom: Default::default(),
83 }
84 }
85}
86
87impl<D, MGD, T, M> RandomizedEncryptor for GenericEncryptingKey<D, MGD, T, M>
88where
89 D: Digest,
90 MGD: Digest + FixedOutputReset,
91 T: UnsignedModularInt,
92 M: CtModulusParams<Modulus = T>,
93{
94 fn encrypt_with_rng_into<'a, R: TryCryptoRng + ?Sized>(
95 &self,
96 rng: &mut R,
97 msg: &[u8],
98 storage: &'a mut [u8],
99 ) -> Result<&'a [u8]> {
100 let label = self.label.as_deref();
101 encrypt_digest_into::<_, D, MGD, _, T>(rng, &self.inner, msg, label, storage)
102 }
103
104 #[cfg(feature = "alloc")]
105 fn encrypt_with_rng<R: CryptoRng + ?Sized>(&self, rng: &mut R, msg: &[u8]) -> Result<Vec<u8>> {
106 let mut storage = vec![0u8; self.inner.size()];
107 let ciphertext = self.encrypt_with_rng_into(rng, msg, &mut storage)?;
108 Ok(ciphertext.to_vec())
109 }
110}
111
112#[cfg(feature = "alloc")]
113impl<D, MGD, T, M> PartialEq for GenericEncryptingKey<D, MGD, T, M>
114where
115 T: UnsignedModularInt,
116 M: ModulusParams<Modulus = T>,
117 GenericRsaPublicKey<T, M>: PartialEq,
118{
119 fn eq(&self, other: &Self) -> bool {
120 self.inner == other.inner && self.label == other.label
121 }
122}
123
124#[cfg(test)]
125mod tests {
126
127 #[test]
128 #[cfg(all(feature = "hazmat", feature = "serde", feature = "keygen"))]
129 fn test_serde() {
130 use super::*;
131 use rand::rngs::ChaCha8Rng;
132 use rand_core::SeedableRng;
133 use serde_test::{assert_tokens, Configure, Token};
134
135 let mut rng = ChaCha8Rng::from_seed([42; 32]);
136 let priv_key =
137 crate::RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
138 let encrypting_key = EncryptingKey::<sha2::Sha256>::new(priv_key.to_public_key());
139
140 let tokens = [
141 Token::Struct {
142 name: "GenericEncryptingKey",
143 len: 4,
144 },
145 Token::Str("inner"),
146 Token::Str(
147 "3024300d06092a864886f70d01010105000313003010020900ab240c3361d02e370203010001",
148 ),
149 Token::Str("label"),
150 Token::None,
151 Token::Str("phantom"),
152 Token::UnitStruct {
153 name: "PhantomData",
154 },
155 Token::Str("mg_phantom"),
156 Token::UnitStruct {
157 name: "PhantomData",
158 },
159 Token::StructEnd,
160 ];
161 assert_tokens(&encrypting_key.readable(), &tokens);
162 }
163}