1use chacha20poly1305::{AeadCore, KeyInit, XChaCha20Poly1305, XNonce, aead::Aead};
10use rand_core::CryptoRngCore;
11use reach_core::{ProstDecode, ProstEncode, ProstEncodeOwned, error, memory::Key};
12#[cfg(any(feature = "reachable", feature = "attestant"))]
13use reach_core::{memory::SharedSecretKeys, storage::GenericVault};
14
15use super::*;
16
17pub(crate) fn decrypt<D>(
22 cipher: &XChaCha20Poly1305,
23 nonce: &XNonce,
24 ciphertext: &[u8],
25) -> Result<D, error::CryptError>
26where
27 D: ProstDecode,
28{
29 let plaintext = cipher.decrypt(nonce, ciphertext)?;
30
31 Ok(D::decode(plaintext)?)
32}
33
34pub trait DecryptableWithNonce<E> {
38 fn decrypt_with_nonce(
40 key: &Key,
41 nonce: &XNonce,
42 encrypted: &E,
43 ) -> Result<Self, error::CryptError>
44 where
45 E: Ciphertext,
46 Self: ProstDecode,
47 {
48 let cipher = XChaCha20Poly1305::new(key.as_ref());
49
50 decrypt(&cipher, nonce, encrypted.ciphertext())
51 }
52}
53
54pub trait Decryptable<E> {
59 fn decrypt(key: &Key, encrypted: &E) -> Result<Self, error::CryptError>
61 where
62 E: Ciphertext + Nonce,
63 Self: ProstDecode,
64 {
65 let cipher = XChaCha20Poly1305::new(key.as_ref());
66
67 decrypt(&cipher, encrypted.nonce(), encrypted.ciphertext())
68 }
69
70 fn decrypt_with_cipher(
75 cipher: &XChaCha20Poly1305,
76 encrypted: &E,
77 ) -> Result<Self, error::CryptError>
78 where
79 E: Ciphertext + Nonce,
80 Self: ProstDecode,
81 {
82 decrypt(cipher, encrypted.nonce(), encrypted.ciphertext())
83 }
84}
85
86fn encrypt<F>(
91 key: &Key,
92 csprng: impl CryptoRngCore,
93 plaintext: &[u8],
94) -> Result<F, error::CryptError>
95where
96 F: From<(XNonce, Vec<u8>)>,
97{
98 let cipher = XChaCha20Poly1305::new(key.as_ref());
99 let nonce = XChaCha20Poly1305::generate_nonce(csprng);
100
101 Ok(F::from((nonce, cipher.encrypt(&nonce, plaintext)?)))
102}
103
104pub trait Encryptable<O> {
110 fn encrypt<F>(&self, key: &Key, csprng: impl CryptoRngCore) -> Result<F, error::CryptError>
112 where
113 F: From<(XNonce, Vec<u8>)>,
114 Self: ProstEncode + Decryptable<O> + Decryptable<F>,
115 {
116 encrypt(key, csprng, &self.encode_to_vec())
117 }
118
119 fn encrypt_owned<F>(self, key: &Key, csprng: impl CryptoRngCore) -> Result<F, error::CryptError>
121 where
122 F: From<(XNonce, Vec<u8>)>,
123 Self: ProstEncodeOwned + Decryptable<O> + Decryptable<F>,
124 {
125 encrypt(key, csprng, &self.encode_to_vec())
126 }
127
128 fn encrypt_owned_with_nonce<F>(self, key: &Key, nonce: &XNonce) -> Result<F, error::CryptError>
136 where
137 F: From<Vec<u8>>,
138 Self: ProstEncodeOwned + DecryptableWithNonce<O> + Decryptable<F> + Sized,
139 {
140 let plaintext = self.encode_to_vec();
141 let cipher = XChaCha20Poly1305::new(key.as_ref());
142
143 Ok(F::from(cipher.encrypt(nonce, plaintext.as_slice())?))
144 }
145}
146
147#[cfg(any(feature = "reaching", feature = "reachable"))]
148mod reaching_reachable {
149 use reach_core::{
150 memory::{Credentials, Message, MessageVaultPassport},
151 wire::{
152 CredentialVault, Envelope, EnvelopeId, MessageVault, MessageVaultId, MessageVaultSeed,
153 SealedEnvelopeId, SealedMessageVaultId,
154 },
155 };
156
157 use super::*;
158
159 ciphertext_nonce!(Envelope, nonce, message_vault_passport_ciphertext);
160 ciphertext_nonce!(MessageVault, message_ciphertext);
161
162 impl Encryptable<MessageVault> for Message {}
163 impl Encryptable<Envelope> for MessageVaultPassport {}
164
165 impl Decryptable<CredentialVault> for Credentials {}
166 impl DecryptableWithNonce<MessageVault> for Message {}
167 impl Decryptable<Envelope> for MessageVaultPassport {}
168 impl Decryptable<MessageVaultSeed> for Message {}
169 impl Decryptable<(XNonce, Vec<u8>)> for MessageVaultPassport {}
170 impl Decryptable<SealedEnvelopeId> for EnvelopeId {}
171 impl Decryptable<SealedMessageVaultId> for MessageVaultId {}
172}
173
174#[cfg(any(feature = "reachable", feature = "attestant"))]
175mod reachable_attestant {
176 use super::*;
177
178 ciphertext_nonce!(GenericVault, nonce, ciphertext);
179
180 impl Encryptable<GenericVault> for SharedSecretKeys {}
181 impl Encryptable<GenericVault> for Key {}
182}
183
184#[cfg(feature = "reachable")]
185mod reachable {
186 use super::*;
187
188 impl Decryptable<GenericVault> for SharedSecretKeys {}
189 impl Decryptable<GenericVault> for Key {}
190}