use crate::bls::{hash256::HASH256, hash384::HASH384, hash512::HASH512, rand::RAND, sha3::SHA3};
pub const MC_SHA2: usize = 2;
pub const MC_SHA3: usize = 3;
pub const SHA256: usize = 32;
pub const SHA384: usize = 48;
pub const SHA512: usize = 64;
#[allow(non_snake_case)]
pub fn GPhashit(
hash: usize,
sha: usize,
w: &mut [u8],
pad: usize,
zpad: usize,
a: Option<&[u8]>,
n: isize,
b: Option<&[u8]>,
) {
let mut r: [u8; 64] = [0; 64];
if hash == MC_SHA2 {
if sha == SHA256 {
let mut h = HASH256::new();
for _ in 0..zpad {
h.process(0);
}
if let Some(x) = a {
h.process_array(x);
}
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();
for _ in 0..zpad {
h.process(0);
}
if let Some(x) = a {
h.process_array(x);
}
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();
for _ in 0..zpad {
h.process(0);
}
if let Some(x) = a {
h.process_array(x);
}
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 hash == MC_SHA3 {
let mut h = SHA3::new(sha);
for _ in 0..zpad {
h.process(0);
}
if let Some(x) = a {
h.process_array(x);
}
if n >= 0 {
h.process_num(n as i32)
}
if let Some(x) = b {
h.process_array(x);
}
h.hash(&mut r);
}
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
}
}
}
}
#[allow(non_snake_case)]
pub fn SPhashit(hash: usize, sha: usize, w: &mut [u8], a: Option<&[u8]>) {
GPhashit(hash, sha, w, 0, 0, a, -1, None);
}
pub 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;
}
}
pub fn kdf2(hash: usize, 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];
GPhashit(hash, sha, &mut b, 0, 0, Some(z), counter as isize, p);
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(
hash: usize,
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]
}
hmac1(hash, sha, &mut f, sha, pass, &s[0..sl + 4]);
for j in 0..sha {
u[j] = f[j]
}
for _ in 1..rep {
hmac1(hash, sha, &mut ku, sha, pass, &mut u);
for k in 0..sha {
u[k] = ku[k];
f[k] ^= u[k]
}
}
for j in 0..sha {
if kp < olen {
k[kp] = f[j]
}
kp += 1
}
}
}
fn blksize(hash: usize, sha: usize) -> usize {
let mut lb = 0;
if hash == MC_SHA2 {
lb = 64;
if sha > 32 {
lb = 128;
}
}
if hash == MC_SHA3 {
lb = 200 - 2 * sha;
}
return lb;
}
pub fn hmac1(hash: usize, sha: usize, tag: &mut [u8], olen: usize, k: &[u8], m: &[u8]) -> bool {
let mut b: [u8; 64] = [0; 64];
let mut k0: [u8; 128] = [0; 128];
let lb = blksize(hash, sha);
if lb == 0 {
return false;
}
for i in 0..lb {
k0[i] = 0
}
if k.len() > lb {
SPhashit(hash, sha, &mut b, Some(k));
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
}
GPhashit(hash, sha, &mut b, 0, 0, Some(&mut k0[0..lb]), -1, Some(m));
for i in 0..lb {
k0[i] ^= 0x6a
}
GPhashit(
hash,
sha,
tag,
olen,
0,
Some(&mut k0[0..lb]),
-1,
Some(&b[0..sha]),
);
return true;
}
pub fn hkdf_extract(hash: usize, hlen: usize, prk: &mut [u8], salt: Option<&[u8]>, ikm: &[u8]) {
if let Some(x) = salt {
hmac1(hash, hlen, prk, hlen, x, ikm);
} else {
let h: [u8; 64] = [0; 64];
hmac1(hash, hlen, prk, hlen, &h[0..hlen], ikm);
}
}
pub fn hkdf_expand(hash: usize, hlen: usize, okm: &mut [u8], olen: usize, prk: &[u8], info: &[u8]) {
let n = olen / hlen;
let flen = olen % hlen;
let mut t: [u8; 1024] = [0; 1024]; let mut k: [u8; 64] = [0; 64];
let mut l = 0;
let mut m = 0;
for i in 1..=n {
for j in 0..info.len() {
t[l] = info[j];
l = l + 1;
}
t[l] = i as u8;
l = l + 1;
hmac1(hash, hlen, &mut k, hlen, prk, &t[0..l]);
l = 0;
for j in 0..hlen {
okm[m] = k[j];
m = m + 1;
t[l] = k[j];
l = l + 1;
}
}
if flen > 0 {
for j in 0..info.len() {
t[l] = info[j];
l = l + 1;
}
t[l] = (n + 1) as u8;
l = l + 1;
hmac1(hash, hlen, &mut k, flen, prk, &t[0..l]);
for j in 0..flen {
okm[m] = k[j];
m = m + 1;
}
}
}
fn ceil(a: usize, b: usize) -> usize {
return (a - 1) / b + 1;
}
pub fn xof_expand(hlen: usize, okm: &mut [u8], olen: usize, dst: &[u8], msg: &[u8]) {
let mut h = SHA3::new(hlen);
for i in 0..msg.len() {
h.process(msg[i]);
}
h.process(((olen >> 8) & 0xff) as u8);
h.process((olen & 0xff) as u8);
for i in 0..dst.len() {
h.process(dst[i]);
}
h.process((dst.len() & 0xff) as u8);
h.shake(okm, olen);
}
pub fn xmd_expand(hash: usize, hlen: usize, okm: &mut [u8], olen: usize, dst: &[u8], msg: &[u8]) {
let mut tmp: [u8; 260] = [0; 260];
let mut h0: [u8; 64] = [0; 64];
let mut h1: [u8; 64] = [0; 64];
let mut h2: [u8; 64] = [0; 64];
let ell = ceil(olen, hlen);
let blk = blksize(hash, hlen);
tmp[0] = ((olen >> 8) & 0xff) as u8;
tmp[1] = (olen & 0xff) as u8;
tmp[2] = 0;
for j in 0..dst.len() {
tmp[3 + j] = dst[j];
}
tmp[3 + dst.len()] = (dst.len() & 0xff) as u8;
GPhashit(
hash,
hlen,
&mut h0,
0,
blk,
Some(msg),
-1,
Some(&tmp[0..dst.len() + 4]),
);
let mut k = 0;
for i in 1..=ell {
for j in 0..hlen {
h1[j] ^= h0[j];
h2[j] = h1[j];
}
tmp[0] = i as u8;
for j in 0..dst.len() {
tmp[1 + j] = dst[j];
}
tmp[1 + dst.len()] = (dst.len() & 0xff) as u8;
GPhashit(
hash,
hlen,
&mut h1,
0,
0,
Some(&h2[0..hlen]),
-1,
Some(&tmp[0..dst.len() + 2]),
);
for j in 0..hlen {
okm[k] = h1[j];
k += 1;
if k == olen {
break;
}
}
}
}
pub fn mgf1(sha: usize, z: &[u8], olen: usize, k: &mut [u8]) {
let hlen = sha;
let mut j = 0;
for i in 0..k.len() {
k[i] = 0
}
let mut cthreshold = olen / hlen;
if olen % hlen != 0 {
cthreshold += 1
}
for counter in 0..cthreshold {
let mut b: [u8; 64] = [0; 64];
GPhashit(MC_SHA2, sha, &mut b, 0, 0, Some(z), counter as isize, None);
if j + hlen > olen {
for i in 0..(olen % hlen) {
k[j] = b[i];
j += 1
}
} else {
for i in 0..hlen {
k[j] = b[i];
j += 1
}
}
}
}
pub fn mgf1xor(sha: usize, z: &[u8], olen: usize, k: &mut [u8]) {
let hlen = sha;
let mut j = 0;
let mut cthreshold = olen / hlen;
if olen % hlen != 0 {
cthreshold += 1
}
for counter in 0..cthreshold {
let mut b: [u8; 64] = [0; 64];
GPhashit(MC_SHA2, sha, &mut b, 0, 0, Some(z), counter as isize, None);
if j + hlen > olen {
for i in 0..(olen % hlen) {
k[j] ^= b[i];
j += 1
}
} else {
for i in 0..hlen {
k[j] ^= b[i];
j += 1
}
}
}
}
const SHA256ID: [u8; 19] = [
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20,
];
const SHA384ID: [u8; 19] = [
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30,
];
const SHA512ID: [u8; 19] = [
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40,
];
pub fn pkcs15(sha: usize, m: &[u8], w: &mut [u8], rfs: usize) -> bool {
let olen = rfs;
let hlen = sha;
let idlen = 19;
let mut b: [u8; 64] = [0; 64];
if olen < idlen + hlen + 10 {
return false;
}
SPhashit(MC_SHA2, sha, &mut b, Some(m));
for i in 0..w.len() {
w[i] = 0
}
let mut i = 0;
w[i] = 0;
i += 1;
w[i] = 1;
i += 1;
for _ in 0..olen - idlen - hlen - 3 {
w[i] = 0xff;
i += 1
}
w[i] = 0;
i += 1;
if hlen == SHA256 {
for j in 0..idlen {
w[i] = SHA256ID[j];
i += 1
}
}
if hlen == SHA384 {
for j in 0..idlen {
w[i] = SHA384ID[j];
i += 1
}
}
if hlen == SHA512 {
for j in 0..idlen {
w[i] = SHA512ID[j];
i += 1
}
}
for j in 0..hlen {
w[i] = b[j];
i += 1
}
return true;
}
pub fn pss_encode(sha: usize, m: &[u8], rng: &mut RAND, f: &mut [u8], rfs: usize) -> bool {
let emlen = rfs;
let embits = 8 * emlen - 1;
let hlen = sha;
let mut h: [u8; 64] = [0; 64];
let mut salt: [u8; 64] = [0; 64];
let mut md: [u8; 136] = [0; 136];
for i in 0..hlen {
salt[i] = rng.getbyte()
}
let mask = (0xff as u8) >> (8 * emlen - embits);
SPhashit(MC_SHA2, sha, &mut h, Some(m));
if emlen < hlen + hlen + 2 {
return false;
}
for i in 0..8 {
md[i] = 0;
}
for i in 0..hlen {
md[8 + i] = h[i];
}
for i in 0..hlen {
md[8 + hlen + i] = salt[i];
}
SPhashit(MC_SHA2, sha, &mut h, Some(&md[0..8 + hlen + hlen]));
for i in 0..emlen - hlen - hlen - 2 {
f[i] = 0;
}
f[emlen - hlen - hlen - 2] = 0x01;
for i in 0..hlen {
f[emlen + i - hlen - hlen - 1] = salt[i];
}
mgf1xor(sha, &h[0..hlen], emlen - hlen - 1, f);
f[0] &= mask;
for i in 0..hlen {
f[emlen + i - hlen - 1] = h[i];
}
f[emlen - 1] = 0xbc as u8;
return true;
}
pub fn pss_verify(sha: usize, m: &[u8], f: &[u8]) -> bool {
let emlen = f.len();
let embits = 8 * emlen - 1;
let hlen = sha;
let mut db: [u8; 512] = [0; 512];
let mut hmask: [u8; 64] = [0; 64];
let mut h: [u8; 64] = [0; 64];
let mut salt: [u8; 64] = [0; 64];
let mut md: [u8; 136] = [0; 136];
let mask = (0xff as u8) >> (8 * emlen - embits);
SPhashit(MC_SHA2, sha, &mut hmask, Some(m));
if emlen < hlen + hlen + 2 {
return false;
}
if f[emlen - 1] != 0xbc as u8 {
return false;
}
if (f[0] & (!mask)) != 0 {
return false;
}
for i in 0..emlen - hlen - 1 {
db[i] = f[i]
}
for i in 0..hlen {
h[i] = f[emlen + i - hlen - 1]
}
mgf1xor(sha, &h[0..hlen], emlen - hlen - 1, &mut db);
db[0] &= mask;
let mut k = 0 as u8;
for i in 0..emlen - hlen - hlen - 2 {
k |= db[i]
}
if k != 0 {
return false;
}
if db[emlen - hlen - hlen - 2] != 0x01 {
return false;
}
for i in 0..hlen {
salt[i] = db[emlen + i - hlen - hlen - 1]
}
for i in 0..8 {
md[i] = 0
}
for i in 0..hlen {
md[8 + i] = hmask[i]
}
for i in 0..hlen {
md[8 + hlen + i] = salt[i]
}
SPhashit(MC_SHA2, sha, &mut hmask, Some(&md[0..8 + hlen + hlen]));
k = 0;
for i in 0..hlen {
k |= h[i] - hmask[i];
}
if k != 0 {
return false;
}
return true;
}
pub fn oaep_encode(
sha: usize,
m: &[u8],
rng: &mut RAND,
p: Option<&[u8]>,
f: &mut [u8],
rfs: usize,
) -> bool {
let olen = rfs - 1;
let mlen = m.len();
let hlen = sha;
let mut seed: [u8; 64] = [0; 64];
let seedlen = hlen;
if mlen > olen - hlen - seedlen - 1 {
return false;
}
let mut dbmask: [u8; 512] = [0; 512];
SPhashit(MC_SHA2, sha, f, p);
let slen = olen - mlen - hlen - seedlen - 1;
for i in 0..slen {
f[hlen + i] = 0
}
f[hlen + slen] = 1;
for i in 0..mlen {
f[hlen + slen + 1 + i] = m[i]
}
for i in 0..seedlen {
seed[i] = rng.getbyte()
}
mgf1(sha, &seed, olen - seedlen, &mut dbmask);
for i in 0..olen - seedlen {
dbmask[i] ^= f[i]
}
mgf1(sha, &dbmask[0..olen - seedlen], seedlen, f);
for i in 0..seedlen {
f[i] ^= seed[i]
}
for i in 0..olen - seedlen {
f[i + seedlen] = dbmask[i]
}
let d = 1;
for i in (d..rfs).rev() {
f[i] = f[i - d];
}
for i in (0..d).rev() {
f[i] = 0;
}
return true;
}
pub fn oaep_decode(sha: usize, p: Option<&[u8]>, f: &mut [u8], rfs: usize) -> usize {
let olen = rfs - 1;
let hlen = sha;
let mut seed: [u8; 64] = [0; 64];
let seedlen = hlen;
let mut chash: [u8; 64] = [0; 64];
if olen < seedlen + hlen + 1 {
return 0;
}
let mut dbmask: [u8; 512] = [0; 512];
if f.len() < rfs {
let d = rfs - f.len();
for i in (d..rfs).rev() {
f[i] = f[i - d];
}
for i in (0..d).rev() {
f[i] = 0;
}
}
SPhashit(MC_SHA2, sha, &mut chash, p);
let x = f[0];
for i in seedlen..olen {
dbmask[i - seedlen] = f[i + 1];
}
mgf1(sha, &dbmask[0..olen - seedlen], seedlen, &mut seed);
for i in 0..seedlen {
seed[i] ^= f[i + 1]
}
mgf1(sha, &seed, olen - seedlen, f);
for i in 0..olen - seedlen {
dbmask[i] ^= f[i]
}
let mut comp = true;
for i in 0..hlen {
if chash[i] != dbmask[i] {
comp = false
}
}
for i in 0..olen - seedlen - hlen {
dbmask[i] = dbmask[i + hlen]
}
for i in 0..hlen {
seed[i] = 0;
chash[i] = 0
}
let mut k = 0;
loop {
if k >= olen - seedlen - hlen {
return 0;
}
if dbmask[k] != 0 {
break;
}
k += 1;
}
let t = dbmask[k];
if !comp || x != 0 || t != 0x01 {
for i in 0..olen - seedlen {
dbmask[i] = 0
}
return 0;
}
for i in 0..olen - seedlen - hlen - k - 1 {
f[i] = dbmask[i + k + 1];
}
for i in 0..olen - seedlen {
dbmask[i] = 0
}
return olen - seedlen - hlen - k - 1;
}