Encrypting data with AES using openssl in rust
AES cryptography openssl rustIn the previous post, we discussed about generating the RSA key pair and using it to encrypt and decrypt the data. This one is about generating the AES key and using it.
Before we get started
-
What is AES?
Symmetric-key block cipher (single key for both encryption and decryption) that encrypts data in blocks of 128 bits (16 bytes). Encrypts data in blocks of 128 bits, regardless of the original input length.
AES has three main variants:
- AES-128 : The most common variant, using 128-bit keys (16 bytes).
- AES-192 : Using 192-bit keys (24 bytes), which provides more security than AES-128.
- AES-256 : The strongest variant, using 256-bit keys (32 bytes).
It is used for encrypting the data both at rest and transit.
It’s been the standard for encrypting sensitive information since 1997.
To use AES in a rust project, steps are straightforward
- Generate an
AES
key - Generate an
Initialization Vector
;IV
- Initialize the cipher
- encrypt the plain text using these three things.
The decryption process is similar,
- use the same
AES
key andIV
- Initialize the cipher
- Decrypt the cipher text.
Key concepts
Before going ahead, let’s understand what are these things:
AES
Key: A key of size 128, 192, or 256 bits (16, 24, or 32 bytes). It should be generated using Cryptographically secure pseudorandom number generator (CSPRNG).Initialization Vector
: IV, it is an input to a cryptographic primitive being used to provide the initial state. In simple words, a random value used to initialize the encryption process.- Cipher: in this context, it is the required cipher algorithm (which is
AES
) that also specifies the key size and the encryption mode. Block cipher modes
Implementation
In this first step, we will
- generate the 192 bit AES key
- generate 16 bytes of
IV
- use the CBC mode
- encrypt and decrypt the plain text.
Let’s get into the code.
Setting up the project
Add openssl
to Cargo.toml
[package]
name = "openssl_demo_aes"
version = "0.1.0"
edition = "2021"
[dependencies]
openssl = "0.10.68"
Writing the code
main.rs
use openssl::rand::rand_bytes;
use openssl::symm::{decrypt, encrypt, Cipher};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let plaintext_input = "this is plain text";
println!("plaintext input: {}", plaintext_input);
println!("plaintext_input bytes: {:?}", plaintext_input.as_bytes());
// Generate a 192-bit (24-byte) AES key using CSPRNG
// which is openssl::rand::rand_bytes
let mut key = vec![0; 24];
let _ = rand_bytes(&mut key)?;
println!("key: {:?}", key);
// Generate an IV with 16 bytes of randomness
let mut iv = vec![0; 16];
let _ = rand_bytes(&mut iv)?;
println!("iv: {:?}", iv);
// initialize the cipher AES 192 bits CBC mode
let cipher = Cipher::aes_192_cbc();
// encrypt the plain text
let ciphertext = encrypt(cipher, &key, Some(&iv), plaintext_input.as_bytes())?;
println!("ciphertext: {:?}", ciphertext);
// decrypt the cipher text
let plaintext_decrypted = decrypt(cipher, &key, Some(&iv), &ciphertext)?;
// print the decrypted data
println!("plaintext decrypted bytes: {:?}", plaintext_decrypted);
let plaintext_decrypted_str = String::from_utf8(plaintext_decrypted)?;
println!("plaintext_decrypted string: {}", plaintext_decrypted_str);
Ok(())
}
To run this
$ cargo run --release
Finished release [optimized] target(s) in 0.01s
Running `target/release/openssl_demo_aes`
plaintext input: this is plain text
plaintext_input bytes: [116, 104, 105, 115, 32, 105, 115, 32, 112, 108, 97, 105, 110, 32, 116, 101, 120, 116]
key: [88, 66, 219, 249, 32, 214, 42, 85, 253, 95, 8, 91, 138, 17, 147, 210, 133, 251, 45, 193, 187, 210, 232, 138]
iv: [102, 1, 67, 255, 50, 92, 147, 252, 28, 3, 147, 115, 78, 169, 246, 205]
ciphertext: [217, 239, 51, 187, 185, 133, 161, 221, 51, 69, 27, 158, 201, 126, 154, 123, 43, 35, 118, 144, 190, 166, 177, 198, 168, 220, 68, 104, 196, 95, 9, 186]
plaintext decrypted bytes: [116, 104, 105, 115, 32, 105, 115, 32, 112, 108, 97, 105, 110, 32, 116, 101, 120, 116]
plaintext_decrypted string: this is plain text
points to remember
- IVs should never be reused with the same key.
- Secure storage of keys and IVs is crucial (e.g., using a secure key management system).
- Keys should not be hard coded into the programs.
- Insecure random number generators should be avoided.
In this example, we used CBC
mode, which requires Padding
and is susceptible
to padding oracle attacks if not implemented properly. The alternative is
GCM provides built-in
authentication, making it a preferred choice for many applications.
Next steps
In the next post, we will see how to use AES_GCM
using the crate openssl.