Skip to content

Commit

Permalink
support 192-bit key (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
keepsimple1 authored Sep 22, 2020
1 parent 1fd8e83 commit 92486a9
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 9 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,16 @@
[![Build](https://github.com/keepsimple1/libaes/workflows/Build%20and%20Test/badge.svg)](https://github.com/keepsimple1/libaes/actions)
[![Cargo](https://img.shields.io/crates/v/libaes.svg)](https://crates.io/crates/libaes)

This is a re-implementation of OpenSSL 1.1.1 AES core algorithms in safe Rust, with zero dependencies.

My original motivation is to find a correct, fast and minimal AES library in Rust, so that I can easily use it to
interact with an existing data system that uses AES. But I was not able to find such a library so I decided to
write one by porting AES core from [OpenSSL 1.1.1 stable](https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/aes/aes_core.c).
This is a re-implementation of AES in safe Rust, with zero dependencies. The core algorithm is ported
from AES core in [OpenSSL 1.1.1 stable](https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/crypto/aes/aes_core.c).
This library strives to be:

- Correct (as the original OpenSSL implementation)
- Fast (as OpenSSL 1.1.1)
- Safe Rust code only.
- Minimal: no dependencies.

In this version, this library supports 128-bit and 256-bit keys with CBC mode only. Automatic padding is included.
Currently, this library supports 128-bit, 192-bit and 256-bit keys with CBC mode only. Automatic padding is included.

## Examples

Expand Down Expand Up @@ -52,6 +49,6 @@ at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
Contributions are welcome! Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the above license(s), shall be
dual licensed as above, without any additional terms or conditions.
33 changes: 31 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
//! - Zero dependencies.
//! - Fast (as the C version).
//!
//! In this version, this cipher supports 128-bit and 256-bit keys in CBC mode only.
//! Currently, this cipher supports 128-bit, 192-bit and 256-bit keys in CBC mode only.
//!
//! # Examples
//!
//! ```
//! use libaes::Cipher;
//!
//! let my_key = b"This is the key!"; // key is 16 bytes
//! let my_key = b"This is the key!"; // key is 16 bytes, i.e. 128-bit
//! let plaintext = b"A plaintext";
//! let iv = b"This is 16 bytes";
//!
Expand All @@ -35,6 +35,8 @@

/// 128-bit are 16 bytes
pub const AES_128_KEY_LEN: usize = 16;
/// 192-bit are 24 bytes
pub const AES_192_KEY_LEN: usize = 24;
/// 256-bit are 32 bytes
pub const AES_256_KEY_LEN: usize = 32;

Expand Down Expand Up @@ -75,6 +77,29 @@ impl Cipher {
Cipher { encrypt_key, decrypt_key }
}

/// Create an AES 192-bit cipher with a given key.
///
/// Once created, a cipher can encrypt or decrypt any times of data using the same key.
/// `user_key` must be at length of 192-bits, i.e. 24 bytes.
///
/// # Examples
///
/// ```
/// use libaes::Cipher;
///
/// let my_key = b"This is the key! 192 bit"; // 24 bytes
/// let cipher = Cipher::new_192(my_key);
/// ```
pub fn new_192(user_key: &[u8; AES_192_KEY_LEN]) -> Cipher {
let mut encrypt_key = AesKey { rd_key: [0; RD_KEY_MAX_SIZE], rounds: 0 };
aes_set_encrypt_key(user_key, 192, &mut encrypt_key);

let mut decrypt_key = AesKey { rd_key: [0; RD_KEY_MAX_SIZE], rounds: 0 };
aes_set_decrypt_key(user_key, 192, &mut decrypt_key);

Cipher { encrypt_key, decrypt_key }
}

/// Create an AES 256-bit cipher with a given key.
///
/// Once created, a cipher can encrypt or decrypt any times of data using the same key.
Expand Down Expand Up @@ -103,6 +128,8 @@ impl Cipher {
/// The input data is not modified. The output is a new Vec. Padding is done automatically.
/// `iv` is a 16-byte slice. Panics if `iv` is less than 16 bytes.
///
/// This method works for all key sizes.
///
/// # Examples
///
/// ```
Expand Down Expand Up @@ -133,6 +160,8 @@ impl Cipher {
/// The input data is not modified. The output is a new Vec. Padding is handled automatically.
/// `iv` is a 16-byte slice. Panics if `iv` is less than 16 bytes.
///
/// This method works for all key sizes.
///
/// # Examples
///
/// ```
Expand Down
46 changes: 46 additions & 0 deletions tests/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,34 @@ fn nist_verify_aes_128_cbc() {
assert_eq!(decrypted[..], plaintext[..]);
}

#[test]
fn nist_verify_aes_192_cbc() {
// Verify the implementation's correctness using NIST Special Publication 800-38A:
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
// Appendix F.2.3 and F.2.4 CBC Example Vectors for 192-bit
const NIST_CBC_KEY: &[u8; 24] =
b"\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5\
\x62\xf8\xea\xd2\x52\x2c\x6b\x7b";
let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
let plaintext = b"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a\
\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51\
\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef\
\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
let ciphertext = b"\x4f\x02\x1d\xb2\x43\xbc\x63\x3d\x71\x78\x18\x3a\x9f\xa0\x71\xe8\
\xb4\xd9\xad\xa9\xad\x7d\xed\xf4\xe5\xe7\x38\x76\x3f\x69\x14\x5a\
\x57\x1b\x24\x20\x12\xfb\x7a\xe0\x7f\xa9\xba\xac\x3d\xf1\x02\xe0\
\x08\xb0\xe2\x79\x88\x59\x88\x81\xd9\x20\xa9\xe6\x4f\x56\x15\xcd";
let cipher = Cipher::new_192(NIST_CBC_KEY);
let encrypted = cipher.cbc_encrypt(iv, plaintext);
let len_without_padding = 16 * 4;
let padding_size = 16;
assert_eq!(encrypted.len(), len_without_padding + padding_size);
assert_eq!(encrypted[..len_without_padding], ciphertext[..]);

let decrypted = cipher.cbc_decrypt(iv, &encrypted[..]);
assert_eq!(decrypted[..], plaintext[..]);
}

#[test]
fn nist_verify_aes_256_cbc() {
// Verify the implementation's correctness using NIST Special Publication 800-38A:
Expand Down Expand Up @@ -76,6 +104,15 @@ fn small_data() {
assert_ne!(encrypted_256[..], encrypted_128[..]); // Verify AES-256 is different from AES-128
let decrypted_256 = cipher.cbc_decrypt(iv, &encrypted_256[..]);
assert_eq!(decrypted_256[..], plaintext[..]);

// Test with AES-192
let key_192 = b"This is the key! 192 bit";
let cipher = Cipher::new_192(key_192);
let encrypted_192 = cipher.cbc_encrypt(iv, plaintext);
assert_eq!(encrypted_192.len(), 16); // Verify padding
assert_ne!(encrypted_192[..], encrypted_256[..]); // Verify AES-192 is different from AES-256
let decrypted_192 = cipher.cbc_decrypt(iv, &encrypted_192[..]);
assert_eq!(decrypted_192[..], plaintext[..]);
}

#[test]
Expand Down Expand Up @@ -117,4 +154,13 @@ fn large_data() {
assert_ne!(encrypted_256[..], encrypted_128[..]);
let decrypted_256 = cipher.cbc_decrypt(iv, &encrypted_256[..]);
assert_eq!(decrypted_256[..], plaintext[..]);

// Test with AES-192
let key_192 = b"This is the key! 192 bit";
let cipher = Cipher::new_192(key_192);
let encrypted_192 = cipher.cbc_encrypt(iv, plaintext);
assert_eq!(encrypted_192.len(), encrypted_256.len());
assert_ne!(encrypted_192[..], encrypted_256[..]);
let decrypted_192 = cipher.cbc_decrypt(iv, &encrypted_192[..]);
assert_eq!(decrypted_192[..], plaintext[..]);
}

0 comments on commit 92486a9

Please sign in to comment.