Skip to main content

layer_crypto/
aes.rs

1//! AES-IGE (Infinite Garble Extension): used by Telegram's MTProto.
2
3#![allow(deprecated)]
4
5use aes::Aes256;
6use aes::cipher::generic_array::GenericArray;
7use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
8
9/// Encrypt `buffer` in-place with AES-256-IGE.
10/// `buffer.len()` must be a multiple of 16.
11pub fn ige_encrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
12    assert_eq!(buffer.len() % 16, 0);
13    let cipher = Aes256::new(GenericArray::from_slice(key));
14
15    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
16    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
17    let mut next_iv2 = [0u8; 16];
18
19    for block in buffer.chunks_mut(16) {
20        next_iv2.copy_from_slice(block);
21        for i in 0..16 {
22            block[i] ^= iv1[i];
23        }
24        cipher.encrypt_block(GenericArray::from_mut_slice(block));
25        for i in 0..16 {
26            block[i] ^= iv2[i];
27        }
28        iv1.copy_from_slice(block);
29        std::mem::swap(&mut iv2, &mut next_iv2);
30    }
31}
32
33/// Decrypt `buffer` in-place with AES-256-IGE.
34/// `buffer.len()` must be a multiple of 16.
35pub fn ige_decrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
36    assert_eq!(buffer.len() % 16, 0);
37    let cipher = Aes256::new(GenericArray::from_slice(key));
38
39    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
40    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
41    let mut next_iv1 = [0u8; 16];
42
43    for block in buffer.chunks_mut(16) {
44        next_iv1.copy_from_slice(block);
45        for i in 0..16 {
46            block[i] ^= iv2[i];
47        }
48        cipher.decrypt_block(GenericArray::from_mut_slice(block));
49        for i in 0..16 {
50            block[i] ^= iv1[i];
51        }
52        std::mem::swap(&mut iv1, &mut next_iv1);
53        iv2.copy_from_slice(block);
54    }
55}