-
Notifications
You must be signed in to change notification settings - Fork 154
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
1 parent
ad109f3
commit 90897dd
Showing
4 changed files
with
175 additions
and
4 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
use core::ops::{Div, Mul}; | ||
|
||
use aead::{array::Array, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser}; | ||
use cipher::{consts::U2, BlockCipherEncrypt, BlockSizeUser}; | ||
|
||
use crate::{Aes256, Aes256Gcm, Nonce, Tag}; | ||
|
||
/// XAES-256-GCM | ||
#[derive(Clone)] | ||
pub struct XaesGcm256 { | ||
aes: Aes256, | ||
k1: Block, | ||
} | ||
|
||
type KeySize = <Aes256Gcm as KeySizeUser>::KeySize; | ||
type NonceSize = <<Aes256Gcm as AeadCore>::NonceSize as Mul<U2>>::Output; | ||
type TagSize = <Aes256Gcm as AeadCore>::TagSize; | ||
type CiphertextOverhead = <Aes256Gcm as AeadCore>::CiphertextOverhead; | ||
type Block = Array<u8, <Aes256 as BlockSizeUser>::BlockSize>; | ||
|
||
/// Maximum length of plaintext. | ||
pub const P_MAX: u64 = 1 << 36; | ||
|
||
/// Maximum length of associated data. | ||
// pub const A_MAX: u64 = 1 << 61; | ||
pub const A_MAX: u64 = 1 << 36; | ||
|
||
/// Maximum length of ciphertext. | ||
pub const C_MAX: u64 = (1 << 36) + 16; | ||
|
||
impl AeadCore for XaesGcm256 { | ||
type NonceSize = NonceSize; | ||
type TagSize = TagSize; | ||
type CiphertextOverhead = CiphertextOverhead; | ||
} | ||
|
||
impl KeySizeUser for XaesGcm256 { | ||
type KeySize = KeySize; | ||
} | ||
|
||
impl KeyInit for XaesGcm256 { | ||
// Implements step 1 and 2 of the spec. | ||
fn new(key: &Key<Aes256>) -> Self { | ||
let aes = Aes256::new(key); | ||
|
||
// L = AES-256ₖ(0¹²⁸) | ||
let mut k1 = Block::default(); | ||
aes.encrypt_block(&mut k1); | ||
|
||
// If MSB₁(L) = 0 then K1 = L << 1 Else K1 = (L << 1) ⊕ 0¹²⁰10000111 | ||
let mut msb = 0; | ||
for i in (0..k1.len()).rev() { | ||
let new_msb = k1[i] >> 7; | ||
k1[i] = (k1[i] << 1) | msb; | ||
msb = new_msb; | ||
} | ||
|
||
let b = k1.len() - 1; | ||
k1[b] ^= msb * 0b10000111; | ||
|
||
Self { aes, k1 } | ||
} | ||
} | ||
|
||
impl AeadInPlace for XaesGcm256 { | ||
fn encrypt_in_place_detached( | ||
&self, | ||
nonce: &Nonce<NonceSize>, | ||
associated_data: &[u8], | ||
buffer: &mut [u8], | ||
) -> Result<Tag<TagSize>, Error> { | ||
if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { | ||
return Err(Error); | ||
} | ||
|
||
let (n1, n) = nonce.split_ref::<<NonceSize as Div<U2>>::Output>(); | ||
let k = self.derive_key(n1); | ||
Aes256Gcm::new(&k).encrypt_in_place_detached(n, associated_data, buffer) | ||
} | ||
|
||
fn decrypt_in_place_detached( | ||
&self, | ||
nonce: &Nonce<NonceSize>, | ||
associated_data: &[u8], | ||
buffer: &mut [u8], | ||
tag: &Tag<TagSize>, | ||
) -> Result<(), Error> { | ||
if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { | ||
return Err(Error); | ||
} | ||
|
||
let (n1, n) = nonce.split_ref::<<NonceSize as Div<U2>>::Output>(); | ||
let k = self.derive_key(n1); | ||
Aes256Gcm::new(&k).decrypt_in_place_detached(n, associated_data, buffer, tag) | ||
} | ||
} | ||
|
||
impl XaesGcm256 { | ||
// Implements steps 3 - 5 of the spec. | ||
fn derive_key(&self, n1: &Nonce<<NonceSize as Div<U2>>::Output>) -> Key<Aes256Gcm> { | ||
// M1 = 0x00 || 0x01 || X || 0x00 || N[:12] | ||
let mut m1 = Block::default(); | ||
m1[..4].copy_from_slice(&[0, 1, b'X', 0]); | ||
m1[4..].copy_from_slice(n1); | ||
|
||
// M2 = 0x00 || 0x02 || X || 0x00 || N[:12] | ||
let mut m2 = Block::default(); | ||
m2[..4].copy_from_slice(&[0, 2, b'X', 0]); | ||
m2[4..].copy_from_slice(n1); | ||
|
||
// Kₘ = AES-256ₖ(M1 ⊕ K1) | ||
// Kₙ = AES-256ₖ(M2 ⊕ K1) | ||
// Kₓ = Kₘ || Kₙ = AES-256ₖ(M1 ⊕ K1) || AES-256ₖ(M2 ⊕ K1) | ||
let mut key: Key<Aes256Gcm> = Array::default(); | ||
let (mut km, mut kn) = key.split_ref_mut::<<KeySize as Div<U2>>::Output>(); | ||
for i in 0..km.len() { | ||
km[i] = m1[i] ^ self.k1[i]; | ||
} | ||
for i in 0..kn.len() { | ||
kn[i] = m2[i] ^ self.k1[i]; | ||
} | ||
|
||
self.aes.encrypt_block(&mut km); | ||
self.aes.encrypt_block(&mut kn); | ||
key | ||
} | ||
} |
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,35 @@ | ||
//! XAES-256-GCM test vectors | ||
|
||
#![cfg(all(feature = "aes", feature = "alloc"))] | ||
|
||
#[macro_use] | ||
mod common; | ||
|
||
use aes_gcm::aead::{array::Array, Aead, AeadInPlace, KeyInit, Payload}; | ||
use aes_gcm::XaesGcm256; | ||
use common::TestVector; | ||
use hex_literal::hex; | ||
|
||
/// C2SP XAES-256-GCM test vectors | ||
/// | ||
/// <https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md> | ||
const TEST_VECTORS: &[TestVector<[u8; 32]>] = &[ | ||
TestVector { | ||
key: &hex!("0101010101010101010101010101010101010101010101010101010101010101"), | ||
nonce: b"ABCDEFGHIJKLMNOPQRSTUVWX", | ||
plaintext: b"XAES-256-GCM", | ||
aad: b"", | ||
ciphertext: &hex!("ce546ef63c9cc60765923609"), | ||
tag: &hex!("b33a9a1974e96e52daf2fcf7075e2271"), | ||
}, | ||
TestVector { | ||
key: &hex!("0303030303030303030303030303030303030303030303030303030303030303"), | ||
nonce: b"ABCDEFGHIJKLMNOPQRSTUVWX", | ||
plaintext: b"XAES-256-GCM", | ||
aad: b"c2sp.org/XAES-256-GCM", | ||
ciphertext: &hex!("986ec1832593df5443a17943"), | ||
tag: &hex!("7fd083bf3fdb41abd740a21f71eb769d"), | ||
}, | ||
]; | ||
|
||
tests!(XaesGcm256, TEST_VECTORS); |