sos_core/crypto/cipher/
mod.rs

1//! Constants for supported symmetric ciphers.
2use super::{AeadPack, Nonce, PrivateKey};
3use crate::{Error, Result};
4use age::x25519::Recipient;
5use serde::{Deserialize, Serialize};
6use std::{fmt, str::FromStr};
7
8pub mod aes_gcm_256;
9pub mod x25519;
10pub mod xchacha20_poly1305;
11
12/// Extended ChaCha20 Poly1305 cipher.
13pub const X_CHACHA20_POLY1305: u8 = 1;
14
15/// AES-GCM 256 cipher.
16pub const AES_GCM_256: u8 = 2;
17
18/// X25519 asymmetric cipher using AGE.
19pub const X25519: u8 = 3;
20
21/// Supported cipher algorithms.
22#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Serialize, Deserialize)]
23pub enum Cipher {
24    /// Cipher for XChaCha20Poly1305 encryption.
25    XChaCha20Poly1305,
26    /// Cipher for AES-GCM 256 bit encryption.
27    AesGcm256,
28    /// X25519 asymmetric encryption using AGE.
29    X25519,
30}
31
32impl Cipher {
33    /// Encrypt plaintext using this cipher.
34    pub async fn encrypt_symmetric(
35        &self,
36        key: &PrivateKey,
37        plaintext: &[u8],
38        nonce: Option<Nonce>,
39    ) -> Result<AeadPack> {
40        match self {
41            Cipher::XChaCha20Poly1305 => match key {
42                PrivateKey::Symmetric(key) => {
43                    xchacha20_poly1305::encrypt(key, plaintext, nonce)
44                }
45                _ => Err(Error::NotSymmetric),
46            },
47            Cipher::AesGcm256 => match key {
48                PrivateKey::Symmetric(key) => {
49                    aes_gcm_256::encrypt(key, plaintext, nonce)
50                }
51                _ => Err(Error::NotSymmetric),
52            },
53            _ => Err(Error::NotSymmetric),
54        }
55    }
56
57    /// Decrypt ciphertext using this cipher.
58    pub async fn decrypt_symmetric(
59        &self,
60        key: &PrivateKey,
61        aead: &AeadPack,
62    ) -> Result<Vec<u8>> {
63        match self {
64            Cipher::XChaCha20Poly1305 => match key {
65                PrivateKey::Symmetric(key) => {
66                    xchacha20_poly1305::decrypt(key, aead)
67                }
68                _ => Err(Error::NotSymmetric),
69            },
70            Cipher::AesGcm256 => match key {
71                PrivateKey::Symmetric(key) => aes_gcm_256::decrypt(key, aead),
72                _ => Err(Error::NotSymmetric),
73            },
74            _ => Err(Error::NotSymmetric),
75        }
76    }
77
78    /// Encrypt plaintext using this cipher.
79    pub async fn encrypt_asymmetric(
80        &self,
81        key: &PrivateKey,
82        plaintext: &[u8],
83        recipients: Vec<Recipient>,
84    ) -> Result<AeadPack> {
85        match self {
86            Cipher::X25519 => match key {
87                PrivateKey::Asymmetric(_) => {
88                    x25519::encrypt(plaintext, recipients).await
89                }
90                _ => Err(Error::NotAsymmetric),
91            },
92            _ => Err(Error::NotAsymmetric),
93        }
94    }
95
96    /// Decrypt ciphertext using this cipher.
97    pub async fn decrypt_asymmetric(
98        &self,
99        key: &PrivateKey,
100        aead: &AeadPack,
101    ) -> Result<Vec<u8>> {
102        match self {
103            Cipher::X25519 => match key {
104                PrivateKey::Asymmetric(identity) => {
105                    x25519::decrypt(identity, aead).await
106                }
107                _ => Err(Error::NotAsymmetric),
108            },
109            _ => Err(Error::NotAsymmetric),
110        }
111    }
112}
113
114impl Default for Cipher {
115    fn default() -> Self {
116        Self::AesGcm256
117    }
118}
119
120impl fmt::Display for Cipher {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        write!(f, "{}", {
123            match self {
124                Self::XChaCha20Poly1305 => "x_chacha20_poly1305",
125                Self::AesGcm256 => "aes_gcm_256",
126                Self::X25519 => "age_x25519",
127            }
128        })
129    }
130}
131
132impl FromStr for Cipher {
133    type Err = Error;
134
135    fn from_str(s: &str) -> Result<Self> {
136        match s {
137            "x_chacha20_poly1305" => Ok(Self::XChaCha20Poly1305),
138            "aes_gcm_256" => Ok(Self::AesGcm256),
139            "age_x25519" => Ok(Self::X25519),
140            _ => Err(Error::InvalidCipher(s.to_string())),
141        }
142    }
143}
144
145impl From<&Cipher> for u8 {
146    fn from(value: &Cipher) -> Self {
147        match value {
148            Cipher::XChaCha20Poly1305 => X_CHACHA20_POLY1305,
149            Cipher::AesGcm256 => AES_GCM_256,
150            Cipher::X25519 => X25519,
151        }
152    }
153}
154
155impl TryFrom<u8> for Cipher {
156    type Error = Error;
157    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
158        match value {
159            X_CHACHA20_POLY1305 => Ok(Cipher::XChaCha20Poly1305),
160            AES_GCM_256 => Ok(Cipher::AesGcm256),
161            X25519 => Ok(Cipher::X25519),
162            _ => Err(Error::InvalidCipher(value.to_string())),
163        }
164    }
165}