1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![deny(unsafe_code)]
9#![warn(missing_docs, rust_2018_idioms)]
10
11#![cfg_attr(feature = "getrandom", doc = "```")]
16#![cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
17pub use aead;
34pub use aes;
35pub use aes_gcm;
36
37use core::ops::{Div, Mul};
38
39use aead::{
40 AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, TagPosition, array::Array, inout::InOutBuf,
41};
42use aes::Aes256;
43use aes_gcm::Aes256Gcm;
44use cipher::{BlockCipherEncrypt, BlockSizeUser, consts::U2};
45
46#[derive(Clone)]
48pub struct Xaes256Gcm {
49 aes: Aes256,
50 k1: Block,
51}
52
53type KeySize = <Aes256Gcm as KeySizeUser>::KeySize;
54type NonceSize = <<Aes256Gcm as AeadCore>::NonceSize as Mul<U2>>::Output;
55type TagSize = <Aes256Gcm as AeadCore>::TagSize;
56type Block = Array<u8, <Aes256 as BlockSizeUser>::BlockSize>;
57
58pub type Nonce<Size = NonceSize> = aes_gcm::Nonce<Size>;
60
61pub type Key<B = Aes256> = aes_gcm::Key<B>;
63
64pub type Tag<Size = TagSize> = aes_gcm::Tag<Size>;
66
67pub const P_MAX: u64 = 1 << 36;
69
70pub const A_MAX: u64 = 1 << 36;
73
74pub const C_MAX: u64 = (1 << 36) + 16;
76
77impl AeadCore for Xaes256Gcm {
78 type NonceSize = NonceSize;
79 type TagSize = TagSize;
80 const TAG_POSITION: TagPosition = TagPosition::Postfix;
81}
82
83impl KeySizeUser for Xaes256Gcm {
84 type KeySize = KeySize;
85}
86
87impl KeyInit for Xaes256Gcm {
88 fn new(key: &Key) -> Self {
90 let aes = Aes256::new(key);
91
92 let mut k1 = Block::default();
94 aes.encrypt_block(&mut k1);
95
96 let mut msb = 0;
98 for i in (0..k1.len()).rev() {
99 let new_msb = k1[i] >> 7;
100 k1[i] = (k1[i] << 1) | msb;
101 msb = new_msb;
102 }
103
104 let b = k1.len() - 1;
105 k1[b] ^= msb * 0b10000111;
106
107 Self { aes, k1 }
108 }
109}
110
111impl AeadInOut for Xaes256Gcm {
112 fn encrypt_inout_detached(
113 &self,
114 nonce: &Nonce,
115 associated_data: &[u8],
116 buffer: InOutBuf<'_, '_, u8>,
117 ) -> Result<Tag, Error> {
118 if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
119 return Err(Error);
120 }
121
122 let (n1, n) = nonce.split_ref::<<NonceSize as Div<U2>>::Output>();
123 let k = self.derive_key(n1);
124 Aes256Gcm::new(&k).encrypt_inout_detached(n, associated_data, buffer)
125 }
126
127 fn decrypt_inout_detached(
128 &self,
129 nonce: &Nonce,
130 associated_data: &[u8],
131 buffer: InOutBuf<'_, '_, u8>,
132 tag: &Tag,
133 ) -> Result<(), Error> {
134 if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
135 return Err(Error);
136 }
137
138 let (n1, n) = nonce.split_ref::<<NonceSize as Div<U2>>::Output>();
139 let k = self.derive_key(n1);
140 Aes256Gcm::new(&k).decrypt_inout_detached(n, associated_data, buffer, tag)
141 }
142}
143
144impl Xaes256Gcm {
145 fn derive_key(&self, n1: &Nonce<<NonceSize as Div<U2>>::Output>) -> Key<Aes256Gcm> {
147 let mut m1 = Block::default();
149 m1[..4].copy_from_slice(&[0, 1, b'X', 0]);
150 m1[4..].copy_from_slice(n1);
151
152 let mut m2 = Block::default();
154 m2[..4].copy_from_slice(&[0, 2, b'X', 0]);
155 m2[4..].copy_from_slice(n1);
156
157 let mut key: Key<Aes256Gcm> = Array::default();
161 let (km, kn) = key.split_ref_mut::<<KeySize as Div<U2>>::Output>();
162 for i in 0..km.len() {
163 km[i] = m1[i] ^ self.k1[i];
164 }
165 for i in 0..kn.len() {
166 kn[i] = m2[i] ^ self.k1[i];
167 }
168
169 self.aes.encrypt_block(km);
170 self.aes.encrypt_block(kn);
171 key
172 }
173}