use super::big;
use super::big::BIG;
use super::ecp;
use super::ecp::ECP;
use super::rom;
use aes;
use aes::AES;
use hash256::HASH256;
use hash384::HASH384;
use hash512::HASH512;
use rand::RAND;
pub const INVALID_PUBLIC_KEY: isize = -2;
pub const ERROR: isize = -3;
pub const INVALID: isize = -4;
pub const EFS: usize = big::MODBYTES as usize;
pub const EGS: usize = big::MODBYTES as usize;
pub const SHA256: usize = 32;
pub const SHA384: usize = 48;
pub const SHA512: usize = 64;
#[allow(non_snake_case)]
fn inttobytes(n: usize, b: &mut [u8]) {
let mut i = b.len();
let mut m = n;
while m > 0 && i > 0 {
i -= 1;
b[i] = (m & 0xff) as u8;
m /= 256;
}
}
fn hashit(sha: usize, a: &[u8], n: usize, b: Option<&[u8]>, pad: usize, w: &mut [u8]) {
let mut r: [u8; 64] = [0; 64];
if sha == SHA256 {
let mut h = HASH256::new();
h.process_array(a);
if n > 0 {
h.process_num(n as i32)
}
if let Some(x) = b {
h.process_array(x);
}
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
}
if sha == SHA384 {
let mut h = HASH384::new();
h.process_array(a);
if n > 0 {
h.process_num(n as i32)
}
if let Some(x) = b {
h.process_array(x);
}
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
}
if sha == SHA512 {
let mut h = HASH512::new();
h.process_array(a);
if n > 0 {
h.process_num(n as i32)
}
if let Some(x) = b {
h.process_array(x);
}
let hs = h.hash();
for i in 0..sha {
r[i] = hs[i];
}
}
if pad == 0 {
for i in 0..sha {
w[i] = r[i]
}
} else {
if pad <= sha {
for i in 0..pad {
w[i] = r[i]
}
} else {
for i in 0..sha {
w[i + pad - sha] = r[i]
}
for i in 0..(pad - sha) {
w[i] = 0
}
}
}
}
pub fn kdf1(sha: usize, z: &[u8], olen: usize, k: &mut [u8]) {
let hlen = sha;
let mut lk = 0;
let mut cthreshold = olen / hlen;
if olen % hlen != 0 {
cthreshold += 1
}
for counter in 0..cthreshold {
let mut b: [u8; 64] = [0; 64];
hashit(sha, z, counter, None, 0, &mut b);
if lk + hlen > olen {
for i in 0..(olen % hlen) {
k[lk] = b[i];
lk += 1
}
} else {
for i in 0..hlen {
k[lk] = b[i];
lk += 1
}
}
}
}
pub fn kdf2(sha: usize, z: &[u8], p: Option<&[u8]>, olen: usize, k: &mut [u8]) {
let hlen = sha;
let mut lk = 0;
let mut cthreshold = olen / hlen;
if olen % hlen != 0 {
cthreshold += 1
}
for counter in 1..cthreshold + 1 {
let mut b: [u8; 64] = [0; 64];
hashit(sha, z, counter, p, 0, &mut b);
if lk + hlen > olen {
for i in 0..(olen % hlen) {
k[lk] = b[i];
lk += 1
}
} else {
for i in 0..hlen {
k[lk] = b[i];
lk += 1
}
}
}
}
pub fn pbkdf2(sha: usize, pass: &[u8], salt: &[u8], rep: usize, olen: usize, k: &mut [u8]) {
let mut d = olen / sha;
if olen % sha != 0 {
d += 1
}
let mut f: [u8; 64] = [0; 64];
let mut u: [u8; 64] = [0; 64];
let mut ku: [u8; 64] = [0; 64];
let mut s: [u8; 36] = [0; 36]; let mut n: [u8; 4] = [0; 4];
let sl = salt.len();
let mut kp = 0;
for i in 0..d {
for j in 0..sl {
s[j] = salt[j]
}
inttobytes(i + 1, &mut n);
for j in 0..4 {
s[sl + j] = n[j]
}
hmac(sha, &s[0..sl + 4], pass, sha, &mut f);
for j in 0..sha {
u[j] = f[j]
}
for _ in 1..rep {
hmac(sha, &mut u, pass, sha, &mut ku);
for k in 0..sha {
u[k] = ku[k];
f[k] ^= u[k]
}
}
for j in 0..EFS {
if kp < olen {
k[kp] = f[j]
}
kp += 1
}
}
}
pub fn hmac(sha: usize, m: &[u8], k: &[u8], olen: usize, tag: &mut [u8]) -> bool {
let mut b: [u8; 64] = [0; 64];
let mut k0: [u8; 128] = [0; 128];
if olen < 4 {
return false;
}
let mut lb = 64;
if sha > 32 {
lb = 128
}
for i in 0..lb {
k0[i] = 0
}
if k.len() > lb {
hashit(sha, k, 0, None, 0, &mut b);
for i in 0..sha {
k0[i] = b[i]
}
} else {
for i in 0..k.len() {
k0[i] = k[i]
}
}
for i in 0..lb {
k0[i] ^= 0x36
}
hashit(sha, &mut k0[0..lb], 0, Some(m), 0, &mut b);
for i in 0..lb {
k0[i] ^= 0x6a
}
hashit(sha, &mut k0[0..lb], 0, Some(&b[0..sha]), olen, tag);
return true;
}
pub fn cbc_iv0_encrypt(k: &[u8], m: &[u8]) -> Vec<u8> {
let mut a = AES::new();
let mut fin = false;
let mut c: Vec<u8> = Vec::new();
let mut buff: [u8; 16] = [0; 16];
a.init(aes::CBC, k.len(), k, None);
let mut ipt = 0;
let mut i;
loop {
i = 0;
while i < 16 {
if ipt < m.len() {
buff[i] = m[ipt];
i += 1;
ipt += 1;
} else {
fin = true;
break;
}
}
if fin {
break;
}
a.encrypt(&mut buff);
for j in 0..16 {
c.push(buff[j]);
}
}
let padlen = 16 - i;
for j in i..16 {
buff[j] = padlen as u8
}
a.encrypt(&mut buff);
for j in 0..16 {
c.push(buff[j]);
}
a.end();
return c;
}
pub fn cbc_iv0_decrypt(k: &[u8], c: &[u8]) -> Option<Vec<u8>> {
let mut a = AES::new();
let mut fin = false;
let mut m: Vec<u8> = Vec::new();
let mut buff: [u8; 16] = [0; 16];
a.init(aes::CBC, k.len(), k, None);
let mut ipt = 0;
let mut i;
if c.len() == 0 {
return None;
}
let mut ch = c[ipt];
ipt += 1;
loop {
i = 0;
while i < 16 {
buff[i] = ch;
if ipt >= c.len() {
fin = true;
break;
} else {
ch = c[ipt];
ipt += 1
}
i += 1;
}
a.decrypt(&mut buff);
if fin {
break;
}
for j in 0..16 {
m.push(buff[j]);
}
}
a.end();
let mut bad = false;
let padlen = buff[15] as usize;
if i != 15 || padlen < 1 || padlen > 16 {
bad = true
}
if padlen >= 2 && padlen <= 16 {
for j in 16 - padlen..16 {
if buff[j] != padlen as u8 {
bad = true
}
}
}
if !bad {
for i in 0..16 - padlen {
m.push(buff[i]);
}
}
if bad {
return None;
}
return Some(m);
}
#[allow(non_snake_case)]
pub fn key_pair_generate(rng: Option<&mut RAND>, s: &mut [u8], w: &mut [u8]) -> isize {
let res = 0;
let mut sc: BIG;
let G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
if let Some(mut x) = rng {
sc = BIG::randomnum(&r, &mut x);
} else {
sc = BIG::frombytes(&s);
sc.rmod(&r);
}
sc.tobytes(s);
let WP = G.mul(&mut sc);
WP.tobytes(w, false);
return res;
}
#[allow(non_snake_case)]
pub fn public_key_validate(w: &[u8]) -> isize {
let mut WP = ECP::frombytes(w);
let mut res = 0;
let r = BIG::new_ints(&rom::CURVE_ORDER);
if WP.is_infinity() {
res = INVALID_PUBLIC_KEY
}
if res == 0 {
let q = BIG::new_ints(&rom::MODULUS);
let nb = q.nbits();
let mut k = BIG::new();
k.one();
k.shl((nb + 4) / 2);
k.add(&q);
k.div(&r);
while k.parity() == 0 {
k.shr(1);
WP.dbl();
}
if !k.isunity() {
WP = WP.mul(&mut k)
}
if WP.is_infinity() {
res = INVALID_PUBLIC_KEY
}
}
return res;
}
#[allow(non_snake_case)]
pub fn ecpsvdp_dh(s: &[u8], wd: &[u8], z: &mut [u8]) -> isize {
let mut res = 0;
let mut t: [u8; EFS] = [0; EFS];
let mut sc = BIG::frombytes(&s);
let mut W = ECP::frombytes(&wd);
if W.is_infinity() {
res = ERROR
}
if res == 0 {
let r = BIG::new_ints(&rom::CURVE_ORDER);
sc.rmod(&r);
W = W.mul(&mut sc);
if W.is_infinity() {
res = ERROR;
} else {
W.getx().tobytes(&mut t);
for i in 0..EFS {
z[i] = t[i]
}
}
}
return res;
}
#[allow(non_snake_case)]
pub fn ecpsp_dsa(
sha: usize,
rng: &mut RAND,
s: &[u8],
f: &[u8],
c: &mut [u8],
d: &mut [u8],
) -> isize {
let mut t: [u8; EFS] = [0; EFS];
let mut b: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
hashit(sha, f, 0, None, big::MODBYTES as usize, &mut b);
let G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
let mut sc = BIG::frombytes(s);
let fb = BIG::frombytes(&b);
let mut cb = BIG::new();
let mut db = BIG::new();
let mut tb = BIG::new();
let mut V = ECP::new();
while db.iszilch() {
let mut u = BIG::randomnum(&r, rng);
let mut w = BIG::randomnum(&r, rng);
V.copy(&G);
V = V.mul(&mut u);
let vx = V.getx();
cb.copy(&vx);
cb.rmod(&r);
if cb.iszilch() {
continue;
}
tb.copy(&BIG::modmul(&mut u, &mut w, &r));
u.copy(&tb);
u.invmodp(&r);
db.copy(&BIG::modmul(&mut sc, &mut cb, &r));
db.add(&fb);
tb.copy(&BIG::modmul(&mut db, &mut w, &r));
db.copy(&tb);
tb.copy(&BIG::modmul(&mut u, &mut db, &r));
db.copy(&tb);
}
cb.tobytes(&mut t);
for i in 0..EFS {
c[i] = t[i]
}
db.tobytes(&mut t);
for i in 0..EFS {
d[i] = t[i]
}
return 0;
}
#[allow(non_snake_case)]
pub fn ecpvp_dsa(sha: usize, w: &[u8], f: &[u8], c: &[u8], d: &[u8]) -> isize {
let mut res = 0;
let mut b: [u8; big::MODBYTES as usize] = [0; big::MODBYTES as usize];
hashit(sha, f, 0, None, big::MODBYTES as usize, &mut b);
let mut G = ECP::generator();
let r = BIG::new_ints(&rom::CURVE_ORDER);
let mut cb = BIG::frombytes(c);
let mut db = BIG::frombytes(d);
let mut fb = BIG::frombytes(&b);
let mut tb = BIG::new();
if cb.iszilch() || BIG::comp(&cb, &r) >= 0 || db.iszilch() || BIG::comp(&db, &r) >= 0 {
res = INVALID;
}
if res == 0 {
db.invmodp(&r);
tb.copy(&BIG::modmul(&mut fb, &mut db, &r));
fb.copy(&tb);
let h2 = BIG::modmul(&mut cb, &mut db, &r);
let WP = ECP::frombytes(&w);
if WP.is_infinity() {
res = ERROR;
} else {
let mut P = ECP::new();
P.copy(&WP);
P = P.mul2(&h2, &mut G, &fb);
if P.is_infinity() {
res = INVALID;
} else {
db = P.getx();
db.rmod(&r);
if BIG::comp(&db, &cb) != 0 {
res = INVALID
}
}
}
}
return res;
}
#[allow(non_snake_case)]
pub fn ecies_encrypt(
sha: usize,
p1: &[u8],
p2: &[u8],
rng: &mut RAND,
w: &[u8],
m: &[u8],
v: &mut [u8],
t: &mut [u8],
) -> Option<Vec<u8>> {
let mut z: [u8; EFS] = [0; EFS];
let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut u: [u8; EGS] = [0; EGS];
let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
if key_pair_generate(Some(rng), &mut u, v) != 0 {
return None;
}
if ecpsvdp_dh(&u, &w, &mut z) != 0 {
return None;
}
for i in 0..2 * EFS + 1 {
vz[i] = v[i]
}
for i in 0..EFS {
vz[2 * EFS + 1 + i] = z[i]
}
kdf2(sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
for i in 0..ecp::AESKEY {
k1[i] = k[i];
k2[i] = k[ecp::AESKEY + i]
}
let mut c = cbc_iv0_encrypt(&k1, m);
let mut l2: [u8; 8] = [0; 8];
let p2l = p2.len();
inttobytes(p2l, &mut l2);
for i in 0..p2l {
c.push(p2[i]);
}
for i in 0..8 {
c.push(l2[i]);
}
hmac(sha, &c, &k2, t.len(), t);
for _ in 0..p2l + 8 {
c.pop();
}
return Some(c);
}
fn ncomp(t1: &[u8], t2: &[u8], n: usize) -> bool {
let mut res = 0;
for i in 0..n {
res |= (t1[i] ^ t2[i]) as isize;
}
if res == 0 {
return true;
}
return false;
}
#[allow(non_snake_case)]
pub fn ecies_decrypt(
sha: usize,
p1: &[u8],
p2: &[u8],
v: &[u8],
c: &mut Vec<u8>,
t: &[u8],
u: &[u8],
) -> Option<Vec<u8>> {
let mut z: [u8; EFS] = [0; EFS];
let mut k1: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut k2: [u8; ecp::AESKEY] = [0; ecp::AESKEY];
let mut vz: [u8; 3 * EFS + 1] = [0; 3 * EFS + 1];
let mut k: [u8; 2 * ecp::AESKEY] = [0; 2 * ecp::AESKEY];
let mut tag: [u8; 32] = [0; 32];
for i in 0..t.len() {
tag[i] = t[i]
}
if ecpsvdp_dh(&u, &v, &mut z) != 0 {
return None;
}
for i in 0..2 * EFS + 1 {
vz[i] = v[i]
}
for i in 0..EFS {
vz[2 * EFS + 1 + i] = z[i]
}
kdf2(sha, &vz, Some(p1), 2 * ecp::AESKEY, &mut k);
for i in 0..ecp::AESKEY {
k1[i] = k[i];
k2[i] = k[ecp::AESKEY + i]
}
let m = cbc_iv0_decrypt(&k1, &c);
if m == None {
return None;
}
let mut l2: [u8; 8] = [0; 8];
let p2l = p2.len();
inttobytes(p2l, &mut l2);
for i in 0..p2l {
c.push(p2[i]);
}
for i in 0..8 {
c.push(l2[i]);
}
hmac(sha, &c, &k2, t.len(), &mut tag);
for _ in 0..p2l + 8 {
c.pop();
}
if !ncomp(&t, &tag, t.len()) {
return None;
}
return m;
}