Skip to main content

layer_crypto/
aes.rs

1// Copyright (c) Ankit Chaubey <ankitchaubey.dev@gmail.com>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4// NOTE:
5// The "Layer" project is no longer maintained or supported.
6// Its original purpose for personal SDK/APK experimentation and learning
7// has been fulfilled.
8//
9// Please use Ferogram instead:
10// https://github.com/ankit-chaubey/ferogram
11// Ferogram will receive future updates and development, although progress
12// may be slower.
13//
14// Ferogram is an async Telegram MTProto client library written in Rust.
15// Its implementation follows the behaviour of the official Telegram clients,
16// particularly Telegram Desktop and TDLib, and aims to provide a clean and
17// modern async interface for building Telegram clients and tools.
18
19//! AES-IGE (Infinite Garble Extension): used by Telegram's MTProto.
20
21#![allow(deprecated)]
22
23use aes::Aes256;
24use aes::cipher::generic_array::GenericArray;
25use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
26
27/// Encrypt `buffer` in-place with AES-256-IGE.
28/// `buffer.len()` must be a multiple of 16.
29pub fn ige_encrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
30    assert_eq!(buffer.len() % 16, 0);
31    let cipher = Aes256::new(GenericArray::from_slice(key));
32
33    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
34    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
35    let mut next_iv2 = [0u8; 16];
36
37    for block in buffer.chunks_mut(16) {
38        next_iv2.copy_from_slice(block);
39        for i in 0..16 {
40            block[i] ^= iv1[i];
41        }
42        cipher.encrypt_block(GenericArray::from_mut_slice(block));
43        for i in 0..16 {
44            block[i] ^= iv2[i];
45        }
46        iv1.copy_from_slice(block);
47        std::mem::swap(&mut iv2, &mut next_iv2);
48    }
49}
50
51/// Decrypt `buffer` in-place with AES-256-IGE.
52/// `buffer.len()` must be a multiple of 16.
53pub fn ige_decrypt(buffer: &mut [u8], key: &[u8; 32], iv: &[u8; 32]) {
54    assert_eq!(buffer.len() % 16, 0);
55    let cipher = Aes256::new(GenericArray::from_slice(key));
56
57    let mut iv1: [u8; 16] = iv[..16].try_into().unwrap();
58    let mut iv2: [u8; 16] = iv[16..].try_into().unwrap();
59    let mut next_iv1 = [0u8; 16];
60
61    for block in buffer.chunks_mut(16) {
62        next_iv1.copy_from_slice(block);
63        for i in 0..16 {
64            block[i] ^= iv2[i];
65        }
66        cipher.decrypt_block(GenericArray::from_mut_slice(block));
67        for i in 0..16 {
68            block[i] ^= iv1[i];
69        }
70        std::mem::swap(&mut iv1, &mut next_iv1);
71        iv2.copy_from_slice(block);
72    }
73}