1#![deny(unsafe_code)]
4
5use aead::consts::U16;
6use aead::inout::InOutBuf;
7use aead::{
8 AeadCore,
9 AeadInOut,
10 Error,
11 Key,
12 KeyInit,
13 KeySizeUser,
14 Nonce,
15 Tag,
16 TagPosition,
17};
18use subtle::ConstantTimeEq;
19use zeroize::Zeroize;
20
21use crate::backend::{
22 AD_BLK_EVN,
23 AD_BLK_ODD,
24 MSG_BLK,
25 ad_encryption,
26 ad2msg_encryption,
27 g8a,
28 lfsr_gf56,
29 msg_decryption_m_inplace,
30 msg_encryption_m_inplace,
31 nonce_encryption,
32 reset_lfsr_gf56,
33 rho,
34 romulus_m_compute_w,
35};
36
37#[derive(Clone)]
39pub struct RomulusM {
40 key: Key<Self>,
41}
42
43impl Drop for RomulusM {
44 fn drop(&mut self) {
45 self.key.as_mut_slice().zeroize();
46 }
47}
48
49impl KeySizeUser for RomulusM {
50 type KeySize = U16;
51}
52
53impl KeyInit for RomulusM {
54 fn new(key: &Key<Self>) -> Self {
55 Self { key: *key }
56 }
57}
58
59impl AeadCore for RomulusM {
60 type NonceSize = U16;
61 type TagSize = U16;
62 const TAG_POSITION: TagPosition = TagPosition::Postfix;
63}
64
65impl AeadInOut for RomulusM {
66 fn encrypt_inout_detached(
67 &self,
68 nonce: &Nonce<Self>,
69 associated_data: &[u8],
70 buffer: InOutBuf<'_, '_, u8>,
71 ) -> Result<Tag<Self>, Error> {
72 let k = crate::stack_secret::zeroizing_copy_16(self.key.as_slice());
73 let n = crate::stack_secret::zeroizing_copy_16(nonce.as_slice());
74 let buffer = buffer.into_out();
77 let tag = romulus_m_encrypt(&k, &n, associated_data, buffer)?;
78 Ok(Tag::<Self>::from(tag))
79 }
80
81 fn decrypt_inout_detached(
82 &self,
83 nonce: &Nonce<Self>,
84 associated_data: &[u8],
85 buffer: InOutBuf<'_, '_, u8>,
86 tag: &Tag<Self>,
87 ) -> Result<(), Error> {
88 let k = crate::stack_secret::zeroizing_copy_16(self.key.as_slice());
89 let n = crate::stack_secret::zeroizing_copy_16(nonce.as_slice());
90 let tg = crate::stack_secret::zeroizing_copy_16(tag.as_slice());
91 let buffer = buffer.into_out();
92 romulus_m_decrypt(&k, &n, associated_data, buffer, &tg)
93 }
94}
95
96pub(crate) fn romulus_m_encrypt(
98 key: &[u8; 16],
99 nonce: &[u8; 16],
100 ad: &[u8],
101 buf: &mut [u8],
102) -> Result<[u8; 16], Error> {
103 let mut s = [0u8; 16];
104 let mut cnt = [0u8; 7];
105 reset_lfsr_gf56(&mut cnt);
106 let n_ad = AD_BLK_ODD;
107 let t_ad = AD_BLK_EVN;
108 let mlen_u = buf.len() as u64;
109 let xlen_init = mlen_u;
110 let mut ad_off = 0usize;
111 let mut adlen = ad.len() as u64;
112
113 let w = romulus_m_compute_w(adlen, xlen_init, n_ad, t_ad);
114
115 if adlen == 0 {
116 lfsr_gf56(&mut cnt);
117 } else {
118 while adlen > 0 {
119 adlen = ad_encryption(
120 ad,
121 &mut ad_off,
122 &mut s,
123 key,
124 adlen,
125 &mut cnt,
126 40,
127 n_ad,
128 t_ad,
129 );
130 }
131 }
132
133 let mut mac_off = 0usize;
134 let mut xlen = mlen_u;
135
136 if w & 8 == 0 {
137 xlen = ad2msg_encryption(buf, &mut mac_off, &mut cnt, &mut s, key, t_ad, 44, xlen);
138 } else if mlen_u == 0 {
139 lfsr_gf56(&mut cnt);
140 }
141
142 while xlen > 0 {
143 xlen = ad_encryption(
144 buf,
145 &mut mac_off,
146 &mut s,
147 key,
148 xlen,
149 &mut cnt,
150 44,
151 n_ad,
152 t_ad,
153 );
154 }
155
156 nonce_encryption(nonce, &mut cnt, &mut s, key, t_ad, w);
157
158 let mut tag = [0u8; 16];
159 g8a(&s, &mut tag);
160
161 reset_lfsr_gf56(&mut cnt);
162 s.copy_from_slice(&tag);
163
164 let msg_n = MSG_BLK;
165 let mut enc_off = 0usize;
166
167 if mlen_u > 0 {
168 nonce_encryption(nonce, &mut cnt, &mut s, key, t_ad, 36);
169 let mut rem = mlen_u;
170 while rem > msg_n as u64 {
171 rem = msg_encryption_m_inplace(
172 buf,
173 &mut enc_off,
174 nonce,
175 &mut cnt,
176 &mut s,
177 key,
178 msg_n,
179 t_ad,
180 36,
181 rem,
182 );
183 }
184 let r = rem as usize;
185 let mut last = [0u8; 16];
186 last[..r].copy_from_slice(&buf[enc_off..enc_off + r]);
187 let mut ctmp = [0u8; 16];
188 rho(&last[..r], &mut ctmp, &mut s, r, 16);
189 buf[enc_off..enc_off + r].copy_from_slice(&ctmp[..r]);
190 }
191
192 Ok(tag)
193}
194
195pub(crate) fn romulus_m_decrypt(
199 key: &[u8; 16],
200 nonce: &[u8; 16],
201 ad: &[u8],
202 ct: &mut [u8],
203 tag: &[u8; 16],
204) -> Result<(), Error> {
205 let ok = romulus_m_decrypt_core(key, nonce, ad, ct, tag);
206 if ok {
207 Ok(())
208 } else {
209 ct.zeroize();
210 Err(Error)
211 }
212}
213
214pub(crate) fn romulus_m_decrypt_core(
216 key: &[u8; 16],
217 nonce: &[u8; 16],
218 ad: &[u8],
219 ct: &mut [u8],
220 tag: &[u8; 16],
221) -> bool {
222 let body_len = ct.len();
223 let xlen = body_len as u64;
224
225 let mut s = [0u8; 16];
226 let mut cnt = [0u8; 7];
227 reset_lfsr_gf56(&mut cnt);
228 let n_ad = AD_BLK_ODD;
229 let t_ad = AD_BLK_EVN;
230
231 s.copy_from_slice(tag);
232
233 let msg_n = MSG_BLK;
234 let mut clen = body_len as u64;
235 let mut off = 0usize;
236
237 if clen > 0 {
238 nonce_encryption(nonce, &mut cnt, &mut s, key, t_ad, 36);
239 while clen > msg_n as u64 {
240 clen = msg_decryption_m_inplace(
241 ct, &mut off, nonce, &mut cnt, &mut s, key, msg_n, t_ad, 36, clen,
242 );
243 }
244 let r = clen as usize;
245 let mut tmp = [0u8; 16];
246 tmp[..r].copy_from_slice(&ct[off..off + r]);
247 let mut ptmp = [0u8; 16];
248 crate::backend::irho(&mut ptmp, &tmp[..r], &mut s, r, 16);
249 ct[off..off + r].copy_from_slice(&ptmp[..r]);
250 }
251
252 s.fill(0);
253 reset_lfsr_gf56(&mut cnt);
254
255 let mut ad_off = 0usize;
256 let mut adlen = ad.len() as u64;
257 let w = romulus_m_compute_w(adlen, xlen, n_ad, t_ad);
258
259 if adlen == 0 {
260 lfsr_gf56(&mut cnt);
261 } else {
262 while adlen > 0 {
263 adlen = ad_encryption(
264 ad,
265 &mut ad_off,
266 &mut s,
267 key,
268 adlen,
269 &mut cnt,
270 40,
271 n_ad,
272 t_ad,
273 );
274 }
275 }
276
277 let mut mac_off = 0usize;
278 let mut xrem = xlen;
279
280 if w & 8 == 0 {
281 xrem = ad2msg_encryption(ct, &mut mac_off, &mut cnt, &mut s, key, t_ad, 44, xrem);
282 } else if body_len == 0 {
283 lfsr_gf56(&mut cnt);
284 }
285
286 while xrem > 0 {
287 xrem = ad_encryption(
288 ct,
289 &mut mac_off,
290 &mut s,
291 key,
292 xrem,
293 &mut cnt,
294 44,
295 n_ad,
296 t_ad,
297 );
298 }
299
300 nonce_encryption(nonce, &mut cnt, &mut s, key, t_ad, w);
301
302 let mut calc = [0u8; 16];
303 g8a(&s, &mut calc);
304 bool::from(calc.ct_eq(tag))
305}