Skip to main content

onionlink_core/
crypto.rs

1use aes::{Aes128, Aes256};
2use ctr::cipher::{KeyIvInit, StreamCipher};
3use curve25519_dalek::edwards::CompressedEdwardsY;
4use curve25519_dalek::scalar::Scalar;
5use hmac::{Hmac, Mac};
6use rand::RngCore;
7use sha1::Sha1;
8use sha2::Sha256;
9use sha3::digest::{ExtendableOutput, Update, XofReader};
10use sha3::{Digest as ShaDigest, Sha3_256, Shake256};
11use x25519_dalek::{PublicKey, StaticSecret};
12
13use crate::error::{ensure, Error, Result};
14use crate::tor::{K_CELL_BODY_LEN, K_RELAY_HEADER_LEN, K_RELAY_PAYLOAD_LEN};
15use crate::util::{put_u64, read_u16, Bytes};
16
17pub fn random_bytes(n: usize) -> Bytes {
18    let mut b = vec![0; n];
19    rand::rngs::OsRng.fill_bytes(&mut b);
20    b
21}
22
23pub fn ct_equal(a: &[u8], b: &[u8]) -> bool {
24    if a.len() != b.len() {
25        return false;
26    }
27    let mut diff = 0u8;
28    for (&x, &y) in a.iter().zip(b) {
29        diff |= x ^ y;
30    }
31    diff == 0
32}
33
34pub fn sha1(in_bytes: &[u8]) -> Bytes {
35    let mut h = Sha1::new();
36    sha1::Digest::update(&mut h, in_bytes);
37    h.finalize().to_vec()
38}
39
40pub fn sha256(in_bytes: &[u8]) -> Bytes {
41    let mut h = Sha256::new();
42    sha2::Digest::update(&mut h, in_bytes);
43    h.finalize().to_vec()
44}
45
46pub fn sha3_256(in_bytes: &[u8]) -> Bytes {
47    let mut h = Sha3_256::new();
48    ShaDigest::update(&mut h, in_bytes);
49    h.finalize().to_vec()
50}
51
52pub fn hmac_sha256(key: &[u8], msg: &[u8]) -> Result<Bytes> {
53    let mut mac = Hmac::<Sha256>::new_from_slice(key).map_err(|_| Error::new("hmac failed"))?;
54    Mac::update(&mut mac, msg);
55    Ok(mac.finalize().into_bytes().to_vec())
56}
57
58pub fn shake256(in_bytes: &[u8], out_len: usize) -> Bytes {
59    let mut h = Shake256::default();
60    h.update(in_bytes);
61    let mut reader = h.finalize_xof();
62    let mut out = vec![0; out_len];
63    reader.read(&mut out);
64    out
65}
66
67pub fn tor_mac(key: &[u8], msg: &[u8]) -> Bytes {
68    let mut input = Bytes::new();
69    put_u64(&mut input, key.len() as u64);
70    input.extend_from_slice(key);
71    input.extend_from_slice(msg);
72    sha3_256(&input)
73}
74
75type Aes128Ctr = ctr::Ctr128BE<Aes128>;
76type Aes256Ctr = ctr::Ctr128BE<Aes256>;
77
78enum AesCtr {
79    Aes128(Box<Aes128Ctr>),
80    Aes256(Box<Aes256Ctr>),
81}
82
83impl AesCtr {
84    fn new(key: &[u8], iv: &[u8]) -> Result<Self> {
85        ensure(iv.len() == 16, "bad aes ctr iv")?;
86        match key.len() {
87            16 => Ok(Self::Aes128(Box::new(
88                Aes128Ctr::new_from_slices(key, iv).map_err(|_| Error::new("aes setkey failed"))?,
89            ))),
90            32 => Ok(Self::Aes256(Box::new(
91                Aes256Ctr::new_from_slices(key, iv).map_err(|_| Error::new("aes setkey failed"))?,
92            ))),
93            _ => Err(Error::new("aes setkey failed")),
94        }
95    }
96
97    fn apply(&mut self, input: &[u8]) -> Bytes {
98        let mut out = input.to_vec();
99        match self {
100            Self::Aes128(c) => c.apply_keystream(&mut out),
101            Self::Aes256(c) => c.apply_keystream(&mut out),
102        }
103        out
104    }
105}
106
107pub fn aes_ctr_crypt(key: &[u8], input: &[u8], iv: Option<&[u8]>) -> Result<Bytes> {
108    let zero = [0u8; 16];
109    let mut c = AesCtr::new(key, iv.unwrap_or(&zero))?;
110    Ok(c.apply(input))
111}
112
113pub struct AesCtrStream {
114    ctr: AesCtr,
115}
116
117impl AesCtrStream {
118    pub fn new(key: &[u8]) -> Self {
119        let iv = [0u8; 16];
120        Self {
121            ctr: AesCtr::new(key, &iv).expect("valid relay AES key length"),
122        }
123    }
124
125    pub fn apply(&mut self, input: &[u8]) -> Result<Bytes> {
126        Ok(self.ctr.apply(input))
127    }
128}
129
130#[derive(Clone)]
131pub enum DigestState {
132    Sha1(Sha1),
133    Sha3(Box<Sha3_256>),
134}
135
136impl DigestState {
137    pub fn sha1_with_seed(seed: &[u8]) -> Self {
138        let mut h = Sha1::new();
139        sha1::Digest::update(&mut h, seed);
140        Self::Sha1(h)
141    }
142
143    pub fn sha3_with_seed(seed: &[u8]) -> Self {
144        let mut h = Sha3_256::new();
145        ShaDigest::update(&mut h, seed);
146        Self::Sha3(Box::new(h))
147    }
148
149    fn update(&mut self, bytes: &[u8]) {
150        match self {
151            Self::Sha1(h) => sha1::Digest::update(h, bytes),
152            Self::Sha3(h) => ShaDigest::update(h.as_mut(), bytes),
153        }
154    }
155
156    fn current(&self) -> Bytes {
157        match self {
158            Self::Sha1(h) => h.clone().finalize().to_vec(),
159            Self::Sha3(h) => h.as_ref().clone().finalize().to_vec(),
160        }
161    }
162}
163
164#[derive(Clone, Copy, Debug, Eq, PartialEq)]
165pub enum DigestKind {
166    Sha1,
167    Sha3,
168}
169
170pub struct RelayCrypto {
171    f: AesCtrStream,
172    b: AesCtrStream,
173    sf: DigestState,
174    sb: DigestState,
175}
176
177impl RelayCrypto {
178    pub fn new(df: &[u8], db: &[u8], kf: &[u8], kb: &[u8], kind: DigestKind) -> Self {
179        let sf = match kind {
180            DigestKind::Sha1 => DigestState::sha1_with_seed(df),
181            DigestKind::Sha3 => DigestState::sha3_with_seed(df),
182        };
183        let sb = match kind {
184            DigestKind::Sha1 => DigestState::sha1_with_seed(db),
185            DigestKind::Sha3 => DigestState::sha3_with_seed(db),
186        };
187        Self {
188            f: AesCtrStream::new(kf),
189            b: AesCtrStream::new(kb),
190            sf,
191            sb,
192        }
193    }
194
195    pub fn encrypt_relay(&mut self, relay_cmd: u8, stream_id: u16, data: &[u8]) -> Result<Bytes> {
196        ensure(data.len() <= K_RELAY_PAYLOAD_LEN, "relay payload too large")?;
197        let mut body = vec![0; K_CELL_BODY_LEN];
198        body[0] = relay_cmd;
199        body[3] = (stream_id >> 8) as u8;
200        body[4] = stream_id as u8;
201        body[9] = (data.len() >> 8) as u8;
202        body[10] = data.len() as u8;
203        body[K_RELAY_HEADER_LEN..K_RELAY_HEADER_LEN + data.len()].copy_from_slice(data);
204        self.sf.update(&body);
205        let d = self.sf.current();
206        body[5..9].copy_from_slice(&d[..4]);
207        self.encrypt_body_only(&body)
208    }
209
210    pub fn decrypt_recognized(&mut self, encrypted: &[u8]) -> Result<Option<Bytes>> {
211        let body = self.decrypt_body_only(encrypted)?;
212        if self.recognize_decrypted(&body) {
213            Ok(Some(body))
214        } else {
215            Ok(None)
216        }
217    }
218
219    pub fn recognize_decrypted(&mut self, body: &[u8]) -> bool {
220        if body.len() != K_CELL_BODY_LEN || body[1] != 0 || body[2] != 0 {
221            return false;
222        }
223        let mut tmp = body.to_vec();
224        tmp[5..9].fill(0);
225        let checkpoint = self.sb.clone();
226        self.sb.update(&tmp);
227        let d = self.sb.current();
228        if d[..4] == body[5..9] {
229            true
230        } else {
231            self.sb = checkpoint;
232            false
233        }
234    }
235
236    pub fn encrypt_body_only(&mut self, body: &[u8]) -> Result<Bytes> {
237        self.f.apply(body)
238    }
239
240    pub fn decrypt_body_only(&mut self, body: &[u8]) -> Result<Bytes> {
241        self.b.apply(body)
242    }
243}
244
245pub fn kdf_tor(k0: &[u8], len: usize) -> Bytes {
246    let mut out = Bytes::new();
247    let mut i = 0u8;
248    while out.len() < len {
249        let mut input = k0.to_vec();
250        input.push(i);
251        out.extend_from_slice(&sha1(&input));
252        i = i.wrapping_add(1);
253    }
254    out.truncate(len);
255    out
256}
257
258pub fn hkdf_sha256_expand(key_seed: &[u8], info: &[u8], len: usize) -> Result<Bytes> {
259    let mut out = Bytes::new();
260    let mut prev = Bytes::new();
261    let mut i = 1u8;
262    while out.len() < len {
263        let mut msg = prev;
264        msg.extend_from_slice(info);
265        msg.push(i);
266        prev = hmac_sha256(key_seed, &msg)?;
267        out.extend_from_slice(&prev);
268        i = i.wrapping_add(1);
269    }
270    out.truncate(len);
271    Ok(out)
272}
273
274pub fn x25519_public_from_private(privkey: &[u8]) -> Result<Bytes> {
275    ensure(privkey.len() == 32, "bad x25519 private key")?;
276    let mut raw = [0u8; 32];
277    raw.copy_from_slice(privkey);
278    let secret = StaticSecret::from(raw);
279    let public = PublicKey::from(&secret);
280    Ok(public.as_bytes().to_vec())
281}
282
283pub fn x25519_shared(privkey: &[u8], pubkey: &[u8]) -> Result<Bytes> {
284    ensure(
285        privkey.len() == 32 && pubkey.len() == 32,
286        "bad x25519 inputs",
287    )?;
288    let mut priv_raw = [0u8; 32];
289    let mut pub_raw = [0u8; 32];
290    priv_raw.copy_from_slice(privkey);
291    pub_raw.copy_from_slice(pubkey);
292    let secret = StaticSecret::from(priv_raw);
293    let public = PublicKey::from(pub_raw);
294    Ok(secret.diffie_hellman(&public).as_bytes().to_vec())
295}
296
297pub fn ed25519_point_is_valid(pubkey: &[u8]) -> bool {
298    if pubkey.len() != 32 {
299        return false;
300    }
301    let mut raw = [0u8; 32];
302    raw.copy_from_slice(pubkey);
303    CompressedEdwardsY(raw).decompress().is_some()
304}
305
306pub fn ed25519_scalarmult_noclamp(scalar_bytes: &[u8], pubkey: &[u8]) -> Result<Bytes> {
307    ensure(
308        scalar_bytes.len() == 32 && pubkey.len() == 32,
309        "bad ed25519 inputs",
310    )?;
311    let mut s = [0u8; 32];
312    let mut p = [0u8; 32];
313    s.copy_from_slice(scalar_bytes);
314    p.copy_from_slice(pubkey);
315    let point = CompressedEdwardsY(p)
316        .decompress()
317        .ok_or_else(|| Error::new("ed25519 key blinding failed"))?;
318    let scalar = Scalar::from_bytes_mod_order(s);
319    Ok((scalar * point).compress().to_bytes().to_vec())
320}
321
322pub fn relay_body_len(body: &[u8]) -> Result<usize> {
323    read_u16(body, 9).map(|v| v as usize)
324}