use aes::Aes256;
use cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
type B = [u8; 16];
fn mult_by_alpha(x: &B) -> B {
let mut y = [0u8; 16];
for i in 0..16 {
y[i] = x[i].wrapping_mul(2);
if i > 0 && x[i - 1] > 127 {
y[i] = y[i].wrapping_add(1);
}
}
if x[15] > 127 {
y[0] ^= 0x87;
}
y
}
fn xor(a: &B, b: &B) -> B {
let mut o = [0u8; 16];
for i in 0..16 {
o[i] = a[i] ^ b[i];
}
o
}
fn enc(c: &Aes256, b: &B) -> B {
let mut t = (*b).into();
c.encrypt_block(&mut t);
t.into()
}
fn dec(c: &Aes256, b: &B) -> B {
let mut t = (*b).into();
c.decrypt_block(&mut t);
t.into()
}
fn t_star(c: &Aes256, key3: &B, t: &[u8]) -> B {
if t.is_empty() {
return enc(c, key3);
}
let mut k3 = mult_by_alpha(key3);
let blocks: Vec<&[u8]> = t.chunks(16).collect();
let r = blocks.len();
let mut acc = [0u8; 16];
for block in blocks.iter().take(r - 1) {
let mut ti = [0u8; 16];
ti.copy_from_slice(block);
acc = xor(&acc, &xor(&enc(c, &xor(&k3, &ti)), &k3));
k3 = mult_by_alpha(&k3);
}
let last = blocks[r - 1];
let mut tr = [0u8; 16];
if last.len() < 16 {
tr[..last.len()].copy_from_slice(last);
tr[last.len()] = 0x80;
k3 = mult_by_alpha(&k3);
} else {
tr.copy_from_slice(last);
}
acc = xor(&acc, &xor(&enc(c, &xor(&k3, &tr)), &k3));
acc
}
#[allow(clippy::many_single_char_names, clippy::needless_range_loop)]
pub fn eme2_encrypt(c: &Aes256, key2: &B, key3: &B, t: &[u8], p: &[u8]) -> Vec<u8> {
let ts = t_star(c, key3, t);
let n = p.len();
let m = n.div_ceil(16);
let lm = if n.is_multiple_of(16) { 16 } else { n % 16 };
let blk = |i: usize| -> &[u8] {
let s = (i - 1) * 16;
&p[s..core::cmp::min(s + 16, n)]
};
let mut ppp: Vec<B> = vec![[0u8; 16]; m + 1];
let mut l = *key2;
for i in 1..m {
let mut pi = [0u8; 16];
pi.copy_from_slice(blk(i));
ppp[i] = enc(c, &xor(&l, &pi));
l = mult_by_alpha(&l);
}
if lm < 16 {
ppp[m][..lm].copy_from_slice(blk(m));
ppp[m][lm] = 0x80;
} else {
let mut pm = [0u8; 16];
pm.copy_from_slice(blk(m));
ppp[m] = enc(c, &xor(&l, &pm));
}
let mut mp = ts;
for pi in ppp.iter().take(m + 1).skip(1) {
mp = xor(&mp, pi);
}
let (mm, mc1) = if lm < 16 {
let mm = enc(c, &mp);
let mc1 = enc(c, &mm);
(mm, mc1)
} else {
([0u8; 16], enc(c, &mp))
};
let m1 = xor(&mp, &mc1);
let mut mrun = m1;
let mut ccc: Vec<B> = vec![[0u8; 16]; m + 1];
let mut cm = [0u8; 16];
for i in 2..=m.saturating_sub(1) {
if (i - 1) % 128 > 0 {
mrun = mult_by_alpha(&mrun);
ccc[i] = xor(&ppp[i], &mrun);
} else {
let mpj = xor(&ppp[i], &m1);
let mcj = enc(c, &mpj);
mrun = xor(&mpj, &mcj);
ccc[i] = xor(&mcj, &m1);
}
}
if lm < 16 {
for i in 0..lm {
cm[i] = blk(m)[i] ^ mm[i];
}
ccc[m][..lm].copy_from_slice(&cm[..lm]);
ccc[m][lm] = 0x80;
} else if !(m - 1).is_multiple_of(128) {
mrun = mult_by_alpha(&mrun);
ccc[m] = xor(&ppp[m], &mrun);
} else {
ccc[m] = xor(&enc(c, &xor(&m1, &ppp[m])), &m1);
}
let mut c1 = xor(&mc1, &ts);
for cc in ccc.iter().take(m + 1).skip(2) {
c1 = xor(&c1, cc);
}
ccc[1] = c1;
let mut out = vec![0u8; n];
let mut l = *key2;
for i in 1..m {
let ci = xor(&enc(c, &ccc[i]), &l);
out[(i - 1) * 16..i * 16].copy_from_slice(&ci);
l = mult_by_alpha(&l);
}
if lm == 16 {
let cmf = xor(&enc(c, &ccc[m]), &l);
out[(m - 1) * 16..].copy_from_slice(&cmf);
} else {
out[(m - 1) * 16..].copy_from_slice(&cm[..lm]);
}
out
}
#[allow(clippy::many_single_char_names, clippy::needless_range_loop)]
pub fn eme2_decrypt(c: &Aes256, key2: &B, key3: &B, t: &[u8], ct: &[u8]) -> Vec<u8> {
let ts = t_star(c, key3, t);
let n = ct.len();
let m = n.div_ceil(16);
let lm = if n.is_multiple_of(16) { 16 } else { n % 16 };
let blk = |i: usize| -> &[u8] {
let s = (i - 1) * 16;
&ct[s..core::cmp::min(s + 16, n)]
};
let mut ccc: Vec<B> = vec![[0u8; 16]; m + 1];
let mut l = *key2;
for i in 1..m {
let mut ci = [0u8; 16];
ci.copy_from_slice(blk(i));
ccc[i] = dec(c, &xor(&l, &ci));
l = mult_by_alpha(&l);
}
if lm < 16 {
ccc[m][..lm].copy_from_slice(blk(m));
ccc[m][lm] = 0x80;
} else {
let mut cmb = [0u8; 16];
cmb.copy_from_slice(blk(m));
ccc[m] = dec(c, &xor(&l, &cmb));
}
let mut mc = ts;
for cc in ccc.iter().take(m + 1).skip(1) {
mc = xor(&mc, cc);
}
let (mm, mp1) = if lm < 16 {
let mm = dec(c, &mc);
let mp1 = dec(c, &mm);
(mm, mp1)
} else {
([0u8; 16], dec(c, &mc))
};
let m1 = xor(&mp1, &mc);
let mut mrun = m1;
let mut ppp: Vec<B> = vec![[0u8; 16]; m + 1];
let mut pm = [0u8; 16];
for i in 2..=m.saturating_sub(1) {
if (i - 1) % 128 > 0 {
mrun = mult_by_alpha(&mrun);
ppp[i] = xor(&ccc[i], &mrun);
} else {
let mcj = xor(&ccc[i], &m1);
let mpj = dec(c, &mcj);
mrun = xor(&mpj, &mcj);
ppp[i] = xor(&mpj, &m1);
}
}
if lm < 16 {
for i in 0..lm {
pm[i] = blk(m)[i] ^ mm[i];
}
ppp[m][..lm].copy_from_slice(&pm[..lm]);
ppp[m][lm] = 0x80;
} else if !(m - 1).is_multiple_of(128) {
mrun = mult_by_alpha(&mrun);
ppp[m] = xor(&ccc[m], &mrun);
} else {
ppp[m] = xor(&dec(c, &xor(&m1, &ccc[m])), &m1);
}
let mut p1 = xor(&mp1, &ts);
for pi in ppp.iter().take(m + 1).skip(2) {
p1 = xor(&p1, pi);
}
ppp[1] = p1;
let mut out = vec![0u8; n];
let mut l = *key2;
for i in 1..m {
let pi = xor(&dec(c, &ppp[i]), &l);
out[(i - 1) * 16..i * 16].copy_from_slice(&pi);
l = mult_by_alpha(&l);
}
if lm == 16 {
let pmf = xor(&dec(c, &ppp[m]), &l);
out[(m - 1) * 16..].copy_from_slice(&pmf);
} else {
out[(m - 1) * 16..].copy_from_slice(&pm[..lm]);
}
out
}
pub fn raw_cipher(key1: &[u8]) -> Aes256 {
Aes256::new_from_slice(key1).expect("key1 is 32 bytes")
}