aesni Algorithm
The AES-NI (Advanced Encryption Standard New Instructions) algorithm is a set of processor instructions that are designed to accelerate the performance of encryption and decryption operations on modern computer hardware. These instructions were introduced by Intel in their Westmere microarchitecture in 2010, and later adopted by AMD in their processors. AES-NI provides a significant boost in cryptographic performance by offloading the computationally intensive tasks of AES encryption and decryption to the hardware itself, rather than relying on software-based implementations. This results in faster and more efficient cryptographic operations, which is essential for various applications such as secure communication, data storage, and digital payments.
The main advantage of the AES-NI algorithm is its ability to perform cryptographic operations with a lower computational overhead, leading to an overall improvement in system performance and security. The AES-NI instruction set includes seven new instructions that are specifically designed to optimize various stages of the AES algorithm, such as key expansion, round transformations, and finalization. By using these hardware-accelerated instructions, software developers can create highly optimized implementations of the AES algorithm that can process large amounts of data in a short amount of time, while also reducing the risk of side-channel attacks that may leak sensitive information. As a result, the AES-NI algorithm has become an essential feature in modern processors, providing a robust and efficient solution for securing data in today's digital world.
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use aes::KeySize;
use aes::KeySize::{KeySize128, KeySize192, KeySize256};
use symmetriccipher::{BlockEncryptor, BlockDecryptor};
use util::supports_aesni;
#[derive(Copy)]
pub struct AesNiEncryptor {
rounds: u8,
round_keys: [u8; 240]
}
impl Clone for AesNiEncryptor { fn clone(&self) -> AesNiEncryptor { *self } }
#[derive(Copy)]
pub struct AesNiDecryptor {
rounds: u8,
round_keys: [u8; 240]
}
impl Clone for AesNiDecryptor { fn clone(&self) -> AesNiDecryptor { *self } }
/// The number of rounds as well as a function to setup an appropriately sized key.
type RoundSetupInfo = (u8, fn(&[u8], KeyType, &mut [u8]));
impl AesNiEncryptor {
pub fn new(key_size: KeySize, key: &[u8]) -> AesNiEncryptor {
if !supports_aesni() {
panic!("AES-NI not supported on this architecture. If you are \
using the MSVC toolchain, this is because the AES-NI method's \
have not been ported, yet");
}
let (rounds, setup_function): RoundSetupInfo = match key_size {
KeySize128 => (10, setup_working_key_aesni_128),
KeySize192 => (12, setup_working_key_aesni_192),
KeySize256 => (14, setup_working_key_aesni_256)
};
let mut e = AesNiEncryptor {
rounds: rounds,
round_keys: [0u8; 240]
};
setup_function(key, KeyType::Encryption, &mut e.round_keys[0..size(e.rounds)]);
e
}
}
impl AesNiDecryptor {
pub fn new(key_size: KeySize, key: &[u8]) -> AesNiDecryptor {
if !supports_aesni() {
panic!("AES-NI not supported on this architecture. If you are \
using the MSVC toolchain, this is because the AES-NI method's \
have not been ported, yet");
}
let (rounds, setup_function): RoundSetupInfo = match key_size {
KeySize128 => (10, setup_working_key_aesni_128),
KeySize192 => (12, setup_working_key_aesni_192),
KeySize256 => (14, setup_working_key_aesni_256)
};
let mut d = AesNiDecryptor {
rounds: rounds,
round_keys: [0u8; 240]
};
setup_function(key, KeyType::Decryption, &mut d.round_keys[0..size(d.rounds)]);
d
}
}
impl BlockEncryptor for AesNiEncryptor {
fn block_size(&self) -> usize { 16 }
fn encrypt_block(&self, input: &[u8], output: &mut [u8]) {
encrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
}
}
impl BlockDecryptor for AesNiDecryptor {
fn block_size(&self) -> usize { 16 }
fn decrypt_block(&self, input: &[u8], output: &mut [u8]) {
decrypt_block_aesni(self.rounds, input, &self.round_keys[0..size(self.rounds)], output);
}
}
enum KeyType {
Encryption,
Decryption
}
#[inline(always)]
fn size(rounds: u8) -> usize { 16 * ((rounds as usize) + 1) }
extern {
fn rust_crypto_aesni_aesimc(round_keys: *mut u8);
fn rust_crypto_aesni_setup_working_key_128(key: *const u8, round_key: *mut u8);
fn rust_crypto_aesni_setup_working_key_192(key: *const u8, round_key: *mut u8);
fn rust_crypto_aesni_setup_working_key_256(key: *const u8, round_key: *mut u8);
fn rust_crypto_aesni_encrypt_block(
rounds: u8,
input: *const u8,
round_keys: *const u8,
output: *mut u8);
fn rust_crypto_aesni_decrypt_block(
rounds: u8,
input: *const u8,
round_keys: *const u8,
output: *mut u8);
}
fn setup_working_key_aesni_128(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
unsafe {
rust_crypto_aesni_setup_working_key_128(key.as_ptr(), round_key.as_mut_ptr());
match key_type {
KeyType::Decryption => {
// range of rounds keys from #1 to #9; skip the first and last key
for i in 1..10 {
rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
}
}
KeyType::Encryption => { /* nothing more to do */ }
}
}
}
fn setup_working_key_aesni_192(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
unsafe {
rust_crypto_aesni_setup_working_key_192(key.as_ptr(), round_key.as_mut_ptr());
match key_type {
KeyType::Decryption => {
// range of rounds keys from #1 to #11; skip the first and last key
for i in 1..12 {
rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
}
}
KeyType::Encryption => { /* nothing more to do */ }
}
}
}
fn setup_working_key_aesni_256(key: &[u8], key_type: KeyType, round_key: &mut [u8]) {
unsafe {
rust_crypto_aesni_setup_working_key_256(key.as_ptr(), round_key.as_mut_ptr());
match key_type {
KeyType::Decryption => {
// range of rounds keys from #1 to #13; skip the first and last key
for i in 1..14 {
rust_crypto_aesni_aesimc(round_key.get_unchecked_mut(16 * i));
}
}
KeyType::Encryption => { /* nothing more to do */ }
}
}
}
fn encrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
unsafe {
rust_crypto_aesni_encrypt_block(
rounds,
input.as_ptr(),
round_keys.as_ptr(),
output.as_mut_ptr());
}
}
fn decrypt_block_aesni(rounds: u8, input: &[u8], round_keys: &[u8], output: &mut [u8]) {
unsafe {
rust_crypto_aesni_decrypt_block(
rounds as u8,
input.as_ptr(),
round_keys.get_unchecked(round_keys.len() - 16),
output.as_mut_ptr());
}
}