Skip to content

Commit ffcd541

Browse files
committed
Refactored Cipher with macro generated inner implementation
- fixes #5
1 parent a489f1b commit ffcd541

File tree

7 files changed

+258
-95
lines changed

7 files changed

+258
-95
lines changed

Diff for: .gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ Cargo.lock
88

99
# These are backup files generated by rustfmt
1010
**/*.rs.bk
11+
12+
# Editors
13+
.bak
14+
.vscode
15+
.swp

Diff for: Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "shadowsocks-crypto"
3-
version = "0.1.2"
3+
version = "0.2.0"
44
authors = ["luozijun <[email protected]>"]
55
edition = "2018"
66
license = "MIT"

Diff for: README.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
ss-crypto
2-
================
1+
shadowsocks-crypto
2+
==================
33

4+
shadowsocks' flavored cryptographic algorithm in pure Rust.
45

56
Supported Ciphers
67
-----------------------

Diff for: src/v1/aeadcipher.rs

+91-24
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub use crypto2::aeadcipher::{Aes128Gcm, Aes256Gcm, Chacha20Poly1305};
2525
pub use super::ring::{Aes128Gcm, Aes256Gcm, Chacha20Poly1305};
2626
use super::CipherKind;
2727

28-
trait AeadCipherInner {
28+
trait AeadCipherExt {
2929
fn ac_kind(&self) -> CipherKind;
3030
fn ac_key_len(&self) -> usize;
3131
fn ac_block_len(&self) -> usize;
@@ -39,7 +39,7 @@ trait AeadCipherInner {
3939

4040
macro_rules! impl_aead_cipher {
4141
($name:tt, $kind:tt) => {
42-
impl AeadCipherInner for $name {
42+
impl AeadCipherExt for $name {
4343
fn ac_kind(&self) -> CipherKind {
4444
CipherKind::$kind
4545
}
@@ -76,7 +76,7 @@ macro_rules! impl_aead_cipher {
7676

7777
macro_rules! impl_siv_cmac_cipher {
7878
($name:tt, $kind:tt) => {
79-
impl AeadCipherInner for $name {
79+
impl AeadCipherExt for $name {
8080
fn ac_kind(&self) -> CipherKind {
8181
CipherKind::$kind
8282
}
@@ -137,8 +137,94 @@ impl_siv_cmac_cipher!(AesSivCmac256, AES_SIV_CMAC_256);
137137
impl_siv_cmac_cipher!(AesSivCmac384, AES_SIV_CMAC_384);
138138
impl_siv_cmac_cipher!(AesSivCmac512, AES_SIV_CMAC_512);
139139

140+
macro_rules! aead_cipher_variant {
141+
($($name:ident @ $kind:ident,)+) => {
142+
enum AeadCipherInner {
143+
$($name($name),)+
144+
}
145+
146+
impl AeadCipherInner {
147+
fn new(kind: CipherKind, key: &[u8]) -> Self {
148+
match kind {
149+
$(CipherKind::$kind => AeadCipherInner::$name($name::new(key)),)+
150+
_ => unreachable!("unrecognized AEAD cipher kind {:?}", kind),
151+
}
152+
}
153+
}
154+
155+
impl AeadCipherExt for AeadCipherInner {
156+
fn ac_kind(&self) -> CipherKind {
157+
match *self {
158+
$(AeadCipherInner::$name(ref c) => c.ac_kind(),)+
159+
}
160+
}
161+
162+
fn ac_key_len(&self) -> usize {
163+
match *self {
164+
$(AeadCipherInner::$name(ref c) => c.ac_key_len(),)+
165+
}
166+
}
167+
fn ac_block_len(&self) -> usize {
168+
match *self {
169+
$(AeadCipherInner::$name(ref c) => c.ac_block_len(),)+
170+
}
171+
}
172+
173+
fn ac_tag_len(&self) -> usize {
174+
match *self {
175+
$(AeadCipherInner::$name(ref c) => c.ac_tag_len(),)+
176+
}
177+
}
178+
179+
fn ac_n_min(&self) -> usize {
180+
match *self {
181+
$(AeadCipherInner::$name(ref c) => c.ac_n_min(),)+
182+
}
183+
}
184+
fn ac_n_max(&self) -> usize {
185+
match *self {
186+
$(AeadCipherInner::$name(ref c) => c.ac_n_max(),)+
187+
}
188+
}
189+
190+
fn ac_encrypt_slice(&self, nonce: &[u8], plaintext_in_ciphertext_out: &mut [u8]) {
191+
match *self {
192+
$(AeadCipherInner::$name(ref c) => c.ac_encrypt_slice(nonce, plaintext_in_ciphertext_out),)+
193+
}
194+
}
195+
196+
fn ac_decrypt_slice(&self, nonce: &[u8], plaintext_in_ciphertext_out: &mut [u8]) -> bool {
197+
match *self {
198+
$(AeadCipherInner::$name(ref c) => c.ac_decrypt_slice(nonce, plaintext_in_ciphertext_out),)+
199+
}
200+
}
201+
}
202+
};
203+
}
204+
205+
aead_cipher_variant! {
206+
Aes128Ccm @ AES_128_CCM,
207+
Aes256Ccm @ AES_256_CCM,
208+
209+
Aes128OcbTag128 @ AES_128_OCB_TAGLEN128,
210+
Aes192OcbTag128 @ AES_192_OCB_TAGLEN128,
211+
Aes256OcbTag128 @ AES_256_OCB_TAGLEN128,
212+
213+
Aes128Gcm @ AES_128_GCM,
214+
Aes256Gcm @ AES_256_GCM,
215+
216+
AesSivCmac256 @ AES_SIV_CMAC_256,
217+
AesSivCmac384 @ AES_SIV_CMAC_384,
218+
AesSivCmac512 @ AES_SIV_CMAC_512,
219+
220+
Aes128GcmSiv @ AES_128_GCM_SIV,
221+
Aes256GcmSiv @ AES_256_GCM_SIV,
222+
223+
Chacha20Poly1305 @ CHACHA20_POLY1305,
224+
}
225+
140226
pub struct AeadCipher {
141-
cipher: Box<dyn AeadCipherInner + Send + 'static>,
227+
cipher: AeadCipherInner,
142228
nlen: usize,
143229
nonce: [u8; Self::N_MAX],
144230
}
@@ -147,27 +233,8 @@ impl AeadCipher {
147233
const N_MAX: usize = 16;
148234

149235
pub fn new(kind: CipherKind, key: &[u8]) -> Self {
150-
use self::CipherKind::*;
151-
152-
let cipher: Box<dyn AeadCipherInner + Send + 'static> = match kind {
153-
AES_128_CCM => Box::new(Aes128Ccm::new(key)),
154-
AES_256_CCM => Box::new(Aes256Ccm::new(key)),
155-
AES_128_OCB_TAGLEN128 => Box::new(Aes128OcbTag128::new(key)),
156-
AES_192_OCB_TAGLEN128 => Box::new(Aes192OcbTag128::new(key)),
157-
AES_256_OCB_TAGLEN128 => Box::new(Aes256OcbTag128::new(key)),
158-
AES_128_GCM => Box::new(Aes128Gcm::new(key)),
159-
AES_256_GCM => Box::new(Aes256Gcm::new(key)),
160-
AES_SIV_CMAC_256 => Box::new(AesSivCmac256::new(key)),
161-
AES_SIV_CMAC_384 => Box::new(AesSivCmac384::new(key)),
162-
AES_SIV_CMAC_512 => Box::new(AesSivCmac512::new(key)),
163-
AES_128_GCM_SIV => Box::new(Aes128GcmSiv::new(key)),
164-
AES_256_GCM_SIV => Box::new(Aes256GcmSiv::new(key)),
165-
CHACHA20_POLY1305 => Box::new(Chacha20Poly1305::new(key)),
166-
_ => unreachable!(),
167-
};
168-
236+
let cipher = AeadCipherInner::new(kind, key);
169237
let nlen = std::cmp::min(cipher.ac_n_max(), Self::N_MAX);
170-
171238
let nonce = [0u8; Self::N_MAX];
172239

173240
Self {

Diff for: src/v1/cipher.rs

+49-19
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,34 @@ impl CipherInner for AeadCipher {
217217
}
218218

219219
/// Unified interface of Ciphers
220-
pub struct Cipher {
221-
cipher: Box<dyn CipherInner + Send + 'static>,
220+
pub enum Cipher {
221+
Dummy(DummyCipher),
222+
#[cfg(feature = "v1-stream")]
223+
Stream(StreamCipher),
224+
#[cfg(feature = "v1-aead")]
225+
Aead(AeadCipher),
226+
}
227+
228+
macro_rules! cipher_method_forward {
229+
(ref $self:expr, $method:ident $(, $param:expr),*) => {
230+
match *$self {
231+
Cipher::Dummy(ref c) => c.$method($($param),*),
232+
#[cfg(feature = "v1-stream")]
233+
Cipher::Stream(ref c) => c.$method($($param),*),
234+
#[cfg(feature = "v1-aead")]
235+
Cipher::Aead(ref c) => c.$method($($param),*),
236+
}
237+
};
238+
239+
(mut $self:expr, $method:ident $(, $param:expr),*) => {
240+
match *$self {
241+
Cipher::Dummy(ref mut c) => c.$method($($param),*),
242+
#[cfg(feature = "v1-stream")]
243+
Cipher::Stream(ref mut c) => c.$method($($param),*),
244+
#[cfg(feature = "v1-aead")]
245+
Cipher::Aead(ref mut c) => c.$method($($param),*),
246+
}
247+
};
222248
}
223249

224250
impl Cipher {
@@ -231,24 +257,18 @@ impl Cipher {
231257
///
232258
/// - Stream Ciphers initialize with IV
233259
/// - AEAD Ciphers initialize with SALT
234-
pub fn new(kind: CipherKind, key: &[u8], iv_or_salt: &[u8]) -> Self {
260+
pub fn new(kind: CipherKind, key: &[u8], iv_or_salt: &[u8]) -> Cipher {
235261
let category = kind.category();
236262

237263
match category {
238264
CipherCategory::None => {
239265
let _ = key;
240266
let _ = iv_or_salt;
241267

242-
let cipher = Box::new(DummyCipher::new());
243-
244-
Self { cipher }
268+
Cipher::Dummy(DummyCipher::new())
245269
}
246270
#[cfg(feature = "v1-stream")]
247-
CipherCategory::Stream => {
248-
let cipher = Box::new(StreamCipher::new(kind, key, iv_or_salt));
249-
250-
Self { cipher }
251-
}
271+
CipherCategory::Stream => Cipher::Stream(StreamCipher::new(kind, key, iv_or_salt)),
252272
#[cfg(feature = "v1-aead")]
253273
CipherCategory::Aead => {
254274
use crypto2::kdf::HkdfSha1;
@@ -260,34 +280,32 @@ impl Cipher {
260280

261281
let subkey = &okm[..ikm.len()];
262282

263-
let cipher = Box::new(AeadCipher::new(kind, subkey));
264-
265-
Self { cipher }
283+
Cipher::Aead(AeadCipher::new(kind, subkey))
266284
}
267285
}
268286
}
269287

270288
/// Get the `CipherCategory` of the current cipher
271289
pub fn category(&self) -> CipherCategory {
272-
self.cipher.ss_category()
290+
cipher_method_forward!(ref self, ss_category)
273291
}
274292

275293
/// Get the `CipherKind` of the current cipher
276294
pub fn kind(&self) -> CipherKind {
277-
self.cipher.ss_kind()
295+
cipher_method_forward!(ref self, ss_kind)
278296
}
279297

280298
/// Get the TAG length of AEAD ciphers
281299
pub fn tag_len(&self) -> usize {
282-
self.cipher.ss_tag_len()
300+
cipher_method_forward!(ref self, ss_tag_len)
283301
}
284302

285303
/// Encrypt a packet. Encrypted result will be written in `pkt`
286304
///
287305
/// - Stream Ciphers: the size of input and output packets are the same
288306
/// - AEAD Ciphers: the size of output must be at least `input.len() + TAG_LEN`
289307
pub fn encrypt_packet(&mut self, pkt: &mut [u8]) {
290-
self.cipher.ss_encrypt_slice(pkt)
308+
cipher_method_forward!(mut self, ss_encrypt_slice, pkt)
291309
}
292310

293311
/// Decrypt a packet. Decrypted result will be written in `pkt`
@@ -296,7 +314,7 @@ impl Cipher {
296314
/// - AEAD Ciphers: the size of output is `input.len() - TAG_LEN`
297315
#[must_use]
298316
pub fn decrypt_packet(&mut self, pkt: &mut [u8]) -> bool {
299-
self.cipher.ss_decrypt_slice(pkt)
317+
cipher_method_forward!(mut self, ss_decrypt_slice, pkt)
300318
}
301319
}
302320

@@ -331,3 +349,15 @@ fn test_cipher_new_stream() {
331349
let cipher = Cipher::new(kind, &key, &iv);
332350
assert_eq!(cipher.tag_len(), 0);
333351
}
352+
353+
#[test]
354+
fn test_send() {
355+
fn test<C: Send>() {}
356+
test::<Cipher>();
357+
}
358+
359+
#[test]
360+
fn test_sync() {
361+
fn test<C: Sync>() {}
362+
test::<Cipher>();
363+
}

Diff for: src/v1/kind.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -545,10 +545,14 @@ impl core::fmt::Display for CipherKind {
545545
}
546546
}
547547

548+
/// Error while parsing `CipherKind` from string
549+
#[derive(Debug, Clone)]
550+
pub struct ParseCipherKindError;
551+
548552
impl core::str::FromStr for CipherKind {
549-
type Err = std::io::Error;
553+
type Err = ParseCipherKindError;
550554

551-
fn from_str(s: &str) -> Result<Self, std::io::Error> {
555+
fn from_str(s: &str) -> Result<Self, ParseCipherKindError> {
552556
use self::CipherKind::*;
553557

554558
match s.to_lowercase().as_str() {
@@ -664,10 +668,7 @@ impl core::str::FromStr for CipherKind {
664668
// "aes-siv-cmac-256" => Ok(AES_SIV_CMAC_256),
665669
// "aes-siv-cmac-384" => Ok(AES_SIV_CMAC_384),
666670
// "aes-siv-cmac-512" => Ok(AES_SIV_CMAC_512),
667-
_ => Err(std::io::Error::new(
668-
std::io::ErrorKind::Other,
669-
"unknown cipher type",
670-
)),
671+
_ => Err(ParseCipherKindError),
671672
}
672673
}
673674
}

0 commit comments

Comments
 (0)