| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| */ |
| |
| use xxx::ecp; |
| use xxx::ecp::ECP; |
| use xxx::big::BIG; |
| use xxx::rom; |
| use xxx::big; |
| |
| use rand::RAND; |
| use hash256::HASH256; |
| use hash384::HASH384; |
| use hash512::HASH512; |
| use aes; |
| use aes::AES; |
| |
| |
| 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 EAS: usize=16; |
| //pub const EBS: usize=16; |
| pub const SHA256: usize=32; |
| pub const SHA384: usize=48; |
| pub const SHA512: usize=64; |
| |
| //pub const HASH_TYPE: usize=SHA512; |
| |
| #[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} |
| |
| |
| //for i in 0..sha {w[i]=r[i]} |
| //for i in sha..pad {w[i]=0} |
| } |
| } |
| } |
| |
| /* Key Derivation Functions */ |
| /* Input octet Z */ |
| /* Output key of length olen */ |
| pub fn kdf1(sha: usize,z: &[u8],olen: usize,k: &mut [u8]) { |
| /* NOTE: the parameter olen is the length of the output K in bytes */ |
| 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]) { |
| /* NOTE: the parameter olen is the length of the output K in bytes */ |
| 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} |
| } |
| } |
| } |
| |
| /* Password based Key Derivation Function */ |
| /* Input password p, salt s, and repeat count */ |
| /* Output key of length olen */ |
| 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]; // Maximum salt of 32 bytes + 4 |
| 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} |
| } |
| } |
| |
| /* Calculate HMAC of m using key k. HMAC is tag of length olen (which is length of tag) */ |
| pub fn hmac(sha: usize,m: &[u8],k: &[u8],olen: usize,tag: &mut [u8]) -> bool { |
| /* Input is from an octet m * |
| * olen is requested output length in bytes. k is the key * |
| * The output is the calculated tag */ |
| let mut b:[u8;64]=[0;64]; /* Not good */ |
| let mut k0:[u8;128]=[0;128]; |
| // let olen=tag.len(); /* length of HMAC */ |
| |
| if olen<4 /*|| olen>sha */ {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; |
| } |
| |
| /* AES encryption/decryption. Encrypt byte array m using key k and returns ciphertext c */ |
| pub fn cbc_iv0_encrypt(k: &[u8],m: &[u8]) -> Vec<u8> { /* AES CBC encryption, with Null IV and key K */ |
| /* Input is from an octet string m, output is to an octet string c */ |
| /* Input is padded as necessary to make up a full final block */ |
| 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 opt=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]); |
| //c[opt]=buff[j]; opt+=1; |
| } |
| } |
| |
| /* last block, filled up to i-th index */ |
| |
| 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]); |
| //c[opt]=buff[j]; opt+=1; |
| } |
| a.end(); |
| return c; |
| } |
| |
| /* returns plaintext if all consistent, else returns null string */ |
| pub fn cbc_iv0_decrypt(k: &[u8],c: &[u8]) -> Option<Vec<u8>> { /* padding is removed */ |
| 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 opt=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]); |
| //m[opt]=buff[j]; opt+=1; |
| } |
| } |
| |
| 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]); |
| //m[opt]=buff[j]; opt+=1; |
| } |
| } |
| |
| if bad {return None} |
| return Some(m); |
| } |
| |
| /* Calculate a public/private EC GF(p) key pair w,s where W=s.G mod EC(p), |
| * where s is the secret key and W is the public key |
| * and G is fixed generator. |
| * If RNG is NULL then the private key is provided externally in s |
| * otherwise it is generated randomly internally */ |
| #[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); |
| } |
| |
| //if rom::AES_S>0 { |
| // sc.mod2m(2*rom::AES_S) |
| //} |
| sc.tobytes(s); |
| |
| let WP=G.mul(&mut sc); |
| |
| WP.tobytes(w,false); // To use point compression on public keys, change to true |
| |
| return res; |
| } |
| |
| /* validate public key */ |
| #[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; |
| } |
| |
| /* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */ |
| #[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; |
| } |
| |
| /* IEEE ECDSA Signature, C and D are signature on F using private key S */ |
| #[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); /* s or &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); /* side channel masking */ |
| //if rom::AES_S>0 { |
| // u.mod2m(2*rom::AES_S); |
| //} |
| 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; |
| } |
| |
| /* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ |
| #[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); /* c or &c ? */ |
| let mut db=BIG::frombytes(d); /* d or &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; |
| } |
| |
| /* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */ |
| #[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); |
| } |
| |
| /* constant time n-byte compare */ |
| 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; |
| } |
| |
| /* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */ |
| #[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]; /* 32 is max length of tag */ |
| |
| 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} |
| |
| //let mut same=true; |
| //for i in 0..t.len() { |
| // if t[i]!=tag[i] {same=false} |
| //} |
| //if !same {return None} |
| |
| return m; |
| } |
| |