Symmetric key encryption uses the same key to encrypt and decrypt. It is mainly a block cipher with a block size of 128 bits. In this case we will use the IGE (Infinite Garble Extension) mode. Within IGE [1], we use a salt value, so that the IV (Initialisation Vector) value is used in the encryption process. In this case we will use Rust to implement 128-bit AES with IGE mode. It has the advantage of propagating errors infinitely forward, so if the ciphertect is modified by just single bit will propagate errors for the rest of the ciphertext. This will show the ciphertext as being corrupted.
AES IGE in Rust |
Method
Telegram contains Infinite Garble Extension (IGE) block cipher mode, and which has been integrated into OpenSSL. It is defined by:
and where:
\(c_i = f_K(m_i \oplus c_{i-1}) \oplus m_{i-1} \)
and where \(f_K\) is the AES block function, \(K\)is the key and \(i\) is incremented from 1 to \(n\) and where \(n\) is the number of plaintext blocks. The first block is initialised by \(c_0\) and \(m_0\).
Code
First we create a project with:
cargo new ige
We then go into the ige folder, and add the following to the cargo.toml file:
[package] name = "my-project" version = "0.1.0" authors = ["runner"] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] aes="0.7.5" hex="0.4.3" block-modes="0.8.1" hex-literal="0.3.3"
The toml file defines the crates we will using in the project. In this case we will use AES CFB with a 128-bit key and a static IV 128-bit value ("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"):
use aes::Aes128; use block_modes::{BlockMode, Ige}; use block_modes::block_padding::Pkcs7; use hex_literal::hex; use std::str; use std::env; type Aes128Ige = Ige; fn main() { let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); let mut message = String::from("Hello world!"); let mut mykey =String::from("000102030405060708090A0B0C0D0E0F"); let args: Vec = env::args().collect(); if args.len() >1 { message = args[1].clone(); } if args.len() >2 { mykey = args[2].clone(); } println!("IGE Mode"); println!("Message: {}",message); println!("Key: {}",mykey); let plaintext=message.as_bytes(); let key = hex::decode(mykey).expect("Decoding failed"); let cipher = Aes128Ige::new_from_slices(&key, &iv).unwrap(); let pos = plaintext.len(); let mut buffer = [0u8; 128]; buffer[..pos].copy_from_slice(plaintext); let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap(); println!("\nCiphertext: {:?}",hex::encode(ciphertext)); let cipher = Aes128Ige::new_from_slices(&key,&iv).unwrap(); let mut buf = ciphertext.to_vec(); let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap(); println!("\nCiphertext: {:?}",str::from_utf8(decrypted_ciphertext).unwrap()); }
Finally we simply build with:
cargo build
A sample run is:
==128-bit AES CFB Mode== Message: Hello World! Key: 000102030405060708090A0B0C0D0E0F Ciphertext: "2ec2ab845b726627e53dba263712a9a9" Ciphertext: "Hello World!"
Coding
References
1] B. Laurie, “OpenSSL’s implementation of Infinite Garble Extension”, 2006