ss_rs/crypto/
cipher.rs

1//! Shadowsocks ciphers.
2
3use std::{
4    fmt::{self, Display, Formatter},
5    str::FromStr,
6};
7
8use crate::crypto::aead::Variant;
9
10/// Shadowsocks cipher.
11pub struct Cipher {
12    method: Method,
13    cipher: Variant,
14}
15
16impl Cipher {
17    /// Creates a new Cipher with method and key.
18    pub fn new(method: Method, key: &[u8]) -> Self {
19        Cipher {
20            method,
21            cipher: Variant::new(method, key),
22        }
23    }
24
25    /// Encrypts the given plaintext.
26    pub fn encrypt(&self, nonce: &[u8], plaintext: &[u8]) -> aead::Result<Vec<u8>> {
27        self.cipher.encrypt(nonce, plaintext)
28    }
29
30    /// Decrypts the given ciphertext.
31    pub fn decrypt(&self, nonce: &[u8], ciphertext: &[u8]) -> aead::Result<Vec<u8>> {
32        self.cipher.decrypt(nonce, ciphertext)
33    }
34
35    /// Get the encryption method in use.
36    pub fn method(&self) -> Method {
37        self.method
38    }
39}
40
41/// Errors when handle shadowsocks ciphers.
42#[derive(Debug)]
43pub enum Error {
44    /// Unsupported encryption method.
45    Method(String),
46}
47
48impl Display for Error {
49    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
50        match self {
51            Error::Method(name) => write!(f, "{} is unsupported encryption method", name),
52        }
53    }
54}
55
56impl std::error::Error for Error {}
57
58/// Encryption methods.
59#[derive(Debug, Clone, Copy)]
60pub enum Method {
61    ChaCha20Poly1305,
62    Aes128Gcm,
63    Aes256Gcm,
64}
65
66impl Method {
67    /// Returns required key size of the method.
68    #[inline(always)]
69    pub const fn key_size(&self) -> usize {
70        match self {
71            Method::ChaCha20Poly1305 | Method::Aes256Gcm => 32,
72            Method::Aes128Gcm => 16,
73        }
74    }
75
76    /// Returns required salt size of the method.
77    #[inline(always)]
78    pub const fn salt_size(&self) -> usize {
79        match self {
80            Method::ChaCha20Poly1305 | Method::Aes256Gcm => 32,
81            Method::Aes128Gcm => 16,
82        }
83    }
84
85    /// Returns required iv size of the method.
86    #[inline(always)]
87    pub const fn iv_size(&self) -> usize {
88        12
89    }
90
91    /// Returns required tag size of the method.
92    #[inline(always)]
93    pub const fn tag_size(&self) -> usize {
94        16
95    }
96}
97
98impl Display for Method {
99    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
100        match self {
101            Method::ChaCha20Poly1305 => write!(f, "chacha20-ietf-poly1305"),
102            Method::Aes128Gcm => write!(f, "aes-128-gcm"),
103            Method::Aes256Gcm => write!(f, "aes-256-gcm"),
104        }
105    }
106}
107
108impl FromStr for Method {
109    type Err = Error;
110
111    fn from_str(name: &str) -> Result<Self, Self::Err> {
112        match name {
113            "chacha20-ietf-poly1305" => Ok(Method::ChaCha20Poly1305),
114            "aes-128-gcm" => Ok(Method::Aes128Gcm),
115            "aes-256-gcm" => Ok(Method::Aes256Gcm),
116            s => Err(Error::Method(s.to_owned())),
117        }
118    }
119}