-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
748 additions
and
948 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
use crate::{IV_LEN, SEMIBLOCK_SIZE}; | ||
use aes::cipher::{ | ||
typenum::U16, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, | ||
BlockCipherEncClosure, BlockSizeUser, | ||
}; | ||
|
||
pub(crate) struct Ctx<'a> { | ||
pub(crate) blocks_len: usize, | ||
pub(crate) block: &'a mut Block<Self>, | ||
pub(crate) buf: &'a mut [u8], | ||
} | ||
|
||
impl BlockSizeUser for Ctx<'_> { | ||
type BlockSize = U16; | ||
} | ||
|
||
/// Very similar to the W(S) function defined by NIST in SP 800-38F, Section 6.1 | ||
impl BlockCipherEncClosure for Ctx<'_> { | ||
#[inline(always)] | ||
fn call<B: BlockCipherEncBackend<BlockSize = U16>>(self, backend: &B) { | ||
for j in 0..=5 { | ||
for (i, chunk) in self.buf.chunks_mut(SEMIBLOCK_SIZE).skip(1).enumerate() { | ||
// A | R[i] | ||
self.block[IV_LEN..].copy_from_slice(chunk); | ||
// B = AES(K, ..) | ||
backend.encrypt_block(self.block.into()); | ||
|
||
// A = MSB(64, B) ^ t | ||
let t = (self.blocks_len * j + (i + 1)) as u64; | ||
for (ai, ti) in self.block[..IV_LEN].iter_mut().zip(&t.to_be_bytes()) { | ||
*ai ^= ti; | ||
} | ||
|
||
// R[i] = LSB(64, B) | ||
chunk.copy_from_slice(&self.block[IV_LEN..]); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Very similar to the W^-1(S) function defined by NIST in SP 800-38F, Section 6.1 | ||
impl BlockCipherDecClosure for Ctx<'_> { | ||
#[inline(always)] | ||
fn call<B: BlockCipherDecBackend<BlockSize = U16>>(self, backend: &B) { | ||
for j in (0..=5).rev() { | ||
for (i, chunk) in self.buf.chunks_mut(SEMIBLOCK_SIZE).enumerate().rev() { | ||
// A ^ t | ||
let t = (self.blocks_len * j + (i + 1)) as u64; | ||
for (ai, ti) in self.block[..IV_LEN].iter_mut().zip(&t.to_be_bytes()) { | ||
*ai ^= ti; | ||
} | ||
|
||
// (A ^ t) | R[i] | ||
self.block[IV_LEN..].copy_from_slice(chunk); | ||
|
||
// B = AES-1(K, ..) | ||
backend.decrypt_block(self.block.into()); | ||
|
||
// A = MSB(64, B) | ||
// already set | ||
|
||
// R[i] = LSB(64, B) | ||
chunk.copy_from_slice(&self.block[IV_LEN..]); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
use crate::{ctx::Ctx, Error, IV_LEN, SEMIBLOCK_SIZE}; | ||
use aes::cipher::{ | ||
crypto_common::{InnerInit, InnerUser}, | ||
typenum::U16, | ||
Block, BlockCipherDecrypt, BlockCipherEncrypt, | ||
}; | ||
|
||
/// Default Initial Value for AES-KW as defined in RFC3394 § 2.2.3.1. | ||
/// | ||
/// <https://datatracker.ietf.org/doc/html/rfc3394#section-2.2.3.1> | ||
/// | ||
/// ```text | ||
/// The default initial value (IV) is defined to be the hexadecimal | ||
/// constant: | ||
/// | ||
/// A[0] = IV = A6A6A6A6A6A6A6A6 | ||
/// | ||
/// The use of a constant as the IV supports a strong integrity check on | ||
/// the key data during the period that it is wrapped. If unwrapping | ||
/// produces A[0] = A6A6A6A6A6A6A6A6, then the chance that the key data | ||
/// is corrupt is 2^-64. If unwrapping produces A[0] any other value, | ||
/// then the unwrap must return an error and not return any key data. | ||
/// ``` | ||
const IV: [u8; IV_LEN] = [0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6]; | ||
|
||
/// AES Key Wrapper (KW), as defined in [RFC 3394]. | ||
/// | ||
/// [RFC 3394]: https://www.rfc-editor.org/rfc/rfc3394.txt | ||
#[derive(Debug, Clone, Copy, PartialEq)] | ||
pub struct AesKw<C> { | ||
cipher: C, | ||
} | ||
|
||
impl<C> InnerUser for AesKw<C> { | ||
type Inner = C; | ||
} | ||
|
||
impl<C> InnerInit for AesKw<C> { | ||
#[inline] | ||
fn inner_init(cipher: Self::Inner) -> Self { | ||
AesKw { cipher } | ||
} | ||
} | ||
|
||
impl<C: BlockCipherEncrypt<BlockSize = U16>> AesKw<C> { | ||
/// Wrap `data` and write result to `buf`. | ||
/// | ||
/// Returns slice which points to `buf` and contains wrapped data. | ||
/// | ||
/// Length of `data` must be multiple of [`SEMIBLOCK_SIZE`] and bigger than zero. | ||
/// Length of `buf` must be bigger or equal to `data.len() + IV_LEN`. | ||
#[inline] | ||
pub fn wrap<'a>(&self, data: &[u8], buf: &'a mut [u8]) -> Result<&'a [u8], Error> { | ||
let blocks_len = data.len() / SEMIBLOCK_SIZE; | ||
let blocks_rem = data.len() % SEMIBLOCK_SIZE; | ||
if blocks_rem != 0 { | ||
return Err(Error::InvalidDataSize); | ||
} | ||
|
||
let expected_len = data.len() + IV_LEN; | ||
let buf = buf | ||
.get_mut(..expected_len) | ||
.ok_or(Error::InvalidOutputSize { expected_len })?; | ||
|
||
// 1) Initialize variables | ||
|
||
// Set A to the IV | ||
let block = &mut Block::<C>::default(); | ||
block[..IV_LEN].copy_from_slice(&IV); | ||
|
||
// 2) Calculate intermediate values | ||
buf[IV_LEN..].copy_from_slice(data); | ||
|
||
self.cipher.encrypt_with_backend(Ctx { | ||
blocks_len, | ||
block, | ||
buf, | ||
}); | ||
|
||
// 3) Output the results | ||
buf[..IV_LEN].copy_from_slice(&block[..IV_LEN]); | ||
|
||
Ok(buf) | ||
} | ||
} | ||
|
||
impl<C: BlockCipherDecrypt<BlockSize = U16>> AesKw<C> { | ||
/// Unwrap `data` and write result to `buf`. | ||
/// | ||
/// Returns slice which points to `buf` and contains unwrapped data. | ||
/// | ||
/// Length of `data` must be multiple of [`SEMIBLOCK_SIZE`] and bigger than zero. | ||
/// Length of `buf` must be bigger or equal to `data.len()`. | ||
#[inline] | ||
pub fn unwrap<'a>(&self, data: &[u8], buf: &'a mut [u8]) -> Result<&'a [u8], Error> { | ||
let blocks_len = data.len() / SEMIBLOCK_SIZE; | ||
let blocks_rem = data.len() % SEMIBLOCK_SIZE; | ||
if blocks_rem != 0 || blocks_len < 1 { | ||
return Err(Error::InvalidDataSize); | ||
} | ||
|
||
// 0) Prepare inputs | ||
|
||
let blocks_len = blocks_len - 1; | ||
|
||
let expected_len = blocks_len * SEMIBLOCK_SIZE; | ||
let buf = buf | ||
.get_mut(..expected_len) | ||
.ok_or(Error::InvalidOutputSize { expected_len })?; | ||
|
||
// 1) Initialize variables | ||
|
||
let block = &mut Block::<C>::default(); | ||
block[..IV_LEN].copy_from_slice(&data[..IV_LEN]); | ||
|
||
// for i = 1 to n: R[i] = C[i] | ||
buf.copy_from_slice(&data[IV_LEN..]); | ||
|
||
// 2) Calculate intermediate values | ||
|
||
self.cipher.decrypt_with_backend(Ctx { | ||
blocks_len, | ||
block, | ||
buf, | ||
}); | ||
|
||
// 3) Output the results | ||
|
||
let expected_iv = u64::from_ne_bytes(IV); | ||
let calc_iv = u64::from_ne_bytes(block[..IV_LEN].try_into().unwrap()); | ||
if calc_iv == expected_iv { | ||
Ok(buf) | ||
} else { | ||
buf.fill(0); | ||
Err(Error::IntegrityCheckFailed) | ||
} | ||
} | ||
} |
Oops, something went wrong.