===============
== snarkydev ==
===============
Open source software, Rust, C

Encrypting data with AES using openssl in rust

AES cryptography openssl rust

In 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 and IV
  • 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.