Skip to main content

ferogram_crypto/
aes.rs

1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3//
4// ferogram: async Telegram MTProto client in Rust
5// https://github.com/ankit-chaubey/ferogram
6//
7// Based on layer: https://github.com/ankit-chaubey/layer
8// Follows official Telegram client behaviour (tdesktop, TDLib).
9//
10// If you use or modify this code, keep this notice at the top of your file
11// and include the LICENSE-MIT or LICENSE-APACHE file from this repository:
12// https://github.com/ankit-chaubey/ferogram
13
14//! AES-IGE (Infinite Garble Extension): used by Telegram's MTProto.
15
16#![allow(deprecated)]
17
18use aes::Aes256;
19use aes::cipher::generic_array::GenericArray;
20use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
21
22/// Encrypt `buffer` in-place with AES-256-IGE.
23/// `buffer.len()` must be a multiple of 16.
24pub fn ige_encrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
25    assert_eq!(buffer.len() % 16, 0);
26    let cipher = Aes256::new(GenericArray::from_slice(key));
27
28    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
29    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
30    let mut next_iv2 = [0u8; 16];
31
32    for block in buffer.chunks_mut(16) {
33        next_iv2.copy_from_slice(block);
34        for i in 0..16 {
35            block[i] ^= iv1[i];
36        }
37        cipher.encrypt_block(GenericArray::from_mut_slice(block));
38        for i in 0..16 {
39            block[i] ^= iv2[i];
40        }
41        iv1.copy_from_slice(block);
42        std::mem::swap(&mut iv2, &mut next_iv2);
43    }
44}
45
46/// Decrypt `buffer` in-place with AES-256-IGE.
47/// `buffer.len()` must be a multiple of 16.
48pub fn ige_decrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
49    assert_eq!(buffer.len() % 16, 0);
50    let cipher = Aes256::new(GenericArray::from_slice(key));
51
52    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
53    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
54    let mut next_iv1 = [0u8; 16];
55
56    for block in buffer.chunks_mut(16) {
57        next_iv1.copy_from_slice(block);
58        for i in 0..16 {
59            block[i] ^= iv2[i];
60        }
61        cipher.decrypt_block(GenericArray::from_mut_slice(block));
62        for i in 0..16 {
63            block[i] ^= iv1[i];
64        }
65        std::mem::swap(&mut iv1, &mut next_iv1);
66        iv2.copy_from_slice(block);
67    }
68}