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 { block[i] ^= iv1[i]; }
22        cipher.encrypt_block(GenericArray::from_mut_slice(block));
23        for i in 0..16 { block[i] ^= iv2[i]; }
24        iv1.copy_from_slice(block);
25        std::mem::swap(&mut iv2, &mut next_iv2);
26    }
27}
28
29/// Decrypt `buffer` in-place with AES-256-IGE.
30/// `buffer.len()` must be a multiple of 16.
31pub fn ige_decrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
32    assert_eq!(buffer.len() % 16, 0);
33    let cipher = Aes256::new(GenericArray::from_slice(key));
34
35    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
36    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
37    let mut next_iv1 = [0u8; 16];
38
39    for block in buffer.chunks_mut(16) {
40        next_iv1.copy_from_slice(block);
41        for i in 0..16 { block[i] ^= iv2[i]; }
42        cipher.decrypt_block(GenericArray::from_mut_slice(block));
43        for i in 0..16 { block[i] ^= iv1[i]; }
44        std::mem::swap(&mut iv1, &mut next_iv1);
45        iv2.copy_from_slice(block);
46    }
47}