blob: 26e5a46c6293450affa159d710838a72148282b1 [file] [log] [blame]
//! AES Key Locker Intrinsics
//!
//! The Intrinsics here correspond to those in the `keylockerintrin.h` C header.
use crate::core_arch::x86::__m128i;
use crate::ptr;
#[cfg(test)]
use stdarch_test::assert_instr;
#[repr(C, packed)]
struct EncodeKey128Output(u32, __m128i, __m128i, __m128i, __m128i, __m128i, __m128i);
#[repr(C, packed)]
struct EncodeKey256Output(
u32,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
);
#[repr(C, packed)]
struct AesOutput(u8, __m128i);
#[repr(C, packed)]
struct WideAesOutput(
u8,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
__m128i,
);
#[allow(improper_ctypes)]
unsafe extern "unadjusted" {
#[link_name = "llvm.x86.loadiwkey"]
fn loadiwkey(integrity_key: __m128i, key_lo: __m128i, key_hi: __m128i, control: u32);
#[link_name = "llvm.x86.encodekey128"]
fn encodekey128(key_metadata: u32, key: __m128i) -> EncodeKey128Output;
#[link_name = "llvm.x86.encodekey256"]
fn encodekey256(key_metadata: u32, key_lo: __m128i, key_hi: __m128i) -> EncodeKey256Output;
#[link_name = "llvm.x86.aesenc128kl"]
fn aesenc128kl(data: __m128i, handle: *const u8) -> AesOutput;
#[link_name = "llvm.x86.aesdec128kl"]
fn aesdec128kl(data: __m128i, handle: *const u8) -> AesOutput;
#[link_name = "llvm.x86.aesenc256kl"]
fn aesenc256kl(data: __m128i, handle: *const u8) -> AesOutput;
#[link_name = "llvm.x86.aesdec256kl"]
fn aesdec256kl(data: __m128i, handle: *const u8) -> AesOutput;
#[link_name = "llvm.x86.aesencwide128kl"]
fn aesencwide128kl(
handle: *const u8,
i0: __m128i,
i1: __m128i,
i2: __m128i,
i3: __m128i,
i4: __m128i,
i5: __m128i,
i6: __m128i,
i7: __m128i,
) -> WideAesOutput;
#[link_name = "llvm.x86.aesdecwide128kl"]
fn aesdecwide128kl(
handle: *const u8,
i0: __m128i,
i1: __m128i,
i2: __m128i,
i3: __m128i,
i4: __m128i,
i5: __m128i,
i6: __m128i,
i7: __m128i,
) -> WideAesOutput;
#[link_name = "llvm.x86.aesencwide256kl"]
fn aesencwide256kl(
handle: *const u8,
i0: __m128i,
i1: __m128i,
i2: __m128i,
i3: __m128i,
i4: __m128i,
i5: __m128i,
i6: __m128i,
i7: __m128i,
) -> WideAesOutput;
#[link_name = "llvm.x86.aesdecwide256kl"]
fn aesdecwide256kl(
handle: *const u8,
i0: __m128i,
i1: __m128i,
i2: __m128i,
i3: __m128i,
i4: __m128i,
i5: __m128i,
i6: __m128i,
i7: __m128i,
) -> WideAesOutput;
}
/// Load internal wrapping key (IWKey). The 32-bit unsigned integer `control` specifies IWKey's KeySource
/// and whether backing up the key is permitted. IWKey's 256-bit encryption key is loaded from `key_lo`
/// and `key_hi`.
///
/// - `control[0]`: NoBackup bit. If set, the IWKey cannot be backed up.
/// - `control[1:4]`: KeySource bits. These bits specify the encoding method of the IWKey. The only
/// allowed values are `0` (AES GCM SIV wrapping algorithm with the specified key) and `1` (AES GCM
/// SIV wrapping algorithm with random keys enforced by hardware). After calling `_mm_loadiwkey` with
/// KeySource set to `1`, software must check `ZF` to ensure that the key was loaded successfully.
/// Using any other value may result in a General Protection Exception.
/// - `control[5:31]`: Reserved for future use, must be set to `0`.
///
/// Note that setting the NoBackup bit and using the KeySource value `1` requires hardware support. These
/// permissions can be found by calling `__cpuid(0x19)` and checking the `ECX[0:1]` bits. Failing to follow
/// these restrictions may result in a General Protection Exception.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadiwkey)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(loadiwkey))]
pub unsafe fn _mm_loadiwkey(
control: u32,
integrity_key: __m128i,
key_lo: __m128i,
key_hi: __m128i,
) {
loadiwkey(integrity_key, key_lo, key_hi, control);
}
/// Wrap a 128-bit AES key into a 384-bit key handle and stores it in `handle`. Returns the `control`
/// parameter used to create the IWKey.
///
/// - `key_params[0]`: If set, this key can only be used by the Kernel.
/// - `key_params[1]`: If set, this key can not be used to encrypt.
/// - `key_params[2]`: If set, this key can not be used to decrypt.
/// - `key_params[31:3]`: Reserved for future use, must be set to `0`.
///
/// Note that these restrictions need hardware support, and the supported restrictions can be found by
/// calling `__cpuid(0x19)` and checking the `EAX[0:2]` bits. Failing to follow these restrictions may
/// result in a General Protection Exception.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_encodekey128_u32)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(encodekey128))]
pub unsafe fn _mm_encodekey128_u32(key_params: u32, key: __m128i, handle: *mut u8) -> u32 {
let EncodeKey128Output(control, key0, key1, key2, _, _, _) = encodekey128(key_params, key);
ptr::write_unaligned(handle.cast(), [key0, key1, key2]);
control
}
/// Wrap a 256-bit AES key into a 512-bit key handle and stores it in `handle`. Returns the `control`
/// parameter used to create the IWKey.
///
/// - `key_params[0]`: If set, this key can only be used by the Kernel.
/// - `key_params[1]`: If set, this key can not be used to encrypt.
/// - `key_params[2]`: If set, this key can not be used to decrypt.
/// - `key_params[31:3]`: Reserved for future use, must be set to `0`.
///
/// Note that these restrictions need hardware support, and the supported restrictions can be found by
/// calling `__cpuid(0x19)` and checking the `EAX[0:2]` bits. Failing to follow these restrictions may
/// result in a General Protection Exception.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_encodekey256_u32)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(encodekey256))]
pub unsafe fn _mm_encodekey256_u32(
key_params: u32,
key_lo: __m128i,
key_hi: __m128i,
handle: *mut u8,
) -> u32 {
let EncodeKey256Output(control, key0, key1, key2, key3, _, _, _) =
encodekey256(key_params, key_lo, key_hi);
ptr::write_unaligned(handle.cast(), [key0, key1, key2, key3]);
control
}
/// Encrypt 10 rounds of unsigned 8-bit integers in `input` using 128-bit AES key specified in the
/// 384-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc128kl_u8)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesenc128kl))]
pub unsafe fn _mm_aesenc128kl_u8(output: *mut __m128i, input: __m128i, handle: *const u8) -> u8 {
let AesOutput(status, result) = aesenc128kl(input, handle);
*output = result;
status
}
/// Decrypt 10 rounds of unsigned 8-bit integers in `input` using 128-bit AES key specified in the
/// 384-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec128kl_u8)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesdec128kl))]
pub unsafe fn _mm_aesdec128kl_u8(output: *mut __m128i, input: __m128i, handle: *const u8) -> u8 {
let AesOutput(status, result) = aesdec128kl(input, handle);
*output = result;
status
}
/// Encrypt 14 rounds of unsigned 8-bit integers in `input` using 256-bit AES key specified in the
/// 512-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc256kl_u8)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesenc256kl))]
pub unsafe fn _mm_aesenc256kl_u8(output: *mut __m128i, input: __m128i, handle: *const u8) -> u8 {
let AesOutput(status, result) = aesenc256kl(input, handle);
*output = result;
status
}
/// Decrypt 14 rounds of unsigned 8-bit integers in `input` using 256-bit AES key specified in the
/// 512-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec256kl_u8)
#[inline]
#[target_feature(enable = "kl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesdec256kl))]
pub unsafe fn _mm_aesdec256kl_u8(output: *mut __m128i, input: __m128i, handle: *const u8) -> u8 {
let AesOutput(status, result) = aesdec256kl(input, handle);
*output = result;
status
}
/// Encrypt 10 rounds of 8 groups of unsigned 8-bit integers in `input` using 128-bit AES key specified
/// in the 384-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesencwide128kl_u8)
#[inline]
#[target_feature(enable = "widekl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesencwide128kl))]
pub unsafe fn _mm_aesencwide128kl_u8(
output: *mut __m128i,
input: *const __m128i,
handle: *const u8,
) -> u8 {
let input = &*ptr::slice_from_raw_parts(input, 8);
let WideAesOutput(status, out0, out1, out2, out3, out4, out5, out6, out7) = aesencwide128kl(
handle, input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
);
*output.cast() = [out0, out1, out2, out3, out4, out5, out6, out7];
status
}
/// Decrypt 10 rounds of 8 groups of unsigned 8-bit integers in `input` using 128-bit AES key specified
/// in the 384-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdecwide128kl_u8)
#[inline]
#[target_feature(enable = "widekl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesdecwide128kl))]
pub unsafe fn _mm_aesdecwide128kl_u8(
output: *mut __m128i,
input: *const __m128i,
handle: *const u8,
) -> u8 {
let input = &*ptr::slice_from_raw_parts(input, 8);
let WideAesOutput(status, out0, out1, out2, out3, out4, out5, out6, out7) = aesdecwide128kl(
handle, input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
);
*output.cast() = [out0, out1, out2, out3, out4, out5, out6, out7];
status
}
/// Encrypt 14 rounds of 8 groups of unsigned 8-bit integers in `input` using 256-bit AES key specified
/// in the 512-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesencwide256kl_u8)
#[inline]
#[target_feature(enable = "widekl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesencwide256kl))]
pub unsafe fn _mm_aesencwide256kl_u8(
output: *mut __m128i,
input: *const __m128i,
handle: *const u8,
) -> u8 {
let input = &*ptr::slice_from_raw_parts(input, 8);
let WideAesOutput(status, out0, out1, out2, out3, out4, out5, out6, out7) = aesencwide256kl(
handle, input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
);
*output.cast() = [out0, out1, out2, out3, out4, out5, out6, out7];
status
}
/// Decrypt 14 rounds of 8 groups of unsigned 8-bit integers in `input` using 256-bit AES key specified
/// in the 512-bit key handle `handle`. Store the resulting unsigned 8-bit integers into the corresponding
/// elements of `output`. Returns `0` if the operation was successful, and `1` if the operation failed
/// due to a handle violation.
///
/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdecwide256kl_u8)
#[inline]
#[target_feature(enable = "widekl")]
#[stable(feature = "keylocker_x86", since = "1.89.0")]
#[cfg_attr(test, assert_instr(aesdecwide256kl))]
pub unsafe fn _mm_aesdecwide256kl_u8(
output: *mut __m128i,
input: *const __m128i,
handle: *const u8,
) -> u8 {
let input = &*ptr::slice_from_raw_parts(input, 8);
let WideAesOutput(status, out0, out1, out2, out3, out4, out5, out6, out7) = aesdecwide256kl(
handle, input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7],
);
*output.cast() = [out0, out1, out2, out3, out4, out5, out6, out7];
status
}
#[cfg(test)]
mod tests {
use crate::core_arch::x86::*;
use stdarch_test::simd_test;
#[target_feature(enable = "kl")]
unsafe fn encodekey128() -> [u8; 48] {
let mut handle = [0; 48];
let _ = _mm_encodekey128_u32(0, _mm_setzero_si128(), handle.as_mut_ptr());
handle
}
#[target_feature(enable = "kl")]
unsafe fn encodekey256() -> [u8; 64] {
let mut handle = [0; 64];
let _ = _mm_encodekey256_u32(
0,
_mm_setzero_si128(),
_mm_setzero_si128(),
handle.as_mut_ptr(),
);
handle
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_encodekey128_u32() {
encodekey128();
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_encodekey256_u32() {
encodekey256();
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_aesenc128kl_u8() {
let mut buffer = _mm_setzero_si128();
let key = encodekey128();
for _ in 0..100 {
let status = _mm_aesenc128kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesdec128kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
assert_eq_m128i(buffer, _mm_setzero_si128());
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_aesdec128kl_u8() {
let mut buffer = _mm_setzero_si128();
let key = encodekey128();
for _ in 0..100 {
let status = _mm_aesdec128kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesenc128kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
assert_eq_m128i(buffer, _mm_setzero_si128());
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_aesenc256kl_u8() {
let mut buffer = _mm_setzero_si128();
let key = encodekey256();
for _ in 0..100 {
let status = _mm_aesenc256kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesdec256kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
assert_eq_m128i(buffer, _mm_setzero_si128());
}
#[simd_test(enable = "kl")]
unsafe fn test_mm_aesdec256kl_u8() {
let mut buffer = _mm_setzero_si128();
let key = encodekey256();
for _ in 0..100 {
let status = _mm_aesdec256kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesenc256kl_u8(&mut buffer, buffer, key.as_ptr());
assert_eq!(status, 0);
}
assert_eq_m128i(buffer, _mm_setzero_si128());
}
#[simd_test(enable = "widekl")]
unsafe fn test_mm_aesencwide128kl_u8() {
let mut buffer = [_mm_setzero_si128(); 8];
let key = encodekey128();
for _ in 0..100 {
let status = _mm_aesencwide128kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesdecwide128kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for elem in buffer {
assert_eq_m128i(elem, _mm_setzero_si128());
}
}
#[simd_test(enable = "widekl")]
unsafe fn test_mm_aesdecwide128kl_u8() {
let mut buffer = [_mm_setzero_si128(); 8];
let key = encodekey128();
for _ in 0..100 {
let status = _mm_aesdecwide128kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesencwide128kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for elem in buffer {
assert_eq_m128i(elem, _mm_setzero_si128());
}
}
#[simd_test(enable = "widekl")]
unsafe fn test_mm_aesencwide256kl_u8() {
let mut buffer = [_mm_setzero_si128(); 8];
let key = encodekey256();
for _ in 0..100 {
let status = _mm_aesencwide256kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesdecwide256kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for elem in buffer {
assert_eq_m128i(elem, _mm_setzero_si128());
}
}
#[simd_test(enable = "widekl")]
unsafe fn test_mm_aesdecwide256kl_u8() {
let mut buffer = [_mm_setzero_si128(); 8];
let key = encodekey256();
for _ in 0..100 {
let status = _mm_aesdecwide256kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for _ in 0..100 {
let status = _mm_aesencwide256kl_u8(buffer.as_mut_ptr(), buffer.as_ptr(), key.as_ptr());
assert_eq!(status, 0);
}
for elem in buffer {
assert_eq_m128i(elem, _mm_setzero_si128());
}
}
}