ss_light/crypto/
util.rs

1use md5::{Digest, Md5};
2use ring::aead::{Nonce, NONCE_LEN};
3use ring::hkdf::{KeyType, Salt, HKDF_SHA1_FOR_LEGACY_USE_ONLY};
4
5/// NonceSequence implemented according to [shadowsocks wiki](https://shadowsocks.org/en/wiki/AEAD-Ciphers.html).
6/// the nonce is incremented by one as if it were an unsigned little-endian integer
7pub struct NonceSequence {
8    nonce: [u8; NONCE_LEN],
9    is_first: bool,
10}
11
12impl NonceSequence {
13    pub fn new() -> Self {
14        NonceSequence {
15            nonce: [0u8; NONCE_LEN],
16            is_first: true,
17        }
18    }
19
20    /// return nonce after adding one, it were an unsigned little-endian integer
21    pub fn increment(&mut self) -> &[u8] {
22        if self.is_first {
23            self.is_first = false;
24            return &self.nonce;
25        }
26
27        for i in 0..self.nonce.len() {
28            if self.nonce[i] < 0xff {
29                self.nonce[i] += 1;
30                break;
31            } else {
32                self.nonce[i] = 0;
33            }
34        }
35        return &self.nonce;
36    }
37}
38
39/// For ring aead
40impl ring::aead::NonceSequence for NonceSequence {
41    fn advance(&mut self) -> Result<ring::aead::Nonce, ring::error::Unspecified> {
42        Nonce::try_assume_unique_for_key(self.increment())
43    }
44}
45
46/// Nonce with all zero bytes
47pub struct NonceZeroSequence {}
48const NONCE_ALL_ZERO: [u8; NONCE_LEN] = [0u8; NONCE_LEN];
49/// For ring aead
50impl ring::aead::NonceSequence for NonceZeroSequence {
51    fn advance(&mut self) -> Result<ring::aead::Nonce, ring::error::Unspecified> {
52        Nonce::try_assume_unique_for_key(&NONCE_ALL_ZERO)
53    }
54}
55
56pub fn hkdf_sha1(key: &[u8], salt: &[u8]) -> Vec<u8> {
57    const SUBKEY_INFO: &'static [u8] = b"ss-subkey";
58    let mut sub_key = Vec::<u8>::from([0u8; 64]);
59
60    struct CryptoKeyType(usize);
61    impl KeyType for CryptoKeyType {
62        fn len(&self) -> usize {
63            self.0
64        }
65    }
66
67    let s = Salt::new(HKDF_SHA1_FOR_LEGACY_USE_ONLY, salt);
68    let prk = s.extract(key);
69    let okm = prk
70        .expand(&[SUBKEY_INFO], CryptoKeyType(key.len()))
71        .expect("hkdf_sha1_expand");
72    sub_key.truncate(key.len());
73    okm.fill(&mut sub_key).expect("hkdf_sha1_fill");
74
75    sub_key
76}
77
78pub fn evp_bytes_to_key(password: &[u8], key_len: usize) -> Box<[u8]> {
79    let mut key = vec![0u8; key_len];
80    let mut last = None;
81    let mut offset = 0usize;
82    while offset < key_len {
83        let mut m = Md5::new();
84
85        if let Some(digest) = last {
86            m.update(&digest);
87        }
88
89        m.update(password);
90
91        let digest = m.finalize();
92
93        let amt = std::cmp::min(key_len - offset, digest.len());
94        key[offset..offset + amt].copy_from_slice(&digest[..amt]);
95
96        offset += amt;
97        last = Some(digest);
98    }
99
100    key.into_boxed_slice()
101}
102
103#[cfg(test)]
104mod tests {
105
106    use super::{evp_bytes_to_key, hkdf_sha1, NonceSequence};
107    #[test]
108    fn test_nonce_increment() {
109        let mut seq = NonceSequence::new();
110        for i in 0..=255 {
111            assert_eq!(seq.increment(), [i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
112        }
113        for i in 0..=255 {
114            assert_eq!(seq.increment(), [i, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
115        }
116    }
117
118    #[test]
119    fn test_hkdf_sha1() {
120        let sub_key = hkdf_sha1(&[0u8; 16], &[0u8; 32]);
121        println!("{:?}", sub_key)
122    }
123
124    #[test]
125    fn test_evp_bytes_to_key() {
126        let key = evp_bytes_to_key(b"foobar", 32);
127        assert_eq!(
128            &key[..],
129            &[
130                0x38u8, 0x58, 0xf6, 0x22, 0x30, 0xac, 0x3c, 0x91, 0x5f, 0x30, 0x0c, 0x66, 0x43,
131                0x12, 0xc6, 0x3f, 0x56, 0x83, 0x78, 0x52, 0x96, 0x14, 0xd2, 0x2d, 0xdb, 0x49, 0x23,
132                0x7d, 0x2f, 0x60, 0xbf, 0xdf
133            ]
134        )
135    }
136}