use cipher::{
Block, BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, Iv, IvSizeUser, Key, KeyInit,
KeyIvInit, KeySizeUser, consts::U16, consts::U32, typenum::Sum,
};
use core::fmt;
use hybrid_array::ArraySize;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
const BLOCK_SIZE: usize = 16;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
DataTooShort,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DataTooShort => write!(f, "Data must be at least 16 bytes for EME2"),
}
}
}
impl core::error::Error for Error {}
#[inline]
fn xor_blocks(out: &mut [u8; BLOCK_SIZE], a: &[u8; BLOCK_SIZE], b: &[u8; BLOCK_SIZE]) {
for i in 0..BLOCK_SIZE {
out[i] = a[i] ^ b[i];
}
}
#[inline]
fn xor_into(out: &mut [u8; BLOCK_SIZE], b: &[u8; BLOCK_SIZE]) {
for (out_byte, b_byte) in out.iter_mut().zip(b.iter()) {
*out_byte ^= *b_byte;
}
}
#[inline]
fn mult_by_two(val: &[u8; BLOCK_SIZE]) -> [u8; BLOCK_SIZE] {
let mut res = [0u8; BLOCK_SIZE];
let mut b0 = [0u8; 8];
b0.copy_from_slice(&val[0..8]);
let mut v0 = u64::from_le_bytes(b0);
let mut b1 = [0u8; 8];
b1.copy_from_slice(&val[8..16]);
let mut v1 = u64::from_le_bytes(b1);
let carry_out = (v1 >> 63) as u8;
v1 = (v1 << 1) | (v0 >> 63);
v0 <<= 1;
res[0..8].copy_from_slice(&v0.to_le_bytes());
res[8..16].copy_from_slice(&v1.to_le_bytes());
let mask = 0u8.wrapping_sub(carry_out);
res[0] ^= 0x87 & mask;
res
}
#[inline]
fn encrypt_block<C>(cipher: &C, block: &mut [u8; 16])
where
C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
{
let mut b: Block<C> = (*block).into();
cipher.encrypt_block(&mut b);
*block = b.into();
}
#[inline]
fn decrypt_block<C>(cipher: &C, block: &mut [u8; 16])
where
C: BlockCipherDecrypt + BlockSizeUser<BlockSize = U16>,
{
let mut b: Block<C> = (*block).into();
cipher.decrypt_block(&mut b);
*block = b.into();
}
#[derive(Clone)]
#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))]
pub struct Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
#[cfg_attr(feature = "zeroize", zeroize(skip))]
cipher: C,
key2: Block<C>,
key3: Block<C>,
tweak: Block<C>,
}
impl<C> BlockSizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type BlockSize = U16;
}
impl<C> KeySizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type KeySize = Sum<C::KeySize, U32>;
}
impl<C> KeyInit for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeyInit,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn new(key: &Key<Self>) -> Self {
let key_bytes = key.as_slice();
let key1_len = key_bytes.len() - 32;
let key1 = &key_bytes[..key1_len];
let key2 = Block::<C>::try_from(&key_bytes[key1_len..key1_len + 16])
.unwrap_or_else(|_| unreachable!());
let key3 =
Block::<C>::try_from(&key_bytes[key1_len + 16..]).unwrap_or_else(|_| unreachable!());
let cipher = C::new_from_slice(key1).unwrap_or_else(|_| unreachable!());
let tweak = Block::<C>::default();
Self {
cipher,
key2,
key3,
tweak,
}
}
}
impl<C> IvSizeUser for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
type IvSize = U16;
}
impl<C> KeyIvInit for Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeyInit,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
#[inline]
fn new(key: &Key<Self>, iv: &Iv<Self>) -> Self {
let mut mode = <Self as KeyInit>::new(key);
mode.tweak = mode.hash_ad(iv.as_slice());
mode
}
}
impl<C> cipher::AlgorithmName for Eme2<C>
where
C: BlockCipherEncrypt
+ BlockCipherDecrypt
+ BlockSizeUser<BlockSize = U16>
+ KeySizeUser
+ cipher::AlgorithmName,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Eme2<")?;
<C as cipher::AlgorithmName>::write_alg_name(f)?;
f.write_str(">")
}
}
impl<C> fmt::Debug for Eme2<C>
where
C: BlockCipherEncrypt
+ BlockCipherDecrypt
+ BlockSizeUser<BlockSize = U16>
+ KeySizeUser
+ cipher::AlgorithmName,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Eme2<")?;
<C as cipher::AlgorithmName>::write_alg_name(f)?;
f.write_str("> { ... }")
}
}
impl<C> Eme2<C>
where
C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16> + KeySizeUser,
C::KeySize: core::ops::Add<U32>,
Sum<C::KeySize, U32>: ArraySize,
{
pub fn hash_ad(&self, ad: &[u8]) -> Block<C> {
self.hash_ad_eme2(ad)
}
pub fn hash_ad_eme2(&self, ad: &[u8]) -> Block<C> {
let mut t_star = [0u8; BLOCK_SIZE];
if ad.is_empty() {
t_star.copy_from_slice(self.key3.as_slice());
encrypt_block(&self.cipher, &mut t_star);
return t_star.into();
}
let mut current_key3 = [0u8; BLOCK_SIZE];
current_key3.copy_from_slice(self.key3.as_slice());
let mut tt = [0u8; BLOCK_SIZE];
let chunks = ad.chunks(BLOCK_SIZE);
let r = chunks.len();
current_key3 = mult_by_two(¤t_key3);
for (i, chunk) in chunks.enumerate() {
let is_last = i == r - 1;
if !is_last {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(chunk);
xor_into(&mut block, ¤t_key3);
encrypt_block(&self.cipher, &mut block);
xor_into(&mut tt, &block);
current_key3 = mult_by_two(¤t_key3);
} else {
let mut block = [0u8; BLOCK_SIZE];
if chunk.len() < BLOCK_SIZE {
block[..chunk.len()].copy_from_slice(chunk);
block[chunk.len()] = 0x80;
current_key3 = mult_by_two(¤t_key3);
} else {
block.copy_from_slice(chunk);
}
xor_into(&mut block, ¤t_key3);
encrypt_block(&self.cipher, &mut block);
xor_into(&mut tt, &block);
}
}
#[cfg(feature = "zeroize")]
{
current_key3.zeroize();
}
tt.into()
}
pub fn hash_ad_emestar(&self, ad: &[u8]) -> Block<C> {
let mut t_star = [0u8; BLOCK_SIZE];
if ad.is_empty() {
t_star.copy_from_slice(self.key3.as_slice());
encrypt_block(&self.cipher, &mut t_star);
return t_star.into();
}
let mut current_key3 = [0u8; BLOCK_SIZE];
current_key3.copy_from_slice(self.key3.as_slice());
let mut tt = [0u8; BLOCK_SIZE];
let chunks = ad.chunks(BLOCK_SIZE);
let r = chunks.len();
current_key3 = mult_by_two(¤t_key3);
for (i, chunk) in chunks.enumerate() {
let is_last = i == r - 1;
if !is_last {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(chunk);
xor_into(&mut block, ¤t_key3);
encrypt_block(&self.cipher, &mut block);
xor_into(&mut block, ¤t_key3);
xor_into(&mut tt, &block);
current_key3 = mult_by_two(¤t_key3);
} else {
let mut block = [0u8; BLOCK_SIZE];
if chunk.len() < BLOCK_SIZE {
block[..chunk.len()].copy_from_slice(chunk);
block[chunk.len()] = 0x80;
current_key3 = mult_by_two(¤t_key3);
} else {
block.copy_from_slice(chunk);
}
xor_into(&mut block, ¤t_key3);
encrypt_block(&self.cipher, &mut block);
xor_into(&mut block, ¤t_key3);
xor_into(&mut tt, &block);
}
}
#[cfg(feature = "zeroize")]
{
current_key3.zeroize();
}
tt.into()
}
pub fn tweak(&self) -> &Block<C> {
&self.tweak
}
pub fn set_tweak(&mut self, tweak: Block<C>) {
self.tweak = tweak;
}
pub fn encrypt(&self, data: &mut [u8]) -> Result<(), Error> {
let tweak_slice: &[u8; 16] = self
.tweak
.as_slice()
.try_into()
.expect("slice bounds match block size");
self.encrypt_core(tweak_slice, data)
}
pub fn decrypt(&self, data: &mut [u8]) -> Result<(), Error> {
let tweak_slice: &[u8; 16] = self
.tweak
.as_slice()
.try_into()
.expect("slice bounds match block size");
self.decrypt_core(tweak_slice, data)
}
pub fn encrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
self.encrypt_with_ad_eme2(associated_data, data)
}
pub fn decrypt_with_ad(&self, associated_data: &[u8], data: &mut [u8]) -> Result<(), Error> {
self.decrypt_with_ad_eme2(associated_data, data)
}
pub fn encrypt_with_ad_eme2(
&self,
associated_data: &[u8],
data: &mut [u8],
) -> Result<(), Error> {
let t_star = self.hash_ad_eme2(associated_data);
let tweak_slice: &[u8; 16] = t_star
.as_slice()
.try_into()
.expect("slice bounds match block size");
let res = self.encrypt_core(tweak_slice, data);
#[cfg(feature = "zeroize")]
{
let mut t_star_mut = t_star;
t_star_mut.zeroize();
}
res
}
pub fn decrypt_with_ad_eme2(
&self,
associated_data: &[u8],
data: &mut [u8],
) -> Result<(), Error> {
let t_star = self.hash_ad_eme2(associated_data);
let tweak_slice: &[u8; 16] = t_star
.as_slice()
.try_into()
.expect("slice bounds match block size");
let res = self.decrypt_core(tweak_slice, data);
#[cfg(feature = "zeroize")]
{
let mut t_star_mut = t_star;
t_star_mut.zeroize();
}
res
}
pub fn encrypt_with_ad_emestar(
&self,
associated_data: &[u8],
data: &mut [u8],
) -> Result<(), Error> {
let t_star = self.hash_ad_emestar(associated_data);
let tweak_slice: &[u8; 16] = t_star
.as_slice()
.try_into()
.expect("slice bounds match block size");
let res = self.encrypt_core(tweak_slice, data);
#[cfg(feature = "zeroize")]
{
let mut t_star_mut = t_star;
t_star_mut.zeroize();
}
res
}
pub fn decrypt_with_ad_emestar(
&self,
associated_data: &[u8],
data: &mut [u8],
) -> Result<(), Error> {
let t_star = self.hash_ad_emestar(associated_data);
let tweak_slice: &[u8; 16] = t_star
.as_slice()
.try_into()
.expect("slice bounds match block size");
let res = self.decrypt_core(tweak_slice, data);
#[cfg(feature = "zeroize")]
{
let mut t_star_mut = t_star;
t_star_mut.zeroize();
}
res
}
fn encrypt_core(&self, tweak_slice: &[u8; 16], data: &mut [u8]) -> Result<(), Error> {
let len = data.len();
if len < BLOCK_SIZE {
return Err(Error::DataTooShort);
}
let m = len.div_ceil(BLOCK_SIZE);
let last_full = if len.is_multiple_of(BLOCK_SIZE) {
m
} else {
m - 1
};
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut block, &l_current);
encrypt_block(&self.cipher, &mut block);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&block);
l_current = mult_by_two(&l_current);
}
let mut ppp_m = [0u8; BLOCK_SIZE];
if last_full < m {
let rem = len % BLOCK_SIZE;
ppp_m[..rem].copy_from_slice(&data[last_full * BLOCK_SIZE..len]);
ppp_m[rem] = 0x80;
}
let mut sp = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sp, &ppp_i);
}
if last_full < m {
xor_into(&mut sp, &ppp_m);
}
let mut ppp_0 = [0u8; BLOCK_SIZE];
ppp_0.copy_from_slice(&data[0..BLOCK_SIZE]);
let mut mp_1 = [0u8; BLOCK_SIZE];
xor_blocks(&mut mp_1, &ppp_0, &sp);
xor_into(&mut mp_1, tweak_slice);
let mut mc_1;
let mut ccc_m = [0u8; BLOCK_SIZE];
let mut c_m = [0u8; BLOCK_SIZE];
let mut mm = [0u8; BLOCK_SIZE];
if last_full < m {
mm.copy_from_slice(&mp_1);
encrypt_block(&self.cipher, &mut mm);
mc_1 = mm;
encrypt_block(&self.cipher, &mut mc_1);
let rem = len % BLOCK_SIZE;
for i in 0..rem {
c_m[i] = data[last_full * BLOCK_SIZE + i] ^ mm[i];
}
ccc_m[..rem].copy_from_slice(&c_m[..rem]);
ccc_m[rem] = 0x80;
} else {
mc_1 = mp_1;
encrypt_block(&self.cipher, &mut mc_1);
}
let mut m_1 = [0u8; BLOCK_SIZE];
xor_blocks(&mut m_1, &mp_1, &mc_1);
let mut current_m_j = m_1;
let mut current_m_k = m_1;
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
let mut ccc_i = [0u8; BLOCK_SIZE];
let k = i & 127;
if k == 0 {
let mut mp_j = [0u8; BLOCK_SIZE];
xor_blocks(&mut mp_j, &ppp_i, &m_1);
let mut mc_j = mp_j;
encrypt_block(&self.cipher, &mut mc_j);
xor_blocks(&mut current_m_j, &mp_j, &mc_j);
xor_blocks(&mut ccc_i, &mc_j, &m_1);
current_m_k = current_m_j;
#[cfg(feature = "zeroize")]
{
mp_j.zeroize();
mc_j.zeroize();
}
} else {
current_m_k = mult_by_two(¤t_m_k);
xor_blocks(&mut ccc_i, &ppp_i, ¤t_m_k);
}
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&ccc_i);
}
let mut sc = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sc, &ccc_i);
}
if last_full < m {
xor_into(&mut sc, &ccc_m);
}
let mut ccc_0 = [0u8; BLOCK_SIZE];
xor_blocks(&mut ccc_0, &mc_1, &sc);
xor_into(&mut ccc_0, tweak_slice);
data[0..BLOCK_SIZE].copy_from_slice(&ccc_0);
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut cc_i = [0u8; BLOCK_SIZE];
cc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
encrypt_block(&self.cipher, &mut cc_i);
xor_into(&mut cc_i, &l_current);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&cc_i);
l_current = mult_by_two(&l_current);
}
if last_full < m {
let rem = len % BLOCK_SIZE;
data[last_full * BLOCK_SIZE..len].copy_from_slice(&c_m[..rem]);
}
#[cfg(feature = "zeroize")]
{
l_current.zeroize();
ppp_m.zeroize();
sp.zeroize();
ppp_0.zeroize();
mp_1.zeroize();
mc_1.zeroize();
ccc_m.zeroize();
c_m.zeroize();
m_1.zeroize();
current_m_j.zeroize();
current_m_k.zeroize();
sc.zeroize();
ccc_0.zeroize();
mm.zeroize();
}
Ok(())
}
fn decrypt_core(&self, tweak_slice: &[u8; 16], data: &mut [u8]) -> Result<(), Error> {
let len = data.len();
if len < BLOCK_SIZE {
return Err(Error::DataTooShort);
}
let m = len.div_ceil(BLOCK_SIZE);
let last_full = if len.is_multiple_of(BLOCK_SIZE) {
m
} else {
m - 1
};
let mut l_current = [0u8; BLOCK_SIZE];
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut block = [0u8; BLOCK_SIZE];
block.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut block, &l_current);
decrypt_block(&self.cipher, &mut block);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&block);
l_current = mult_by_two(&l_current);
}
let mut ccc_m = [0u8; BLOCK_SIZE];
if last_full < m {
let rem = len % BLOCK_SIZE;
ccc_m[..rem].copy_from_slice(&data[last_full * BLOCK_SIZE..len]);
ccc_m[rem] = 0x80;
}
let mut sc = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sc, &ccc_i);
}
if last_full < m {
xor_into(&mut sc, &ccc_m);
}
let mut ccc_0 = [0u8; BLOCK_SIZE];
ccc_0.copy_from_slice(&data[0..BLOCK_SIZE]);
let mut mc_1 = [0u8; BLOCK_SIZE];
xor_blocks(&mut mc_1, &ccc_0, &sc);
xor_into(&mut mc_1, tweak_slice);
let mut mp_1;
let mut ppp_m = [0u8; BLOCK_SIZE];
let mut p_m = [0u8; BLOCK_SIZE];
let mut mm = [0u8; BLOCK_SIZE];
if last_full < m {
mm.copy_from_slice(&mc_1);
decrypt_block(&self.cipher, &mut mm);
mp_1 = mm;
decrypt_block(&self.cipher, &mut mp_1);
let rem = len % BLOCK_SIZE;
for i in 0..rem {
p_m[i] = data[last_full * BLOCK_SIZE + i] ^ mm[i];
}
ppp_m[..rem].copy_from_slice(&p_m[..rem]);
ppp_m[rem] = 0x80;
} else {
mp_1 = mc_1;
decrypt_block(&self.cipher, &mut mp_1);
}
let mut m_1 = [0u8; BLOCK_SIZE];
xor_blocks(&mut m_1, &mp_1, &mc_1);
let mut current_m_j = m_1;
let mut current_m_k = m_1;
for i in 1..last_full {
let mut ccc_i = [0u8; BLOCK_SIZE];
ccc_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
let mut ppp_i = [0u8; BLOCK_SIZE];
let k = i & 127;
if k == 0 {
let mut mc_j = [0u8; BLOCK_SIZE];
xor_blocks(&mut mc_j, &ccc_i, &m_1);
let mut mp_j = mc_j;
decrypt_block(&self.cipher, &mut mp_j);
xor_blocks(&mut current_m_j, &mp_j, &mc_j);
xor_blocks(&mut ppp_i, &mp_j, &m_1);
current_m_k = current_m_j;
#[cfg(feature = "zeroize")]
{
mc_j.zeroize();
mp_j.zeroize();
}
} else {
current_m_k = mult_by_two(¤t_m_k);
xor_blocks(&mut ppp_i, &ccc_i, ¤t_m_k);
}
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&ppp_i);
}
let mut sp = [0u8; BLOCK_SIZE];
for i in 1..last_full {
let mut ppp_i = [0u8; BLOCK_SIZE];
ppp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
xor_into(&mut sp, &ppp_i);
}
if last_full < m {
xor_into(&mut sp, &ppp_m);
}
let mut ppp_0 = [0u8; BLOCK_SIZE];
xor_blocks(&mut ppp_0, &mp_1, &sp);
xor_into(&mut ppp_0, tweak_slice);
data[0..BLOCK_SIZE].copy_from_slice(&ppp_0);
l_current.copy_from_slice(self.key2.as_slice());
for i in 0..last_full {
let mut pp_i = [0u8; BLOCK_SIZE];
pp_i.copy_from_slice(&data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE]);
decrypt_block(&self.cipher, &mut pp_i);
xor_into(&mut pp_i, &l_current);
data[i * BLOCK_SIZE..(i + 1) * BLOCK_SIZE].copy_from_slice(&pp_i);
l_current = mult_by_two(&l_current);
}
if last_full < m {
let rem = len % BLOCK_SIZE;
data[last_full * BLOCK_SIZE..len].copy_from_slice(&p_m[..rem]);
}
#[cfg(feature = "zeroize")]
{
l_current.zeroize();
ccc_m.zeroize();
sc.zeroize();
ccc_0.zeroize();
mc_1.zeroize();
mp_1.zeroize();
ppp_m.zeroize();
p_m.zeroize();
m_1.zeroize();
current_m_j.zeroize();
current_m_k.zeroize();
sp.zeroize();
ppp_0.zeroize();
mm.zeroize();
}
Ok(())
}
}