use crate::hash256::HASH256;
use crate::hash384::HASH384;
use crate::hash512::HASH512;
use crate::sha3::SHA3;
use crate::rand::RAND;
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)]
#[allow(clippy::too_many_arguments)]
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, &s[0..sl + 4], pass);
for j in 0..sha {
u[j] = f[j]
}
for _ in 1..rep {
hmac1(hash, sha, &mut ku, sha, &u, pass);
for m in 0..sha {
u[m] = ku[m];
f[m] ^= u[m]
}
}
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;
}
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(&k0[0..lb]), -1, Some(m));
for i in 0..lb {
k0[i] ^= 0x6a
}
GPhashit(hash, sha, tag,olen,0,Some(&k0[0..lb]), -1, Some(&b[0..sha]));
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+=1;
}
t[l]=i as u8; l+=1;
hmac1(hash,hlen,&mut k,hlen,prk,&t[0..l]);
l=0;
for j in 0..hlen {
okm[m]=k[j]; m+=1;
t[l]=k[j]; l+=1;
}
}
if flen>0 {
for j in 0..info.len() {
t[l]=info[j]; l+=1;
}
t[l]=(n+1) as u8; l+=1;
hmac1(hash,hlen,&mut k,flen,prk,&t[0..l]);
for j in 0..flen {
okm[m]=k[j]; m+=1;
}
}
}
fn ceil(a: usize,b: usize) -> usize {
(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
}
true
}
const SHA256IDB: [u8; 17] = [
0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20];
const SHA384IDB: [u8; 17] = [
0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30];
const SHA512IDB: [u8; 17] = [
0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40];
pub fn pkcs15b(sha: usize, m: &[u8], w: &mut [u8],rfs: usize) -> bool {
let olen = rfs;
let hlen = sha;
let idlen = 17;
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] = SHA256IDB[j];
i += 1
}
}
if hlen == SHA384 {
for j in 0..idlen {
w[i] = SHA384IDB[j];
i += 1
}
}
if hlen == SHA512 {
for j in 0..idlen {
w[i] = SHA512IDB[j];
i += 1
}
}
for j in 0..hlen {
w[i] = b[j];
i += 1
}
true
}
pub fn pss_encode(sha: usize, m: &[u8], rng: &mut impl 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;
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;
}
true
}
pub fn oaep_encode(sha: usize, m: &[u8], rng: &mut impl 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[0..seedlen], 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;
}
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[0..seedlen], olen - seedlen, f);
for i in 0..olen - seedlen {
dbmask[i] ^= f[i]
}
let mut comp=0;
for i in 0..hlen {
comp |= (chash[i]^dbmask[i]) as usize;
}
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;
let mut t=0;
let m=olen-seedlen-hlen;
for i in 0..m {
if t==0 && dbmask[i]!=0 {
k=i;
t=dbmask[i];
}
}
if comp!=0 || x != 0 || t != 0x01 {
for i in 0..olen - seedlen {
dbmask[i] = 0
}
return 0;
}
for i in 0..m - k - 1 {
f[i] = dbmask[i + k + 1];
}
for i in 0..olen - seedlen {
dbmask[i] = 0
}
m - k - 1
}