Skip to main content

devolutions_crypto/ciphertext/
mod.rs

1//! Module for symmetric/asymmetric encryption/decryption.
2//!
3//! This module contains everything related to encryption. You can use it to encrypt and decrypt data using either a shared key of a keypair.
4//! Either way, the encryption will give you a `Ciphertext`, which has a method to decrypt it.
5//!
6//! ### Symmetric
7//!
8//! ```rust
9//! use devolutions_crypto::utils::generate_key;
10//! use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };
11//!
12//! let key: Vec<u8> = generate_key(32).expect("generate key shouldn't fail");
13//!
14//! let data = b"somesecretdata";
15//!
16//! let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
17//!
18//! let decrypted_data = encrypted_data.decrypt(&key).expect("The decryption shouldn't fail");
19//!
20//! assert_eq!(decrypted_data, data);
21//! ```
22//!
23//! ### Asymmetric
24//! Here, you will need a `PublicKey` to encrypt data and the corresponding
25//! `PrivateKey` to decrypt it. You can generate them by using `generate_keypair`
26//! in the [Key module](#key).
27//!
28//! ```rust
29//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
30//! use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion, Ciphertext };
31//!
32//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
33//!
34//! let data = b"somesecretdata";
35//!
36//! let encrypted_data: Ciphertext = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
37//!
38//! let decrypted_data = encrypted_data.decrypt_asymmetric(&keypair.private_key).expect("The decryption shouldn't fail");
39//!
40//! assert_eq!(decrypted_data, data);
41//! ```
42
43mod ciphertext_v1;
44mod ciphertext_v2;
45
46use super::CiphertextSubtype;
47pub use super::CiphertextVersion;
48use super::DataType;
49use super::Error;
50use super::Header;
51use super::HeaderType;
52use super::Result;
53
54use super::key::{PrivateKey, PublicKey, SecretKey};
55
56use ciphertext_v1::CiphertextV1;
57use ciphertext_v2::{CiphertextV2Asymmetric, CiphertextV2Symmetric};
58
59use std::borrow::Borrow;
60use std::convert::TryFrom;
61
62#[cfg(feature = "fuzz")]
63use arbitrary::Arbitrary;
64
65/// A versionned ciphertext. Can be either symmetric or asymmetric.
66#[derive(Clone, Debug)]
67#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
68pub struct Ciphertext {
69    pub(crate) header: Header<Ciphertext>,
70    payload: CiphertextPayload,
71}
72
73impl HeaderType for Ciphertext {
74    type Version = CiphertextVersion;
75    type Subtype = CiphertextSubtype;
76
77    fn data_type() -> DataType {
78        DataType::Ciphertext
79    }
80}
81
82#[derive(Clone, Debug)]
83#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
84enum CiphertextPayload {
85    V1(CiphertextV1),
86    V2Symmetric(CiphertextV2Symmetric),
87    V2Asymmetric(CiphertextV2Asymmetric),
88}
89
90/// Returns a `Ciphertext` from cleartext data and a key.
91/// # Arguments
92///  * `data` - The data to encrypt.
93///  * `key` - The key to use. The recommended size is 32 bytes.
94///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
95/// # Returns
96/// Returns a `Ciphertext` containing the encrypted data.
97/// # Example
98/// ```rust
99/// use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion };
100///
101/// let data = b"somesecretdata";
102/// let key = b"somesecretkey";
103///
104/// let encrypted_data = encrypt(data, key, CiphertextVersion::Latest).unwrap();
105/// ```
106pub fn encrypt(data: &[u8], key: &[u8], version: CiphertextVersion) -> Result<Ciphertext> {
107    encrypt_with_raw_key(data, key, version)
108}
109
110/// Returns a `Ciphertext` from cleartext data and a key.
111/// # Arguments
112///  * `data` - The data to encrypt.
113///  * `key` - The key to use. The recommended size is 32 bytes.
114///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
115/// # Returns
116/// Returns a `Ciphertext` containing the encrypted data.
117/// # Example
118/// ```rust
119/// use devolutions_crypto::ciphertext::{ encrypt_with_raw_key, CiphertextVersion };
120///
121/// let data = b"somesecretdata";
122/// let key = b"somesecretkey";
123///
124/// let encrypted_data = encrypt_with_raw_key(data, key, CiphertextVersion::Latest).unwrap();
125/// ```
126pub fn encrypt_with_raw_key(
127    data: &[u8],
128    key: &[u8],
129    version: CiphertextVersion,
130) -> Result<Ciphertext> {
131    encrypt_with_aad(data, key, [].as_slice(), version)
132}
133
134/// Returns a `Ciphertext` from cleartext data and a key.
135/// # Arguments
136///  * `data` - The data to encrypt.
137///  * `key` - The key to use. The recommended size is 32 bytes.
138///  * `aad` - Additionnal data to authenticate alongside the ciphertext.
139///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
140/// # Returns
141/// Returns a `Ciphertext` containing the encrypted data, which also authenticates the `aad` argument.
142/// # Example
143/// ```rust
144/// use devolutions_crypto::ciphertext::{ encrypt_with_aad, CiphertextVersion };
145///
146/// let data = b"somesecretdata";
147/// let key = b"somesecretkey";
148/// let aad = b"somepublicdata";
149///
150/// let encrypted_data = encrypt_with_aad(data, key, aad, CiphertextVersion::Latest).unwrap();
151/// ```
152pub fn encrypt_with_aad(
153    data: &[u8],
154    key: &[u8],
155    aad: &[u8],
156    version: CiphertextVersion,
157) -> Result<Ciphertext> {
158    let mut header = Header::default();
159
160    header.data_subtype = CiphertextSubtype::Symmetric;
161
162    let payload = match version {
163        CiphertextVersion::V1 => {
164            header.version = CiphertextVersion::V1;
165            CiphertextPayload::V1(CiphertextV1::encrypt(data, key, aad, &header)?)
166        }
167        CiphertextVersion::V2 | CiphertextVersion::Latest => {
168            header.version = CiphertextVersion::V2;
169            CiphertextPayload::V2Symmetric(CiphertextV2Symmetric::encrypt(data, key, aad, &header)?)
170        } //_ => return Err(DevoCryptoError::UnknownVersion),
171    };
172
173    Ok(Ciphertext { header, payload })
174}
175
176/// Returns a `Ciphertext` from cleartext data and a `PublicKey`.
177/// You will need the corresponding `PrivateKey` to decrypt it.
178/// # Arguments
179///  * `data` - The data to encrypt.
180///  * `public_key` - The `PublicKey` to use. Use `generate_keypair` to generate a keypair.
181///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
182/// # Returns
183/// Returns a `Ciphertext` containing the encrypted data.
184/// # Example
185/// ```rust
186/// use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion };
187/// use devolutions_crypto::key::{ generate_keypair, KeyVersion };
188///
189/// let data = b"somesecretdata";
190/// let keypair = generate_keypair(KeyVersion::Latest);
191///
192/// let encrypted_data = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).unwrap();
193/// ```
194pub fn encrypt_asymmetric(
195    data: &[u8],
196    public_key: &PublicKey,
197    version: CiphertextVersion,
198) -> Result<Ciphertext> {
199    encrypt_asymmetric_with_aad(data, public_key, [].as_slice(), version)
200}
201
202/// Returns a `Ciphertext` from cleartext data and a `PublicKey`.
203/// You will need the corresponding `PrivateKey` to decrypt it.
204/// # Arguments
205///  * `data` - The data to encrypt.
206///  * `public_key` - The `PublicKey` to use. Use `generate_keypair` to generate a keypair.
207///  * `aad` - Additionnal data to authenticate alongside the ciphertext.
208///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
209/// # Returns
210/// Returns a `Ciphertext` containing the encrypted data.
211/// # Example
212/// ```rust
213/// use devolutions_crypto::ciphertext::{ encrypt_asymmetric_with_aad, CiphertextVersion };
214/// use devolutions_crypto::key::{ generate_keypair, KeyVersion };
215///
216/// let data = b"somesecretdata";
217/// let aad = b"somepublicdata";
218/// let keypair = generate_keypair(KeyVersion::Latest);
219///
220/// let encrypted_data = encrypt_asymmetric_with_aad(data, &keypair.public_key, aad, CiphertextVersion::Latest).unwrap();
221/// ```
222pub fn encrypt_asymmetric_with_aad(
223    data: &[u8],
224    public_key: &PublicKey,
225    aad: &[u8],
226    version: CiphertextVersion,
227) -> Result<Ciphertext> {
228    let mut header = Header::default();
229
230    header.data_subtype = CiphertextSubtype::Asymmetric;
231
232    let payload = match version {
233        CiphertextVersion::V2 | CiphertextVersion::Latest => {
234            header.version = CiphertextVersion::V2;
235            CiphertextPayload::V2Asymmetric(CiphertextV2Asymmetric::encrypt(
236                data, public_key, aad, &header,
237            )?)
238        }
239        _ => return Err(Error::UnknownVersion),
240    };
241
242    Ok(Ciphertext { header, payload })
243}
244
245/// Returns a `Ciphertext` from cleartext data and a `SecretKey`.
246/// # Arguments
247///  * `data` - The data to encrypt.
248///  * `key` - The `SecretKey` to use. Generate one with `generate_secret_key`.
249///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
250/// # Returns
251/// Returns a `Ciphertext` containing the encrypted data.
252/// # Example
253/// ```rust
254/// use devolutions_crypto::ciphertext::{ encrypt_with_secret_key, CiphertextVersion };
255/// use devolutions_crypto::key::{ generate_secret_key, KeyVersion };
256///
257/// let data = b"somesecretdata";
258/// let key = generate_secret_key(KeyVersion::Latest);
259///
260/// let encrypted_data = encrypt_with_secret_key(data, &key, CiphertextVersion::Latest).unwrap();
261/// ```
262pub fn encrypt_with_secret_key(
263    data: &[u8],
264    key: &SecretKey,
265    version: CiphertextVersion,
266) -> Result<Ciphertext> {
267    encrypt(data, key.as_bytes(), version)
268}
269
270/// Returns a `Ciphertext` from cleartext data and a `SecretKey` with additional authenticated data.
271/// # Arguments
272///  * `data` - The data to encrypt.
273///  * `key` - The `SecretKey` to use. Generate one with `generate_secret_key`.
274///  * `aad` - Additional data to authenticate alongside the ciphertext.
275///  * `version` - Version of the library to encrypt with. Use `CiphertextVersion::Latest` if you're not dealing with shared data.
276/// # Returns
277/// Returns a `Ciphertext` containing the encrypted data, which also authenticates the `aad` argument.
278/// # Example
279/// ```rust
280/// use devolutions_crypto::ciphertext::{ encrypt_with_secret_key_and_aad, CiphertextVersion };
281/// use devolutions_crypto::key::{ generate_secret_key, KeyVersion };
282///
283/// let data = b"somesecretdata";
284/// let aad = b"somepublicdata";
285/// let key = generate_secret_key(KeyVersion::Latest);
286///
287/// let encrypted_data = encrypt_with_secret_key_and_aad(data, &key, aad, CiphertextVersion::Latest).unwrap();
288/// ```
289pub fn encrypt_with_secret_key_and_aad(
290    data: &[u8],
291    key: &SecretKey,
292    aad: &[u8],
293    version: CiphertextVersion,
294) -> Result<Ciphertext> {
295    encrypt_with_aad(data, key.as_bytes(), aad, version)
296}
297
298impl Ciphertext {
299    /// Decrypt the data blob using a key.
300    /// # Arguments
301    ///  * `key` - Key to use. The recommended size is 32 bytes.
302    /// # Returns
303    /// Returns the decrypted data.
304    /// # Example
305    /// ```rust
306    /// use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion};
307    ///
308    /// let data = b"somesecretdata";
309    /// let key = b"somesecretkey";
310    ///
311    /// let encrypted_data = encrypt(data, key, CiphertextVersion::Latest).unwrap();
312    /// let decrypted_data = encrypted_data.decrypt(key).unwrap();
313    ///
314    /// assert_eq!(data.to_vec(), decrypted_data);
315    ///```
316    pub fn decrypt(&self, key: &[u8]) -> Result<Vec<u8>> {
317        self.decrypt_with_raw_key(key)
318    }
319
320    /// Decrypt the data blob using a key.
321    /// # Arguments
322    ///  * `key` - Key to use. The recommended size is 32 bytes.
323    /// # Returns
324    /// Returns the decrypted data.
325    /// # Example
326    /// ```rust
327    /// use devolutions_crypto::ciphertext::{ encrypt_with_raw_key, CiphertextVersion};
328    ///
329    /// let data = b"somesecretdata";
330    /// let key = b"somesecretkey";
331    ///
332    /// let encrypted_data = encrypt_with_raw_key(data, key, CiphertextVersion::Latest).unwrap();
333    /// let decrypted_data = encrypted_data.decrypt_with_raw_key(key).unwrap();
334    ///
335    /// assert_eq!(data.to_vec(), decrypted_data);
336    ///```
337    pub fn decrypt_with_raw_key(&self, key: &[u8]) -> Result<Vec<u8>> {
338        self.decrypt_with_aad(key, [].as_slice())
339    }
340
341    /// Decrypt the data blob using a key.
342    /// # Arguments
343    ///  * `key` - Key to use. The recommended size is 32 bytes.
344    ///  * `aad` - Additionnal data to authenticate alongside the ciphertext.
345    /// # Returns
346    /// Returns the decrypted data.
347    /// # Example
348    /// ```rust
349    /// use devolutions_crypto::ciphertext::{ encrypt_with_aad, CiphertextVersion};
350    ///
351    /// let data = b"somesecretdata";
352    /// let key = b"somesecretkey";
353    /// let aad = b"somepublicdata";
354    ///
355    /// let encrypted_data = encrypt_with_aad(data, key, aad, CiphertextVersion::Latest).unwrap();
356    /// let decrypted_data = encrypted_data.decrypt_with_aad(key, aad).unwrap();
357    ///
358    /// assert_eq!(data.to_vec(), decrypted_data);
359    ///```
360    pub fn decrypt_with_aad(&self, key: &[u8], aad: &[u8]) -> Result<Vec<u8>> {
361        match &self.payload {
362            CiphertextPayload::V1(x) => x.decrypt(key, aad, &self.header),
363            CiphertextPayload::V2Symmetric(x) => x.decrypt(key, aad, &self.header),
364            _ => Err(Error::InvalidDataType),
365        }
366    }
367
368    /// Decrypt the data blob using a `PrivateKey`.
369    /// # Arguments
370    ///  * `private_key` - Key to use. Must be the one in the same keypair as the `PublicKey` used for encryption.
371    /// # Returns
372    /// Returns the decrypted data.
373    /// # Example
374    /// ```rust
375    /// use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion };
376    /// use devolutions_crypto::key::{ generate_keypair, KeyVersion };
377    ///
378    /// let data = b"somesecretdata";
379    /// let keypair = generate_keypair(KeyVersion::Latest);
380    ///
381    /// let encrypted_data = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).unwrap();
382    /// let decrypted_data = encrypted_data.decrypt_asymmetric(&keypair.private_key).unwrap();
383    ///
384    /// assert_eq!(decrypted_data, data);
385    ///```
386    pub fn decrypt_asymmetric(&self, private_key: &PrivateKey) -> Result<Vec<u8>> {
387        self.decrypt_asymmetric_with_aad(private_key, [].as_slice())
388    }
389
390    /// Decrypt the data blob using a `PrivateKey`.
391    /// # Arguments
392    ///  * `private_key` - Key to use. Must be the one in the same keypair as the `PublicKey` used for encryption.
393    ///  * `aad` - Additionnal data to authenticate alongside the ciphertext.
394    /// # Returns
395    /// Returns the decrypted data.
396    /// # Example
397    /// ```rust
398    /// use devolutions_crypto::ciphertext::{ encrypt_asymmetric_with_aad, CiphertextVersion };
399    /// use devolutions_crypto::key::{ generate_keypair, KeyVersion };
400    ///
401    /// let data = b"somesecretdata";
402    /// let keypair = generate_keypair(KeyVersion::Latest);
403    /// let aad = b"somepublicdata";
404    ///
405    /// let encrypted_data = encrypt_asymmetric_with_aad(data, &keypair.public_key, aad, CiphertextVersion::Latest).unwrap();
406    /// let decrypted_data = encrypted_data.decrypt_asymmetric_with_aad(&keypair.private_key, aad).unwrap();
407    ///
408    /// assert_eq!(decrypted_data, data);
409    ///```
410    pub fn decrypt_asymmetric_with_aad(
411        &self,
412        private_key: &PrivateKey,
413        aad: &[u8],
414    ) -> Result<Vec<u8>> {
415        match &self.payload {
416            CiphertextPayload::V2Asymmetric(x) => x.decrypt(private_key, aad, &self.header),
417            CiphertextPayload::V1(_) => Err(Error::UnknownVersion),
418            _ => Err(Error::InvalidDataType),
419        }
420    }
421
422    /// Decrypt the data blob using a `SecretKey`.
423    /// # Arguments
424    ///  * `key` - The `SecretKey` used for encryption.
425    /// # Returns
426    /// Returns the decrypted data.
427    /// # Example
428    /// ```rust
429    /// use devolutions_crypto::ciphertext::{ encrypt_with_secret_key, CiphertextVersion };
430    /// use devolutions_crypto::key::{ generate_secret_key, KeyVersion };
431    ///
432    /// let data = b"somesecretdata";
433    /// let key = generate_secret_key(KeyVersion::Latest);
434    ///
435    /// let encrypted_data = encrypt_with_secret_key(data, &key, CiphertextVersion::Latest).unwrap();
436    /// let decrypted_data = encrypted_data.decrypt_with_secret_key(&key).unwrap();
437    ///
438    /// assert_eq!(decrypted_data, data);
439    ///```
440    pub fn decrypt_with_secret_key(&self, key: &SecretKey) -> Result<Vec<u8>> {
441        self.decrypt(key.as_bytes())
442    }
443
444    /// Decrypt the data blob using a `SecretKey` and additional authenticated data.
445    /// # Arguments
446    ///  * `key` - The `SecretKey` used for encryption.
447    ///  * `aad` - Additional data to authenticate alongside the ciphertext.
448    /// # Returns
449    /// Returns the decrypted data.
450    /// # Example
451    /// ```rust
452    /// use devolutions_crypto::ciphertext::{ encrypt_with_secret_key_and_aad, CiphertextVersion };
453    /// use devolutions_crypto::key::{ generate_secret_key, KeyVersion };
454    ///
455    /// let data = b"somesecretdata";
456    /// let aad = b"somepublicdata";
457    /// let key = generate_secret_key(KeyVersion::Latest);
458    ///
459    /// let encrypted_data = encrypt_with_secret_key_and_aad(data, &key, aad, CiphertextVersion::Latest).unwrap();
460    /// let decrypted_data = encrypted_data.decrypt_with_secret_key_and_aad(&key, aad).unwrap();
461    ///
462    /// assert_eq!(decrypted_data, data);
463    ///```
464    pub fn decrypt_with_secret_key_and_aad(&self, key: &SecretKey, aad: &[u8]) -> Result<Vec<u8>> {
465        self.decrypt_with_aad(key.as_bytes(), aad)
466    }
467}
468
469impl From<Ciphertext> for Vec<u8> {
470    /// Serialize the structure into a `Vec<u8>`, for storage, transmission or use in another language.
471    fn from(data: Ciphertext) -> Self {
472        let mut header: Self = data.header.borrow().into();
473        let mut payload: Self = data.payload.into();
474        header.append(&mut payload);
475        header
476    }
477}
478
479impl TryFrom<&[u8]> for Ciphertext {
480    type Error = Error;
481
482    /// Parses the data. Can return an Error of the data is invalid or unrecognized.
483    fn try_from(data: &[u8]) -> Result<Self> {
484        if data.len() < Header::len() {
485            return Err(Error::InvalidLength);
486        };
487
488        let header = Header::try_from(&data[0..Header::len()])?;
489
490        let payload = match header.version {
491            CiphertextVersion::V1 => {
492                CiphertextPayload::V1(CiphertextV1::try_from(&data[Header::len()..])?)
493            }
494            CiphertextVersion::V2 => match header.data_subtype {
495                CiphertextSubtype::Symmetric | CiphertextSubtype::None => {
496                    CiphertextPayload::V2Symmetric(CiphertextV2Symmetric::try_from(
497                        &data[Header::len()..],
498                    )?)
499                }
500                CiphertextSubtype::Asymmetric => CiphertextPayload::V2Asymmetric(
501                    CiphertextV2Asymmetric::try_from(&data[Header::len()..])?,
502                ),
503            },
504            _ => return Err(Error::UnknownVersion),
505        };
506
507        Ok(Self { header, payload })
508    }
509}
510
511impl From<CiphertextPayload> for Vec<u8> {
512    fn from(data: CiphertextPayload) -> Self {
513        match data {
514            CiphertextPayload::V1(x) => x.into(),
515            CiphertextPayload::V2Symmetric(x) => x.into(),
516            CiphertextPayload::V2Asymmetric(x) => x.into(),
517        }
518    }
519}
520
521#[test]
522fn encrypt_decrypt_test() {
523    let key = "0123456789abcdefghijkl".as_bytes();
524    let data = "This is a very complex string of character that we need to encrypt".as_bytes();
525
526    let encrypted = encrypt(data, key, CiphertextVersion::Latest).unwrap();
527
528    let encrypted: Vec<u8> = encrypted.into();
529
530    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
531    let decrypted = encrypted.decrypt(key).unwrap();
532
533    assert_eq!(decrypted, data);
534}
535
536#[test]
537fn encrypt_decrypt_aad_test() {
538    let key = b"0123456789abcdefghijkl";
539    let data = b"This is a very complex string of character that we need to encrypt";
540    let aad = b"This is some public data that we want to authenticate";
541    let wrong_aad = b"this is some public data that we want to authenticate";
542
543    let encrypted = encrypt_with_aad(data, key, aad, CiphertextVersion::Latest).unwrap();
544
545    let encrypted: Vec<u8> = encrypted.into();
546
547    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
548    let decrypted = encrypted.decrypt_with_aad(key, aad).unwrap();
549
550    assert_eq!(decrypted, data);
551
552    let decrypted = encrypted.decrypt_with_aad(key, wrong_aad);
553
554    assert!(decrypted.is_err());
555
556    let decrypted = encrypted.decrypt(key);
557
558    assert!(decrypted.is_err());
559}
560
561#[test]
562fn encrypt_decrypt_v1_test() {
563    let key = "0123456789abcdefghijkl".as_bytes();
564    let data = "This is a very complex string of character that we need to encrypt".as_bytes();
565
566    let encrypted = encrypt(data, key, CiphertextVersion::V1).unwrap();
567
568    assert_eq!(encrypted.header.version, CiphertextVersion::V1);
569    let encrypted: Vec<u8> = encrypted.into();
570
571    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
572    let decrypted = encrypted.decrypt(key).unwrap();
573
574    assert_eq!(decrypted, data);
575}
576
577#[test]
578fn encrypt_decrypt_aad_v1_test() {
579    let key = b"0123456789abcdefghijkl";
580    let data = b"This is a very complex string of character that we need to encrypt";
581    let aad = b"This is some public data that we want to authenticate";
582    let wrong_aad = b"this is some public data that we want to authenticate";
583
584    let encrypted = encrypt_with_aad(data, key, aad, CiphertextVersion::V1).unwrap();
585
586    let encrypted: Vec<u8> = encrypted.into();
587
588    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
589    let decrypted = encrypted.decrypt_with_aad(key, aad).unwrap();
590
591    assert_eq!(decrypted, data);
592
593    let decrypted = encrypted.decrypt_with_aad(key, wrong_aad);
594
595    assert!(decrypted.is_err());
596
597    let decrypted = encrypted.decrypt(key);
598
599    assert!(decrypted.is_err());
600}
601
602#[test]
603fn encrypt_decrypt_v2_test() {
604    let key = "0123456789abcdefghijkl".as_bytes();
605    let data = "This is a very complex string of character that we need to encrypt".as_bytes();
606
607    let encrypted = encrypt(data, key, CiphertextVersion::V2).unwrap();
608
609    assert_eq!(encrypted.header.version, CiphertextVersion::V2);
610    let encrypted: Vec<u8> = encrypted.into();
611
612    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
613    let decrypted = encrypted.decrypt(key).unwrap();
614
615    assert_eq!(decrypted, data);
616}
617
618#[test]
619fn encrypt_decrypt_aad_v2_test() {
620    let key = b"0123456789abcdefghijkl";
621    let data = b"This is a very complex string of character that we need to encrypt";
622    let aad = b"This is some public data that we want to authenticate";
623    let wrong_aad = b"this is some public data that we want to authenticate";
624
625    let encrypted = encrypt_with_aad(data, key, aad, CiphertextVersion::V2).unwrap();
626
627    let encrypted: Vec<u8> = encrypted.into();
628
629    let encrypted = Ciphertext::try_from(encrypted.as_slice()).unwrap();
630    let decrypted = encrypted.decrypt_with_aad(key, aad).unwrap();
631
632    assert_eq!(decrypted, data);
633
634    let decrypted = encrypted.decrypt_with_aad(key, wrong_aad);
635
636    assert!(decrypted.is_err());
637
638    let decrypted = encrypted.decrypt(key);
639
640    assert!(decrypted.is_err());
641}
642
643#[test]
644fn asymmetric_test() {
645    use super::key::{generate_keypair, KeyVersion};
646
647    let test_plaintext = b"this is a test data";
648
649    let keypair = generate_keypair(KeyVersion::Latest);
650
651    let encrypted_data = encrypt_asymmetric(
652        test_plaintext,
653        &keypair.public_key,
654        CiphertextVersion::Latest,
655    )
656    .unwrap();
657
658    let encrypted_data_vec: Vec<u8> = encrypted_data.into();
659
660    assert_ne!(encrypted_data_vec.len(), 0);
661
662    let encrypted_data = Ciphertext::try_from(encrypted_data_vec.as_slice()).unwrap();
663
664    let decrypted_data = encrypted_data
665        .decrypt_asymmetric(&keypair.private_key)
666        .unwrap();
667
668    assert_eq!(decrypted_data, test_plaintext);
669}
670
671#[test]
672fn asymmetric_aad_test() {
673    use super::key::{generate_keypair, KeyVersion};
674
675    let test_plaintext = b"this is a test data";
676    let aad = b"This is some public data that we want to authenticate";
677    let wrong_aad = b"this is some public data that we want to authenticate";
678
679    let keypair = generate_keypair(KeyVersion::Latest);
680
681    let encrypted_data = encrypt_asymmetric_with_aad(
682        test_plaintext,
683        &keypair.public_key,
684        aad,
685        CiphertextVersion::Latest,
686    )
687    .unwrap();
688
689    let encrypted_data_vec: Vec<u8> = encrypted_data.into();
690
691    assert_ne!(encrypted_data_vec.len(), 0);
692
693    let encrypted_data = Ciphertext::try_from(encrypted_data_vec.as_slice()).unwrap();
694
695    let decrypted_data = encrypted_data
696        .decrypt_asymmetric_with_aad(&keypair.private_key, aad)
697        .unwrap();
698
699    assert_eq!(decrypted_data, test_plaintext);
700
701    let decrypted = encrypted_data.decrypt_asymmetric_with_aad(&keypair.private_key, wrong_aad);
702
703    assert!(decrypted.is_err());
704
705    let decrypted = encrypted_data.decrypt_asymmetric(&keypair.private_key);
706
707    assert!(decrypted.is_err());
708}
709
710#[test]
711fn asymmetric_test_v2() {
712    use super::key::{generate_keypair, KeyVersion};
713
714    let test_plaintext = b"this is a test data";
715
716    let keypair = generate_keypair(KeyVersion::V1);
717
718    let encrypted_data =
719        encrypt_asymmetric(test_plaintext, &keypair.public_key, CiphertextVersion::V2).unwrap();
720
721    assert_eq!(encrypted_data.header.version, CiphertextVersion::V2);
722    let encrypted_data_vec: Vec<u8> = encrypted_data.into();
723
724    assert_ne!(encrypted_data_vec.len(), 0);
725
726    let encrypted_data = Ciphertext::try_from(encrypted_data_vec.as_slice()).unwrap();
727
728    let decrypted_data = encrypted_data
729        .decrypt_asymmetric(&keypair.private_key)
730        .unwrap();
731
732    assert_eq!(decrypted_data, test_plaintext);
733}
734
735#[test]
736fn asymmetric_aad_test_v2() {
737    use super::key::{generate_keypair, KeyVersion};
738
739    let test_plaintext = b"this is a test data";
740    let aad = b"This is some public data that we want to authenticate";
741    let wrong_aad = b"this is some public data that we want to authenticate";
742
743    let keypair = generate_keypair(KeyVersion::V1);
744
745    let encrypted_data = encrypt_asymmetric_with_aad(
746        test_plaintext,
747        &keypair.public_key,
748        aad,
749        CiphertextVersion::V2,
750    )
751    .unwrap();
752
753    let encrypted_data_vec: Vec<u8> = encrypted_data.into();
754
755    assert_ne!(encrypted_data_vec.len(), 0);
756
757    let encrypted_data = Ciphertext::try_from(encrypted_data_vec.as_slice()).unwrap();
758
759    let decrypted_data = encrypted_data
760        .decrypt_asymmetric_with_aad(&keypair.private_key, aad)
761        .unwrap();
762
763    assert_eq!(decrypted_data, test_plaintext);
764
765    let decrypted = encrypted_data.decrypt_asymmetric_with_aad(&keypair.private_key, wrong_aad);
766
767    assert!(decrypted.is_err());
768
769    let decrypted = encrypted_data.decrypt_asymmetric(&keypair.private_key);
770
771    assert!(decrypted.is_err());
772}
773
774#[test]
775fn encrypt_decrypt_with_secret_key() {
776    use super::key::{generate_secret_key, KeyVersion};
777
778    let data = b"somesecretdata";
779    let key = generate_secret_key(KeyVersion::Latest);
780
781    let encrypted = encrypt_with_secret_key(data, &key, CiphertextVersion::Latest).unwrap();
782    let decrypted = encrypted.decrypt_with_secret_key(&key).unwrap();
783
784    assert_eq!(decrypted, data);
785}
786
787#[test]
788fn encrypt_decrypt_with_secret_key_aad() {
789    use super::key::{generate_secret_key, KeyVersion};
790
791    let data = b"somesecretdata";
792    let aad = b"somepublicdata";
793    let wrong_aad = b"somewrongdata";
794    let key = generate_secret_key(KeyVersion::Latest);
795
796    let encrypted =
797        encrypt_with_secret_key_and_aad(data, &key, aad, CiphertextVersion::Latest).unwrap();
798    let decrypted = encrypted
799        .decrypt_with_secret_key_and_aad(&key, aad)
800        .unwrap();
801
802    assert_eq!(decrypted, data);
803
804    assert!(encrypted
805        .decrypt_with_secret_key_and_aad(&key, wrong_aad)
806        .is_err());
807    assert!(encrypted.decrypt_with_secret_key(&key).is_err());
808}
809
810#[test]
811fn encrypt_decrypt_with_secret_key_v1() {
812    use super::key::{generate_secret_key, KeyVersion};
813
814    let data = b"somesecretdata";
815    let key = generate_secret_key(KeyVersion::Latest);
816
817    let encrypted = encrypt_with_secret_key(data, &key, CiphertextVersion::V1).unwrap();
818
819    assert_eq!(encrypted.header.version, CiphertextVersion::V1);
820
821    let encrypted_bytes: Vec<u8> = encrypted.into();
822    let encrypted = Ciphertext::try_from(encrypted_bytes.as_slice()).unwrap();
823    let decrypted = encrypted.decrypt_with_secret_key(&key).unwrap();
824
825    assert_eq!(decrypted, data);
826}
827
828#[test]
829fn encrypt_decrypt_with_secret_key_v2() {
830    use super::key::{generate_secret_key, KeyVersion};
831
832    let data = b"somesecretdata";
833    let key = generate_secret_key(KeyVersion::Latest);
834
835    let encrypted = encrypt_with_secret_key(data, &key, CiphertextVersion::V2).unwrap();
836
837    assert_eq!(encrypted.header.version, CiphertextVersion::V2);
838
839    let encrypted_bytes: Vec<u8> = encrypted.into();
840    let encrypted = Ciphertext::try_from(encrypted_bytes.as_slice()).unwrap();
841    let decrypted = encrypted.decrypt_with_secret_key(&key).unwrap();
842
843    assert_eq!(decrypted, data);
844}