| /* |
| 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 std::time::{SystemTime}; |
| use std::time::UNIX_EPOCH; |
| |
| use ecp::ECP; |
| use fp2::FP2; |
| use ecp2::ECP2; |
| use fp4::FP4; |
| use fp12::FP12; |
| use big::BIG; |
| use rand::RAND; |
| use hash256::HASH256; |
| use hash384::HASH384; |
| use hash512::HASH512; |
| use pair; |
| use rom; |
| |
| /* MPIN API Functions */ |
| |
| /* Configure mode of operation */ |
| |
| pub const PERMITS:bool=true; |
| pub const PINERROR:bool=true; |
| pub const FULL: bool=true; |
| pub const SINGLE_PASS:bool=false; |
| |
| pub const EFS: usize=rom::MODBYTES as usize; |
| pub const EGS: usize=rom::MODBYTES as usize; |
| pub const PAS: usize=16; |
| pub const BAD_PARAMS: isize=-11; |
| pub const INVALID_POINT: isize=-14; |
| pub const WRONG_ORDER: isize=-18; |
| pub const BAD_PIN: isize=-19; |
| pub const SHA256: usize=32; |
| pub const SHA384: usize=48; |
| pub const SHA512: usize=64; |
| |
| /* Configure your PIN here */ |
| |
| pub const MAXPIN: i32=10000; /* PIN less than this */ |
| pub const PBLEN: i32=14; /* Number of bits in PIN */ |
| pub const TS: usize=10; /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */ |
| pub const TRAP:usize=200; /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */ |
| |
| pub const HASH_TYPE: usize=SHA256; |
| |
| #[allow(non_snake_case)] |
| fn hash(sha: usize,c: &mut FP4,U: &mut ECP,r: &mut [u8]) -> bool { |
| let mut w:[u8;EFS]=[0;EFS]; |
| let mut t:[u8;6*EFS]=[0;6*EFS]; |
| |
| c.geta().geta().tobytes(&mut w); for i in 0..EFS {t[i]=w[i]} |
| c.geta().getb().tobytes(&mut w); for i in EFS..2*EFS {t[i]=w[i-EFS]} |
| c.getb().geta().tobytes(&mut w); for i in 2*EFS..3*EFS {t[i]=w[i-2*EFS]} |
| c.getb().getb().tobytes(&mut w); for i in 3*EFS..4*EFS {t[i]=w[i-3*EFS]} |
| |
| U.getx().tobytes(&mut w); for i in 4*EFS..5*EFS {t[i]=w[i-4*EFS]} |
| U.gety().tobytes(&mut w); for i in 5*EFS..6*EFS {t[i]=w[i-5*EFS]} |
| |
| if sha==SHA256 { |
| let mut h=HASH256::new(); |
| h.process_array(&t); |
| let sh=h.hash(); |
| for i in 0..PAS {r[i]=sh[i]} |
| return true; |
| } |
| if sha==SHA384 { |
| let mut h=HASH384::new(); |
| h.process_array(&t); |
| let sh=h.hash(); |
| for i in 0..PAS {r[i]=sh[i]} |
| return true; |
| } |
| if sha==SHA512 { |
| let mut h=HASH512::new(); |
| h.process_array(&t); |
| let sh=h.hash(); |
| for i in 0..PAS {r[i]=sh[i]} |
| return true; |
| } |
| return false; |
| |
| } |
| |
| /* Hash number (optional) and string to point on curve */ |
| |
| fn hashit(sha: usize,n: usize,id: &[u8],w: &mut [u8]) -> bool { |
| let mut r:[u8;64]=[0;64]; |
| let mut didit=false; |
| if sha==SHA256 { |
| let mut h=HASH256::new(); |
| if n>0 {h.process_num(n as i32)} |
| h.process_array(id); |
| let hs=h.hash(); |
| for i in 0..sha {r[i]=hs[i];} |
| didit=true; |
| } |
| if sha==SHA384 { |
| let mut h=HASH384::new(); |
| if n>0 {h.process_num(n as i32)} |
| h.process_array(id); |
| let hs=h.hash(); |
| for i in 0..sha {r[i]=hs[i];} |
| didit=true; |
| } |
| if sha==SHA512 { |
| let mut h=HASH512::new(); |
| if n>0 {h.process_num(n as i32)} |
| h.process_array(id); |
| let hs=h.hash(); |
| for i in 0..sha {r[i]=hs[i];} |
| didit=true; |
| } |
| if !didit {return false} |
| |
| let rm=rom::MODBYTES as usize; |
| |
| if sha>rm { |
| for i in 0..rm {w[i]=r[i]} |
| } else { |
| for i in 0..sha {w[i]=r[i]} |
| for i in sha..rm {w[i]=0} |
| } |
| |
| return true; |
| } |
| |
| #[allow(non_snake_case)] |
| fn mapit(h: &[u8]) -> ECP { |
| let mut q=BIG::new_ints(&rom::MODULUS); |
| let mut x=BIG::frombytes(h); |
| x.rmod(&mut q); |
| let mut P:ECP; |
| |
| loop { |
| P=ECP::new_bigint(&x,0); |
| if !P.is_infinity() {break} |
| x.inc(1); x.norm(); |
| } |
| if rom::CURVE_PAIRING_TYPE!=rom::BN_CURVE { |
| let mut c=BIG::new_ints(&rom::CURVE_COF); |
| P=P.mul(&mut c); |
| } |
| return P; |
| } |
| |
| /* return time in slots since epoch */ |
| pub fn today() -> usize { |
| return (SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()/(60*1440)) as usize; |
| } |
| |
| /* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ |
| /* maps a random u to a point on the curve */ |
| #[allow(non_snake_case)] |
| fn emap(u: &BIG,cb: isize) -> ECP { |
| let mut P:ECP; |
| let mut x=BIG::new_copy(u); |
| let mut p=BIG::new_ints(&rom::MODULUS); |
| x.rmod(&mut p); |
| loop { |
| P=ECP::new_bigint(&x,cb); |
| if !P.is_infinity() {break} |
| x.inc(1); x.norm(); |
| } |
| return P; |
| } |
| |
| /* returns u derived from P. Random value in range 1 to return value should then be added to u */ |
| #[allow(non_snake_case)] |
| fn unmap(u: &mut BIG,P: &mut ECP) -> isize { |
| let s=P.gets(); |
| let mut R:ECP; |
| let mut r=0; |
| let x=P.getx(); |
| u.copy(&x); |
| loop { |
| u.dec(1); u.norm(); |
| r+=1; |
| R=ECP::new_bigint(u,s); |
| if !R.is_infinity() {break} |
| } |
| return r as isize; |
| } |
| |
| pub fn hash_id(sha: usize,id: &[u8],w: &mut [u8]) -> bool { |
| return hashit(sha,0,id,w); |
| } |
| |
| /* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ |
| /* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ |
| /* Note that u and v are indistinguisible from random strings */ |
| #[allow(non_snake_case)] |
| pub fn encoding(rng: &mut RAND,e: &mut [u8]) ->isize { |
| let mut t:[u8;EFS]=[0;EFS]; |
| |
| for i in 0..EFS {t[i]=e[i+1]} |
| let mut u=BIG::frombytes(&t); |
| for i in 0..EFS {t[i]=e[i+EFS+1]} |
| let mut v=BIG::frombytes(&t); |
| |
| let mut P=ECP::new_bigs(&u,&v); |
| if P.is_infinity() {return INVALID_POINT} |
| |
| let p=BIG::new_ints(&rom::MODULUS); |
| u=BIG::randomnum(&p,rng); |
| |
| let mut su=rng.getbyte() as isize; /*if (su<0) su=-su;*/ su%=2; |
| |
| let mut W=emap(&mut u,su); |
| P.sub(&mut W); |
| let sv=P.gets(); |
| let rn=unmap(&mut v,&mut P); |
| let mut m=rng.getbyte() as isize; /*if (m<0) m=-m;*/ m%=rn; |
| v.inc(m+1); |
| e[0]=(su+2*sv) as u8; |
| u.tobytes(&mut t); |
| for i in 0..EFS {e[i+1]=t[i]} |
| v.tobytes(&mut t); |
| for i in 0..EFS {e[i+EFS+1]=t[i]} |
| |
| return 0; |
| } |
| |
| #[allow(non_snake_case)] |
| pub fn decoding(d: &mut [u8]) -> isize { |
| let mut t:[u8;EFS]=[0;EFS]; |
| |
| if (d[0]&0x04)!=0 {return INVALID_POINT} |
| |
| for i in 0..EFS {t[i]=d[i+1]} |
| let mut u=BIG::frombytes(&t); |
| for i in 0..EFS {t[i]=d[i+EFS+1]} |
| let mut v=BIG::frombytes(&t); |
| |
| let su=(d[0]&1) as isize; |
| let sv=((d[0]>>1)&1) as isize; |
| let mut W=emap(&mut u,su); |
| let mut P=emap(&mut v,sv); |
| P.add(&mut W); |
| u=P.getx(); |
| v=P.gety(); |
| d[0]=0x04; |
| u.tobytes(&mut t); |
| for i in 0..EFS {d[i+1]=t[i]} |
| v.tobytes(&mut t); |
| for i in 0..EFS {d[i+EFS+1]=t[i]} |
| |
| return 0; |
| } |
| |
| /* R=R1+R2 in group G1 */ |
| #[allow(non_snake_case)] |
| pub fn recombine_g1(r1: &[u8],r2: &[u8],r: &mut [u8]) -> isize { |
| let mut P=ECP::frombytes(&r1); |
| let mut Q=ECP::frombytes(&r2); |
| |
| if P.is_infinity() || Q.is_infinity() {return INVALID_POINT} |
| |
| P.add(&mut Q); |
| |
| P.tobytes(r); |
| return 0; |
| } |
| |
| /* W=W1+W2 in group G2 */ |
| #[allow(non_snake_case)] |
| pub fn recombine_g2(w1: &[u8],w2: &[u8],w: &mut [u8]) -> isize { |
| let mut P=ECP2::frombytes(&w1); |
| let mut Q=ECP2::frombytes(&w2); |
| |
| if P.is_infinity() || Q.is_infinity() {return INVALID_POINT} |
| |
| P.add(&mut Q); |
| |
| P.tobytes(w); |
| return 0; |
| } |
| |
| /* create random secret S */ |
| pub fn random_generate(rng: &mut RAND,s: &mut [u8]) -> isize { |
| let r=BIG::new_ints(&rom::CURVE_ORDER); |
| let mut sc=BIG::randomnum(&r,rng); |
| if rom::AES_S>0 { |
| sc.mod2m(2*rom::AES_S); |
| } |
| sc.tobytes(s); |
| return 0; |
| } |
| |
| /* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ |
| #[allow(non_snake_case)] |
| pub fn get_server_secret(s: &[u8],sst: &mut [u8]) -> isize { |
| |
| let mut Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB))); |
| |
| let mut sc=BIG::frombytes(s); |
| Q=pair::g2mul(&mut Q,&mut sc); |
| Q.tobytes(sst); |
| return 0; |
| } |
| |
| /* |
| W=x*H(G); |
| if RNG == NULL then X is passed in |
| if RNG != NULL the X is passed out |
| if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve |
| */ |
| #[allow(non_snake_case)] |
| pub fn get_g1_multiple(rng: Option<&mut RAND>,typ: usize,x: &mut [u8],g: &[u8],w: &mut [u8]) -> isize { |
| let mut sx:BIG; |
| let r=BIG::new_ints(&rom::CURVE_ORDER); |
| |
| if let Some(mut rd)=rng |
| { |
| sx=BIG::randomnum(&r,rd); |
| if rom::AES_S>0 { |
| sx.mod2m(2*rom::AES_S); |
| } |
| sx.tobytes(x); |
| } else { |
| sx=BIG::frombytes(x); |
| } |
| let mut P:ECP; |
| |
| if typ==0 { |
| P=ECP::frombytes(g); |
| if P.is_infinity() {return INVALID_POINT} |
| } else { |
| P=mapit(g) |
| } |
| |
| |
| |
| pair::g1mul(&mut P,&mut sx).tobytes(w); |
| return 0; |
| } |
| |
| |
| /* Client secret CST=S*H(CID) where CID is client ID and S is master secret */ |
| /* CID is hashed externally */ |
| pub fn get_client_secret(s: &mut [u8],cid: &[u8],cst: &mut [u8]) -> isize { |
| return get_g1_multiple(None,1,s,cid,cst); |
| } |
| |
| /* Extract PIN from TOKEN for identity CID */ |
| #[allow(non_snake_case)] |
| pub fn extract_pin(sha: usize,cid: &[u8],pin: i32,token: &mut [u8]) -> isize { |
| let mut P=ECP::frombytes(&token); |
| const RM:usize=rom::MODBYTES as usize; |
| let mut h:[u8;RM]=[0;RM]; |
| if P.is_infinity() {return INVALID_POINT} |
| hashit(sha,0,cid,&mut h); |
| let mut R=mapit(&h); |
| |
| R=R.pinmul(pin%MAXPIN,PBLEN); |
| P.sub(&mut R); |
| |
| P.tobytes(token); |
| |
| return 0; |
| } |
| |
| /* Functions to support M-Pin Full */ |
| #[allow(non_snake_case)] |
| pub fn precompute(token: &[u8],cid: &[u8],g1: &mut [u8],g2: &mut [u8]) -> isize { |
| let mut T=ECP::frombytes(&token); |
| if T.is_infinity() {return INVALID_POINT} |
| |
| let mut P=mapit(&cid); |
| |
| let mut Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB))); |
| |
| let mut g=pair::ate(&mut Q,&mut T); |
| g=pair::fexp(&g); |
| g.tobytes(g1); |
| |
| g=pair::ate(&mut Q,&mut P); |
| g=pair::fexp(&g); |
| g.tobytes(g2); |
| |
| return 0; |
| } |
| |
| /* Time Permit CTT=S*(date|H(CID)) where S is master secret */ |
| #[allow(non_snake_case)] |
| pub fn get_client_permit(sha: usize,date: usize,s: &[u8],cid: &[u8],ctt: &mut [u8]) ->isize { |
| const RM:usize=rom::MODBYTES as usize; |
| let mut h:[u8;RM]=[0;RM]; |
| hashit(sha,date,cid,&mut h); |
| let mut P=mapit(&h); |
| |
| let mut sc=BIG::frombytes(s); |
| pair::g1mul(&mut P,&mut sc).tobytes(ctt); |
| return 0; |
| } |
| |
| /* Implement step 1 on client side of MPin protocol */ |
| #[allow(non_snake_case)] |
| pub fn client_1(sha: usize,date: usize,client_id: &[u8],rng: Option<&mut RAND>,x: &mut [u8],pin: usize,token: &[u8],sec: &mut [u8],xid: Option<&mut [u8]>,xcid: Option<&mut [u8]>,permit: Option<&[u8]>) ->isize { |
| let r=BIG::new_ints(&rom::CURVE_ORDER); |
| |
| let mut sx:BIG; |
| |
| if let Some(mut rd)=rng |
| { |
| sx=BIG::randomnum(&r,rd); |
| if rom::AES_S>0 { |
| sx.mod2m(2*rom::AES_S); |
| } |
| sx.tobytes(x); |
| } else { |
| sx=BIG::frombytes(x); |
| } |
| |
| const RM:usize=rom::MODBYTES as usize; |
| let mut h:[u8;RM]=[0;RM]; |
| |
| hashit(sha,0,&client_id,&mut h); |
| let mut P=mapit(&h); |
| |
| let mut T=ECP::frombytes(&token); |
| if T.is_infinity() {return INVALID_POINT} |
| |
| let mut W=P.pinmul((pin as i32)%MAXPIN,PBLEN); |
| T.add(&mut W); |
| if date!=0 { |
| if let Some(rpermit)=permit {W=ECP::frombytes(&rpermit);} |
| if W.is_infinity() {return INVALID_POINT} |
| T.add(&mut W); |
| let mut h2:[u8;RM]=[0;RM]; |
| hashit(sha,date,&h,&mut h2); |
| W=mapit(&h2); |
| if let Some(mut rxid)=xid { |
| P=pair::g1mul(&mut P,&mut sx); |
| P.tobytes(&mut rxid); |
| W=pair::g1mul(&mut W,&mut sx); |
| P.add(&mut W); |
| } else { |
| P.add(&mut W); |
| P=pair::g1mul(&mut P,&mut sx); |
| } |
| if let Some(mut rxcid)=xcid {P.tobytes(&mut rxcid)} |
| } else { |
| if let Some(mut rxid)=xid { |
| P=pair::g1mul(&mut P,&mut sx); |
| P.tobytes(&mut rxid); |
| } |
| } |
| |
| T.tobytes(sec); |
| return 0; |
| } |
| |
| /* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */ |
| #[allow(non_snake_case)] |
| pub fn server_1(sha: usize,date: usize,cid: &[u8],hid: &mut [u8],htid: Option<&mut [u8]>) { |
| const RM:usize=rom::MODBYTES as usize; |
| let mut h:[u8;RM]=[0;RM]; |
| |
| hashit(sha,0,cid,&mut h); |
| |
| let mut P=mapit(&h); |
| |
| P.tobytes(hid); |
| if date!=0 { |
| let mut h2:[u8;RM]=[0;RM]; |
| hashit(sha,date,&h,&mut h2); |
| let mut R=mapit(&h2); |
| P.add(&mut R); |
| if let Some(rhtid)=htid {P.tobytes(rhtid);} |
| } |
| } |
| |
| /* Implement step 2 on client side of MPin protocol */ |
| #[allow(non_snake_case)] |
| pub fn client_2(x: &[u8],y: &[u8],sec: &mut [u8]) -> isize { |
| let mut r=BIG::new_ints(&rom::CURVE_ORDER); |
| let mut P=ECP::frombytes(sec); |
| if P.is_infinity() {return INVALID_POINT} |
| |
| let mut px=BIG::frombytes(x); |
| let py=BIG::frombytes(y); |
| px.add(&py); |
| px.rmod(&mut r); |
| //px.rsub(r) |
| |
| P=pair::g1mul(&mut P,&mut px); |
| P.neg(); |
| P.tobytes(sec); |
| |
| return 0; |
| } |
| |
| /* return time since epoch */ |
| pub fn get_time() -> usize { |
| return (SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()) as usize; |
| } |
| |
| /* Generate Y = H(epoch, xCID/xID) */ |
| pub fn get_y(sha: usize,timevalue: usize,xcid: &[u8],y: &mut [u8]) { |
| const RM:usize=rom::MODBYTES as usize; |
| let mut h:[u8;RM]=[0;RM]; |
| |
| hashit(sha,timevalue,xcid,&mut h); |
| |
| let mut sy= BIG::frombytes(&h); |
| let mut q=BIG::new_ints(&rom::CURVE_ORDER); |
| sy.rmod(&mut q); |
| if rom::AES_S>0 { |
| sy.mod2m(2*rom::AES_S); |
| } |
| sy.tobytes(y); |
| } |
| |
| /* Implement step 2 of MPin protocol on server side */ |
| #[allow(non_snake_case)] |
| pub fn server_2(date: usize,hid: &[u8],htid: Option<&[u8]>,y: &[u8],sst: &[u8],xid: Option<&[u8]>,xcid: Option<&[u8]>,msec: &[u8],e: Option<&mut [u8]>,f: Option<&mut [u8]>) -> isize { |
| // q:=NewBIGints(Modulus) |
| let mut Q=ECP2::new_fp2s(&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PXA),&BIG::new_ints(&rom::CURVE_PXB)),&FP2::new_bigs(&BIG::new_ints(&rom::CURVE_PYA),&BIG::new_ints(&rom::CURVE_PYB))); |
| |
| let mut sQ=ECP2::frombytes(&sst); |
| if sQ.is_infinity() {return INVALID_POINT} |
| |
| let mut R:ECP; |
| if date!=0 { |
| if let Some(rxcid)=xcid {R=ECP::frombytes(&rxcid);} |
| else {return BAD_PARAMS} |
| } else { |
| if let Some(rxid)=xid {R=ECP::frombytes(&rxid)} |
| else {return BAD_PARAMS} |
| } |
| if R.is_infinity() {return INVALID_POINT} |
| |
| let mut sy=BIG::frombytes(&y); |
| let mut P:ECP; |
| if date!=0 { |
| if let Some(rhtid)=htid {P=ECP::frombytes(&rhtid)} |
| else {return BAD_PARAMS} |
| } else { |
| P=ECP::frombytes(&hid); |
| } |
| |
| if P.is_infinity() {return INVALID_POINT} |
| |
| P=pair::g1mul(&mut P,&mut sy); |
| P.add(&mut R); |
| R=ECP::frombytes(&msec); |
| if R.is_infinity() {return INVALID_POINT} |
| |
| let mut g:FP12; |
| // FP12 g1=new FP12(0); |
| |
| g=pair::ate2(&mut Q,&mut R,&mut sQ,&mut P); |
| g=pair::fexp(&g); |
| |
| if !g.isunity() { |
| |
| if let Some(rxid)=xid { |
| if let Some(re)=e { |
| if let Some(rf)=f { |
| |
| g.tobytes(re); |
| if date!=0 { |
| P=ECP::frombytes(&hid); |
| if P.is_infinity() {return INVALID_POINT} |
| R=ECP::frombytes(&rxid); |
| if R.is_infinity() {return INVALID_POINT} |
| P=pair::g1mul(&mut P,&mut sy); |
| P.add(&mut R); |
| } |
| g=pair::ate(&mut Q,&mut P); |
| g=pair::fexp(&g); |
| g.tobytes(rf); |
| |
| } |
| } |
| } |
| |
| return BAD_PIN; |
| } |
| |
| return 0; |
| } |
| |
| /* Pollards kangaroos used to return PIN error */ |
| pub fn kangaroo(e: &[u8],f: &[u8]) -> isize { |
| let mut ge=FP12::frombytes(e); |
| let mut gf=FP12::frombytes(f); |
| let mut distance: [isize;TS]=[0;TS]; |
| let mut t=FP12::new_copy(&gf); |
| |
| let mut table: [FP12;TS]=[FP12::new();TS]; |
| let mut s:isize=1; |
| for m in 0..TS { |
| distance[m]=s; |
| table[m]=FP12::new_copy(&t); |
| s*=2; |
| t.usqr(); |
| } |
| t.one(); |
| let mut dn:isize=0; |
| let mut i:usize; |
| for _ in 0..TRAP { |
| i=(t.geta().geta().geta().lastbits(20)%(TS as isize)) as usize; |
| t.mul(&mut table[i]); |
| dn+=distance[i]; |
| } |
| gf.copy(&t); gf.conj(); |
| let mut steps:usize=0; let mut dm:isize=0; |
| let mut res:isize=0; |
| while dm-dn<MAXPIN as isize { |
| steps+=1; |
| if steps>4*TRAP {break} |
| i=(ge.geta().geta().geta().lastbits(20)%(TS as isize)) as usize; |
| ge.mul(&mut table[i]); |
| dm+=distance[i]; |
| if ge.equals(&mut t) { |
| res=dm-dn; |
| break; |
| } |
| if ge.equals(&mut gf) { |
| res=dn-dm; |
| break; |
| } |
| |
| } |
| if steps>4*TRAP || dm-dn>=MAXPIN as isize {res=0 } // Trap Failed - probable invalid token |
| return res; |
| } |
| |
| /* Hash the M-Pin transcript - new */ |
| |
| pub fn hash_all(sha: usize,hid: &[u8],xid: &[u8],xcid: Option<&[u8]>,sec: &[u8],y: &[u8],r: &[u8],w: &[u8],h: &mut[u8]) -> bool { |
| let mut tlen:usize=0; |
| const RM:usize=rom::MODBYTES as usize; |
| let mut t: [u8;10*RM+4]=[0;10*RM+4]; |
| |
| for i in 0 .. hid.len() {t[i]=hid[i]} |
| tlen+=hid.len(); |
| |
| if let Some(rxcid)=xcid { |
| for i in 0..rxcid.len() {t[i+tlen]=rxcid[i]} |
| tlen+=rxcid.len(); |
| } else { |
| for i in 0..xid.len() {t[i+tlen]=xid[i]} |
| tlen+=xid.len(); |
| } |
| |
| for i in 0..sec.len() {t[i+tlen]=sec[i]} |
| tlen+=sec.len(); |
| for i in 0..y.len() {t[i+tlen]=y[i]} |
| tlen+=y.len(); |
| for i in 0..r.len() {t[i+tlen]=r[i]} |
| tlen+=r.len(); |
| for i in 0..w.len() {t[i+tlen]=w[i]} |
| tlen+=w.len(); |
| if tlen!=10*RM+4 {return false} |
| |
| return hashit(sha,0,&t,h); |
| } |
| |
| /* calculate common key on client side */ |
| /* wCID = w.(A+AT) */ |
| #[allow(non_snake_case)] |
| pub fn client_key(sha: usize,g1: &[u8],g2: &[u8],pin: usize,r: &[u8],x: &[u8],h: &[u8],wcid: &[u8],ck: &mut [u8]) -> isize { |
| |
| let mut g1=FP12::frombytes(&g1); |
| let mut g2=FP12::frombytes(&g2); |
| let mut z=BIG::frombytes(&r); |
| let mut x=BIG::frombytes(&x); |
| let h=BIG::frombytes(&h); |
| |
| let mut W=ECP::frombytes(&wcid); |
| if W.is_infinity() {return INVALID_POINT} |
| |
| W=pair::g1mul(&mut W,&mut x); |
| |
| let mut f=FP2::new_bigs(&BIG::new_ints(&rom::CURVE_FRA),&BIG::new_ints(&rom::CURVE_FRB)); |
| let mut r=BIG::new_ints(&rom::CURVE_ORDER); |
| let q=BIG::new_ints(&rom::MODULUS); |
| |
| z.add(&h); //new |
| z.rmod(&mut r); |
| |
| let mut m=BIG::new_copy(&q); |
| m.rmod(&mut r); |
| |
| let mut a=BIG::new_copy(&z); |
| a.rmod(&mut m); |
| |
| let mut b=BIG::new_copy(&z); |
| b.div(&mut m); |
| |
| g2.pinpow(pin as i32,PBLEN); |
| g1.mul(&mut g2); |
| |
| let mut c=g1.trace(); |
| g2.copy(&g1); |
| g2.frob(&mut f); |
| let cp=g2.trace(); |
| g1.conj(); |
| g2.mul(&mut g1); |
| let cpm1=g2.trace(); |
| g2.mul(&mut g1); |
| let cpm2=g2.trace(); |
| |
| c=c.xtr_pow2(&cp,&cpm1,&cpm2,&mut a,&mut b); |
| |
| hash(sha,&mut c,&mut W,ck); |
| |
| return 0 |
| } |
| |
| /* calculate common key on server side */ |
| /* Z=r.A - no time permits involved */ |
| #[allow(non_snake_case)] |
| pub fn server_key(sha: usize,z: &[u8],sst: &[u8],w: &[u8],h: &[u8],hid: &[u8],xid: &[u8],xcid: Option<&[u8]>,sk: &mut [u8]) -> isize { |
| let mut sQ=ECP2::frombytes(&sst); |
| if sQ.is_infinity() {return INVALID_POINT} |
| let mut R=ECP::frombytes(&z); |
| if R.is_infinity() {return INVALID_POINT} |
| let mut A=ECP::frombytes(&hid); |
| if A.is_infinity() {return INVALID_POINT} |
| |
| let mut U=ECP::new(); |
| if let Some(rxcid)=xcid { |
| U.copy(&ECP::frombytes(&rxcid)); |
| } else { |
| U.copy(&ECP::frombytes(&xid)); |
| } |
| |
| if U.is_infinity() {return INVALID_POINT} |
| |
| let mut w=BIG::frombytes(&w); |
| let mut h=BIG::frombytes(&h); |
| A=pair::g1mul(&mut A,&mut h); // new |
| R.add(&mut A); |
| |
| U=pair::g1mul(&mut U,&mut w); |
| let mut g=pair::ate(&mut sQ,&mut R); |
| g=pair::fexp(&g); |
| |
| let mut c=g.trace(); |
| |
| hash(sha,&mut c,&mut U,sk); |
| |
| return 0 |
| } |
| |
| |