1use cipher::{
2 Block, BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, Iv, Key, KeyInit, KeyIvInit,
3 KeySizeUser, IvSizeUser, Array, typenum::{U16, U32, U64, U128, Sum, Unsigned}
4};
5use hybrid_array::ArraySize;
6use core::fmt;
7
8#[cfg(feature = "zeroize")]
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Error {
14 DataTooShort,
16}
17
18impl fmt::Display for Error {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 Self::DataTooShort => write!(f, "Data must be at least one block size for EME2"),
22 }
23 }
24}
25
26impl core::error::Error for Error {}
27
28#[inline]
29fn xor_blocks<C: BlockSizeUser>(out: &mut Block<C>, a: &Block<C>, b: &Block<C>) {
30 for (o, (x, y)) in out.iter_mut().zip(a.iter().zip(b.iter())) {
31 *o = *x ^ *y;
32 }
33}
34
35#[inline]
36fn xor_into<C: BlockSizeUser>(out: &mut Block<C>, b: &Block<C>) {
37 for (o, x) in out.iter_mut().zip(b.iter()) {
38 *o ^= *x;
39 }
40}
41
42pub trait EmePoly: ArraySize {
44 fn mult_by_two(val: &Array<u8, Self>) -> Array<u8, Self>;
46}
47
48macro_rules! impl_eme_poly {
50 ($size:ty, $limbs:expr, $mask_bytes:expr) => {
51 impl EmePoly for $size {
52 #[inline]
53 fn mult_by_two(val: &Array<u8, Self>) -> Array<u8, Self> {
54 let mut res = Array::<u8, Self>::default();
55 let mut v = [0u64; $limbs];
56
57 for i in 0..$limbs {
59 let mut buf = [0u8; 8];
60 buf.copy_from_slice(&val[i * 8..(i + 1) * 8]);
61 v[i] = u64::from_le_bytes(buf);
62 }
63
64 let carry_out = (v[$limbs - 1] >> 63) as u8;
66 for i in (1..$limbs).rev() {
67 v[i] = (v[i] << 1) | (v[i - 1] >> 63);
68 }
69 v[0] <<= 1;
70
71 for i in 0..$limbs {
73 res[i * 8..(i + 1) * 8].copy_from_slice(&v[i].to_le_bytes());
74 }
75
76 let mask_val = 0u8.wrapping_sub(carry_out);
78 let mask: &[u8] = &$mask_bytes;
79 for (r, &m) in res.iter_mut().zip(mask.iter()) {
80 *r ^= m & mask_val;
81 }
82 res
83 }
84 }
85 };
86}
87
88impl_eme_poly!(U16, 2, [0x87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
89impl_eme_poly!(
90 U32,
91 4,
92 [
93 0x25, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
94 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
95 ]
96);
97impl_eme_poly!(
98 U64,
99 8,
100 [
101 0x25, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
105 ]
106);
107impl_eme_poly!(
108 U128,
109 16,
110 [
111 0xa3, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
119 ]
120);
121
122#[inline]
123fn encrypt_block<C>(cipher: &C, block: &mut Block<C>)
124where
125 C: BlockCipherEncrypt + BlockSizeUser,
126{
127 cipher.encrypt_block(block);
128}
129
130#[inline]
131fn decrypt_block<C>(cipher: &C, block: &mut Block<C>)
132where
133 C: BlockCipherDecrypt + BlockSizeUser,
134{
135 cipher.decrypt_block(block);
136}
137
138#[derive(Clone)]
140#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))]
141pub struct Eme2<C>
142where
143 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser,
144 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
145 Sum<C::BlockSize, C::BlockSize>: ArraySize,
146{
147 #[cfg_attr(feature = "zeroize", zeroize(skip))]
148 cipher: C,
149 key2: Block<C>,
150 key3: Block<C>,
151 tweak: Block<C>,
152}
153
154impl<C> BlockSizeUser for Eme2<C>
155where
156 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser,
157 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
158 Sum<C::BlockSize, C::BlockSize>: ArraySize,
159{
160 type BlockSize = C::BlockSize;
161}
162
163impl<C> IvSizeUser for Eme2<C>
164where
165 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser,
166 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
167 Sum<C::BlockSize, C::BlockSize>: ArraySize,
168{
169 type IvSize = C::BlockSize;
170}
171
172impl<C> KeySizeUser for Eme2<C>
173where
174 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser,
175 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
176 Sum<C::BlockSize, C::BlockSize>: ArraySize,
177 C::KeySize: core::ops::Add<Sum<C::BlockSize, C::BlockSize>>,
178 Sum<C::KeySize, Sum<C::BlockSize, C::BlockSize>>: ArraySize,
179{
180 type KeySize = Sum<C::KeySize, Sum<C::BlockSize, C::BlockSize>>;
181}
182
183impl<C> KeyInit for Eme2<C>
184where
185 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeyInit,
186 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
187 Sum<C::BlockSize, C::BlockSize>: ArraySize,
188 C::KeySize: core::ops::Add<Sum<C::BlockSize, C::BlockSize>>,
189 Sum<C::KeySize, Sum<C::BlockSize, C::BlockSize>>: ArraySize,
190{
191 fn new(key: &Key<Self>) -> Self {
192 let bs = C::BlockSize::USIZE;
193 let ks = C::KeySize::USIZE;
194
195 let mut key1 = Key::<C>::default();
196 key1.copy_from_slice(&key[..ks]);
197
198 let mut key2 = Block::<C>::default();
199 key2.copy_from_slice(&key[ks..ks + bs]);
200
201 let mut key3 = Block::<C>::default();
202 key3.copy_from_slice(&key[ks + bs..ks + 2 * bs]);
203
204 let cipher = C::new(&key1);
205 let tweak = Block::<C>::default();
206
207 #[cfg(feature = "zeroize")]
208 {
209 let mut key1_mut = key1;
210 key1_mut.zeroize();
211 }
212
213 Self {
214 cipher,
215 key2,
216 key3,
217 tweak,
218 }
219 }
220}
221
222impl<C> KeyIvInit for Eme2<C>
223where
224 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeyInit,
225 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
226 Sum<C::BlockSize, C::BlockSize>: ArraySize,
227 C::KeySize: core::ops::Add<Sum<C::BlockSize, C::BlockSize>>,
228 Sum<C::KeySize, Sum<C::BlockSize, C::BlockSize>>: ArraySize,
229{
230 #[inline]
231 fn new(key: &Key<Self>, iv: &Iv<Self>) -> Self {
232 let mut mode = <Self as KeyInit>::new(key);
233 mode.tweak = mode.hash_ad(iv.as_slice());
234 mode
235 }
236}
237
238impl<C> cipher::AlgorithmName for Eme2<C>
239where
240 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser + cipher::AlgorithmName,
241 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
242 Sum<C::BlockSize, C::BlockSize>: ArraySize,
243{
244 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 f.write_str("Eme2<")?;
246 <C as cipher::AlgorithmName>::write_alg_name(f)?;
247 f.write_str(">")
248 }
249}
250
251impl<C> fmt::Debug for Eme2<C>
252where
253 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser + cipher::AlgorithmName,
254 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
255 Sum<C::BlockSize, C::BlockSize>: ArraySize,
256{
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 f.write_str("Eme2<")?;
259 <C as cipher::AlgorithmName>::write_alg_name(f)?;
260 f.write_str("> { ... }")
261 }
262}
263
264impl<C> Eme2<C>
265where
266 C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser + KeySizeUser,
267 C::BlockSize: EmePoly + core::ops::Add<C::BlockSize>,
268 Sum<C::BlockSize, C::BlockSize>: ArraySize,
269{
270 pub fn hash_ad(&self, ad: &[u8]) -> Block<C> {
272 let bs = C::BlockSize::USIZE;
273 let mut t_star = Block::<C>::default();
274 if ad.is_empty() {
275 t_star.copy_from_slice(self.key3.as_slice());
276 encrypt_block(&self.cipher, &mut t_star);
277 return t_star;
278 }
279
280 let mut current_key3 = self.key3.clone();
281 let mut tt = Block::<C>::default();
282 let chunks = ad.chunks(bs);
283 let r = chunks.len();
284
285 current_key3 = C::BlockSize::mult_by_two(¤t_key3);
286
287 for (i, chunk) in chunks.enumerate() {
288 let is_last = i == r - 1;
289 if !is_last {
290 let mut block = Block::<C>::default();
291 block.copy_from_slice(chunk);
292 xor_into::<C>(&mut block, ¤t_key3);
293 encrypt_block(&self.cipher, &mut block);
294 xor_into::<C>(&mut block, ¤t_key3);
295 xor_into::<C>(&mut tt, &block);
296 current_key3 = C::BlockSize::mult_by_two(¤t_key3);
297 } else {
298 let mut block = Block::<C>::default();
299 if chunk.len() < bs {
300 block[..chunk.len()].copy_from_slice(chunk);
301 block[chunk.len()] = 0x80;
302 current_key3 = C::BlockSize::mult_by_two(¤t_key3);
303 } else {
304 block.copy_from_slice(chunk);
305 }
306 xor_into::<C>(&mut block, ¤t_key3);
307 encrypt_block(&self.cipher, &mut block);
308 xor_into::<C>(&mut block, ¤t_key3);
309 xor_into::<C>(&mut tt, &block);
310 }
311 }
312
313 #[cfg(feature = "zeroize")]
314 {
315 current_key3.zeroize();
316 }
317
318 tt
319 }
320
321 pub fn tweak(&self) -> &Block<C> {
323 &self.tweak
324 }
325
326 pub fn set_tweak(&mut self, tweak: Block<C>) {
328 self.tweak = tweak;
329 }
330
331 pub fn encrypt(&self, data: &mut [u8]) -> Result<(), Error> {
334 self.encrypt_core(&self.tweak, data)
335 }
336
337 pub fn decrypt(&self, data: &mut [u8]) -> Result<(), Error> {
340 self.decrypt_core(&self.tweak, data)
341 }
342
343 pub fn encrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
346 let t_star = self.hash_ad(associated_data);
347 let res = self.encrypt_core(&t_star, data);
348
349 #[cfg(feature = "zeroize")]
350 {
351 let mut t_star_mut = t_star;
352 t_star_mut.zeroize();
353 }
354
355 res
356 }
357
358 pub fn decrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
361 let t_star = self.hash_ad(associated_data);
362 let res = self.decrypt_core(&t_star, data);
363
364 #[cfg(feature = "zeroize")]
365 {
366 let mut t_star_mut = t_star;
367 t_star_mut.zeroize();
368 }
369
370 res
371 }
372
373 fn encrypt_core(&self, tweak_block: &Block<C>, data: &mut [u8]) -> Result<(), Error> {
374 let bs = C::BlockSize::USIZE;
375 let len = data.len();
376 if len < bs {
377 return Err(Error::DataTooShort);
378 }
379
380 let m = len.div_ceil(bs);
381 let last_full = if len.is_multiple_of(bs) { m } else { m - 1 };
382
383 let mut l_current = self.key2.clone();
385
386 for i in 0..last_full {
387 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
388 xor_into::<C>(block, &l_current);
389 encrypt_block(&self.cipher, block);
390 l_current = C::BlockSize::mult_by_two(&l_current);
391 }
392
393 let mut ppp_m = Block::<C>::default();
394 if last_full < m {
395 let rem = len % bs;
396 ppp_m[..rem].copy_from_slice(&data[last_full * bs..len]);
397 ppp_m[rem] = 0x80;
398 }
399
400 let mut sp = Block::<C>::default();
401 for i in 1..last_full {
402 let ppp_i: &Block<C> = (&data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
403 xor_into::<C>(&mut sp, ppp_i);
404 }
405 if last_full < m {
406 xor_into::<C>(&mut sp, &ppp_m);
407 }
408
409 let ppp_0: &Block<C> = (&data[0..bs]).try_into().expect("slice bounds match");
410
411 let mut mp_1 = Block::<C>::default();
412 xor_blocks::<C>(&mut mp_1, ppp_0, &sp);
413 xor_into::<C>(&mut mp_1, tweak_block);
414
415 let mut mc_1;
416 let mut ccc_m = Block::<C>::default();
417 let mut c_m = Block::<C>::default();
418 let mut mm = Block::<C>::default();
419
420 if last_full < m {
421 mm.copy_from_slice(&mp_1);
422 encrypt_block(&self.cipher, &mut mm);
423 mc_1 = mm.clone();
424 encrypt_block(&self.cipher, &mut mc_1);
425
426 let rem = len % bs;
427 for i in 0..rem {
428 c_m[i] = data[last_full * bs + i] ^ mm[i];
429 }
430 ccc_m[..rem].copy_from_slice(&c_m[..rem]);
431 ccc_m[rem] = 0x80;
432 } else {
433 mc_1 = mp_1.clone();
434 encrypt_block(&self.cipher, &mut mc_1);
435 }
436
437 let mut m_1 = Block::<C>::default();
438 xor_blocks::<C>(&mut m_1, &mp_1, &mc_1);
439
440 let mut current_m_j = m_1.clone();
441 let mut current_m_k = m_1.clone();
442
443 for i in 1..last_full {
445 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
446
447 let k = i & 127;
448 if k == 0 {
449 let mut mp_j = Block::<C>::default();
450 xor_blocks::<C>(&mut mp_j, block, &m_1);
451 let mut mc_j = mp_j.clone();
452 encrypt_block(&self.cipher, &mut mc_j);
453 xor_blocks::<C>(&mut current_m_j, &mp_j, &mc_j);
454 xor_blocks::<C>(block, &mc_j, &m_1);
455 current_m_k = current_m_j.clone();
456
457 #[cfg(feature = "zeroize")]
458 {
459 mp_j.zeroize();
460 mc_j.zeroize();
461 }
462 } else {
463 current_m_k = C::BlockSize::mult_by_two(¤t_m_k);
464 xor_into::<C>(block, ¤t_m_k);
465 }
466 }
467
468 let mut sc = Block::<C>::default();
469 for i in 1..last_full {
470 let ccc_i: &Block<C> = (&data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
471 xor_into::<C>(&mut sc, ccc_i);
472 }
473 if last_full < m {
474 xor_into::<C>(&mut sc, &ccc_m);
475 }
476
477 let mut ccc_0 = Block::<C>::default();
478 xor_blocks::<C>(&mut ccc_0, &mc_1, &sc);
479 xor_into::<C>(&mut ccc_0, tweak_block);
480 data[0..bs].copy_from_slice(&ccc_0);
481
482 l_current = self.key2.clone();
484 for i in 0..last_full {
485 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
486 encrypt_block(&self.cipher, block);
487 xor_into::<C>(block, &l_current);
488 l_current = C::BlockSize::mult_by_two(&l_current);
489 }
490
491 if last_full < m {
492 let rem = len % bs;
493 data[last_full * bs..len].copy_from_slice(&c_m[..rem]);
494 }
495
496 #[cfg(feature = "zeroize")]
497 {
498 l_current.zeroize();
499 ppp_m.zeroize();
500 sp.zeroize();
501 mp_1.zeroize();
502 mc_1.zeroize();
503 ccc_m.zeroize();
504 c_m.zeroize();
505 m_1.zeroize();
506 current_m_j.zeroize();
507 current_m_k.zeroize();
508 sc.zeroize();
509 ccc_0.zeroize();
510 mm.zeroize();
511 }
512
513 Ok(())
514 }
515
516 fn decrypt_core(&self, tweak_block: &Block<C>, data: &mut [u8]) -> Result<(), Error> {
517 let bs = C::BlockSize::USIZE;
518 let len = data.len();
519 if len < bs {
520 return Err(Error::DataTooShort);
521 }
522
523 let m = len.div_ceil(bs);
524 let last_full = if len.is_multiple_of(bs) { m } else { m - 1 };
525
526 let mut l_current = self.key2.clone();
527
528 for i in 0..last_full {
530 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
531 xor_into::<C>(block, &l_current);
532 decrypt_block(&self.cipher, block);
533 l_current = C::BlockSize::mult_by_two(&l_current);
534 }
535
536 let mut ccc_m = Block::<C>::default();
537 if last_full < m {
538 let rem = len % bs;
539 ccc_m[..rem].copy_from_slice(&data[last_full * bs..len]);
540 ccc_m[rem] = 0x80;
541 }
542
543 let mut sc = Block::<C>::default();
544 for i in 1..last_full {
545 let ccc_i: &Block<C> = (&data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
546 xor_into::<C>(&mut sc, ccc_i);
547 }
548 if last_full < m {
549 xor_into::<C>(&mut sc, &ccc_m);
550 }
551
552 let ccc_0: &Block<C> = (&data[0..bs]).try_into().expect("slice bounds match");
553 let mut mc_1 = Block::<C>::default();
554 xor_blocks::<C>(&mut mc_1, ccc_0, &sc);
555 xor_into::<C>(&mut mc_1, tweak_block);
556
557 let mut mp_1;
558 let mut ppp_m = Block::<C>::default();
559 let mut p_m = Block::<C>::default();
560 let mut mm = Block::<C>::default();
561
562 if last_full < m {
563 mm.copy_from_slice(&mc_1);
564 decrypt_block(&self.cipher, &mut mm);
565 mp_1 = mm.clone();
566 decrypt_block(&self.cipher, &mut mp_1);
567
568 let rem = len % bs;
569 for i in 0..rem {
570 p_m[i] = data[last_full * bs + i] ^ mm[i];
571 }
572 ppp_m[..rem].copy_from_slice(&p_m[..rem]);
573 ppp_m[rem] = 0x80;
574 } else {
575 mp_1 = mc_1.clone();
576 decrypt_block(&self.cipher, &mut mp_1);
577 }
578
579 let mut m_1 = Block::<C>::default();
580 xor_blocks::<C>(&mut m_1, &mp_1, &mc_1);
581
582 let mut current_m_j = m_1.clone();
583 let mut current_m_k = m_1.clone();
584
585 for i in 1..last_full {
587 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
588
589 let k = i & 127;
590 if k == 0 {
591 let mut mc_j = Block::<C>::default();
592 xor_blocks::<C>(&mut mc_j, block, &m_1);
593 let mut mp_j = mc_j.clone();
594 decrypt_block(&self.cipher, &mut mp_j);
595 xor_blocks::<C>(&mut current_m_j, &mp_j, &mc_j);
596 xor_blocks::<C>(block, &mp_j, &m_1);
597 current_m_k = current_m_j.clone();
598
599 #[cfg(feature = "zeroize")]
600 {
601 mc_j.zeroize();
602 mp_j.zeroize();
603 }
604 } else {
605 current_m_k = C::BlockSize::mult_by_two(¤t_m_k);
606 xor_into::<C>(block, ¤t_m_k);
607 }
608 }
609
610 let mut sp = Block::<C>::default();
611 for i in 1..last_full {
612 let ppp_i: &Block<C> = (&data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
613 xor_into::<C>(&mut sp, ppp_i);
614 }
615 if last_full < m {
616 xor_into::<C>(&mut sp, &ppp_m);
617 }
618
619 let mut ppp_0 = Block::<C>::default();
620 xor_blocks::<C>(&mut ppp_0, &mp_1, &sp);
621 xor_into::<C>(&mut ppp_0, tweak_block);
622 data[0..bs].copy_from_slice(&ppp_0);
623
624 l_current = self.key2.clone();
626 for i in 0..last_full {
627 let block: &mut Block<C> = (&mut data[i * bs..(i + 1) * bs]).try_into().expect("slice bounds match");
628 decrypt_block(&self.cipher, block);
629 xor_into::<C>(block, &l_current);
630 l_current = C::BlockSize::mult_by_two(&l_current);
631 }
632
633 if last_full < m {
634 let rem = len % bs;
635 data[last_full * bs..len].copy_from_slice(&p_m[..rem]);
636 }
637
638 #[cfg(feature = "zeroize")]
639 {
640 l_current.zeroize();
641 ccc_m.zeroize();
642 sc.zeroize();
643 mc_1.zeroize();
644 mp_1.zeroize();
645 ppp_m.zeroize();
646 p_m.zeroize();
647 m_1.zeroize();
648 current_m_j.zeroize();
649 current_m_k.zeroize();
650 sp.zeroize();
651 ppp_0.zeroize();
652 mm.zeroize();
653 }
654
655 Ok(())
656 }
657}