| using System; |
| |
| /* |
| 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. |
| */ |
| |
| /* MPIN API Functions */ |
| |
| public class MPIN |
| { |
| public static readonly int EFS = ROM.MODBYTES; |
| public static readonly int EGS = ROM.MODBYTES; |
| public const int PAS = 16; |
| public const int BAD_PARAMS = -11; |
| public const int INVALID_POINT = -14; |
| public const int WRONG_ORDER = -18; |
| public const int BAD_PIN = -19; |
| |
| /* Configure your PIN here */ |
| |
| public const int MAXPIN = 10000; // PIN less than this |
| public const int PBLEN = 14; // Number of bits in PIN |
| public const int TS = 10; // 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) |
| public const int TRAP = 200; // 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) |
| |
| /* Hash number (optional) and string to point on curve */ |
| |
| public static sbyte[] hashit(int n, sbyte[] ID) |
| { |
| HASH H = new HASH(); |
| if (n != 0) |
| { |
| H.process_num(n); |
| } |
| H.process_array(ID); |
| sbyte[] h = H.hash(); |
| return h; |
| } |
| |
| public static ECP mapit(sbyte[] h) |
| { |
| BIG q = new BIG(ROM.Modulus); |
| BIG x = BIG.fromBytes(h); |
| x.mod(q); |
| ECP P; |
| while (true) |
| { |
| P = new ECP(x,0); |
| if (!P.is_infinity()) |
| { |
| break; |
| } |
| x.inc(1); |
| x.norm(); |
| } |
| return P; |
| } |
| |
| /* needed for SOK */ |
| public static ECP2 mapit2(sbyte[] h) |
| { |
| BIG q = new BIG(ROM.Modulus); |
| BIG x = BIG.fromBytes(h); |
| BIG one = new BIG(1); |
| FP2 X; |
| ECP2 Q, T, K; |
| x.mod(q); |
| while (true) |
| { |
| X = new FP2(one,x); |
| Q = new ECP2(X); |
| if (!Q.is_infinity()) |
| { |
| break; |
| } |
| x.inc(1); |
| x.norm(); |
| } |
| /* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */ |
| BIG Fra = new BIG(ROM.CURVE_Fra); |
| BIG Frb = new BIG(ROM.CURVE_Frb); |
| X = new FP2(Fra,Frb); |
| x = new BIG(ROM.CURVE_Bnx); |
| |
| T = new ECP2(); |
| T.copy(Q); |
| T.mul(x); |
| T.neg(); |
| K = new ECP2(); |
| K.copy(T); |
| K.dbl(); |
| K.add(T); |
| K.affine(); |
| |
| K.frob(X); |
| Q.frob(X); |
| Q.frob(X); |
| Q.frob(X); |
| Q.add(T); |
| Q.add(K); |
| T.frob(X); |
| T.frob(X); |
| Q.add(T); |
| Q.affine(); |
| return Q; |
| } |
| |
| /* return time in slots since epoch */ |
| public static int today() |
| { |
| TimeSpan t = DateTime.Now- new DateTime(1970,1,1); |
| return (int)(t.TotalSeconds / (60 * 1440)); |
| } |
| |
| /* 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 */ |
| public static ECP map(BIG u, int cb) |
| { |
| ECP P; |
| BIG x = new BIG(u); |
| BIG p = new BIG(ROM.Modulus); |
| x.mod(p); |
| while (true) |
| { |
| P = new ECP(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 */ |
| public static int unmap(BIG u, ECP P) |
| { |
| int s = P.S; |
| ECP R; |
| int r = 0; |
| BIG x = P.X; |
| u.copy(x); |
| while (true) |
| { |
| u.dec(1); |
| u.norm(); |
| r++; |
| R = new ECP(u,s); |
| if (!R.is_infinity()) |
| { |
| break; |
| } |
| } |
| return r; |
| } |
| |
| public static sbyte[] HASH_ID(sbyte[] ID) |
| { |
| return hashit(0,ID); |
| } |
| |
| |
| /* 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 */ |
| public static int ENCODING(RAND rng, sbyte[] E) |
| { |
| int rn, m, su, sv; |
| sbyte[] T = new sbyte[EFS]; |
| |
| for (int i = 0;i < EFS;i++) |
| { |
| T[i] = E[i + 1]; |
| } |
| BIG u = BIG.fromBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| T[i] = E[i + EFS + 1]; |
| } |
| BIG v = BIG.fromBytes(T); |
| |
| ECP P = new ECP(u,v); |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| BIG p = new BIG(ROM.Modulus); |
| u = BIG.randomnum(p,rng); |
| |
| su = rng.Byte; //if (su<0) su=-su; |
| su %= 2; |
| |
| ECP W = map(u,su); |
| P.sub(W); |
| sv = P.S; |
| rn = unmap(v,P); |
| m = rng.Byte; //if (m<0) m=-m; |
| m %= rn; |
| v.inc(m + 1); |
| E[0] = (sbyte)(su + 2 * sv); |
| u.toBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| E[i + 1] = T[i]; |
| } |
| v.toBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| E[i + EFS + 1] = T[i]; |
| } |
| |
| return 0; |
| } |
| |
| public static int DECODING(sbyte[] D) |
| { |
| int su, sv; |
| sbyte[] T = new sbyte[EFS]; |
| |
| if ((D[0] & 0x04) != 0) |
| { |
| return INVALID_POINT; |
| } |
| |
| for (int i = 0;i < EFS;i++) |
| { |
| T[i] = D[i + 1]; |
| } |
| BIG u = BIG.fromBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| T[i] = D[i + EFS + 1]; |
| } |
| BIG v = BIG.fromBytes(T); |
| |
| su = D[0] & 1; |
| sv = (D[0] >> 1) & 1; |
| ECP W = map(u,su); |
| ECP P = map(v,sv); |
| P.add(W); |
| u = P.X; |
| v = P.Y; |
| D[0] = 0x04; |
| u.toBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| D[i + 1] = T[i]; |
| } |
| v.toBytes(T); |
| for (int i = 0;i < EFS;i++) |
| { |
| D[i + EFS + 1] = T[i]; |
| } |
| |
| return 0; |
| } |
| |
| /* R=R1+R2 in group G1 */ |
| public static int RECOMBINE_G1(sbyte[] R1, sbyte[] R2, sbyte[] R) |
| { |
| ECP P = ECP.fromBytes(R1); |
| ECP Q = ECP.fromBytes(R2); |
| |
| if (P.is_infinity() || Q.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| P.add(Q); |
| |
| P.toBytes(R); |
| return 0; |
| } |
| |
| /* W=W1+W2 in group G2 */ |
| public static int RECOMBINE_G2(sbyte[] W1, sbyte[] W2, sbyte[] W) |
| { |
| ECP2 P = ECP2.fromBytes(W1); |
| ECP2 Q = ECP2.fromBytes(W2); |
| |
| if (P.is_infinity() || Q.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| P.add(Q); |
| |
| P.toBytes(W); |
| return 0; |
| } |
| |
| /* create random secret S */ |
| public static int RANDOM_GENERATE(RAND rng, sbyte[] S) |
| { |
| BIG s; |
| BIG r = new BIG(ROM.CURVE_Order); |
| s = BIG.randomnum(r,rng); |
| |
| s.toBytes(S); |
| return 0; |
| } |
| |
| /* Extract PIN from TOKEN for identity CID */ |
| public static int EXTRACT_PIN(sbyte[] CID, int pin, sbyte[] TOKEN) |
| { |
| ECP P = ECP.fromBytes(TOKEN); |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| sbyte[] h = hashit(0,CID); |
| ECP R = mapit(h); |
| |
| |
| pin %= MAXPIN; |
| |
| R = R.pinmul(pin,PBLEN); |
| P.sub(R); |
| |
| P.toBytes(TOKEN); |
| |
| return 0; |
| } |
| |
| /* Implement step 2 on client side of MPin protocol */ |
| public static int CLIENT_2(sbyte[] X, sbyte[] Y, sbyte[] SEC) |
| { |
| BIG r = new BIG(ROM.CURVE_Order); |
| ECP P = ECP.fromBytes(SEC); |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| BIG px = BIG.fromBytes(X); |
| BIG py = BIG.fromBytes(Y); |
| px.add(py); |
| px.mod(r); |
| px.rsub(r); |
| |
| PAIR.G1mul(P,px).toBytes(SEC); |
| return 0; |
| } |
| |
| /* Implement step 1 on client side of MPin protocol */ |
| public static int CLIENT_1(int date, sbyte[] CLIENT_ID, RAND rng, sbyte[] X, int pin, sbyte[] TOKEN, sbyte[] SEC, sbyte[] xID, sbyte[] xCID, sbyte[] PERMIT) |
| { |
| BIG r = new BIG(ROM.CURVE_Order); |
| // BIG q=new BIG(ROM.Modulus); |
| BIG x; |
| // BIG m=new BIG(0); |
| if (rng != null) |
| { |
| x = BIG.randomnum(r,rng); |
| x.toBytes(X); |
| } |
| else |
| { |
| x = BIG.fromBytes(X); |
| } |
| ECP P, T, W; |
| BIG px; |
| // byte[] t=new byte[EFS]; |
| |
| sbyte[] h = hashit(0,CLIENT_ID); |
| P = mapit(h); |
| |
| T = ECP.fromBytes(TOKEN); |
| if (T.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| pin %= MAXPIN; |
| W = P.pinmul(pin,PBLEN); |
| T.add(W); |
| if (date != 0) |
| { |
| W = ECP.fromBytes(PERMIT); |
| if (W.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| T.add(W); |
| h = hashit(date,h); |
| W = mapit(h); |
| if (xID != null) |
| { |
| P = PAIR.G1mul(P,x); |
| P.toBytes(xID); |
| W = PAIR.G1mul(W,x); |
| P.add(W); |
| } |
| else |
| { |
| P.add(W); |
| P = PAIR.G1mul(P,x); |
| } |
| if (xCID != null) |
| { |
| P.toBytes(xCID); |
| } |
| } |
| else |
| { |
| if (xID != null) |
| { |
| P = PAIR.G1mul(P,x); |
| P.toBytes(xID); |
| } |
| } |
| |
| |
| T.toBytes(SEC); |
| return 0; |
| } |
| |
| /* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ |
| public static int GET_SERVER_SECRET(sbyte[] S, sbyte[] SST) |
| { |
| ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb))); |
| |
| BIG s = BIG.fromBytes(S); |
| Q = PAIR.G2mul(Q,s); |
| 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 |
| */ |
| public static int GET_G1_MULTIPLE(RAND rng, int type, sbyte[] X, sbyte[] G, sbyte[] W) |
| { |
| BIG x; |
| BIG r = new BIG(ROM.CURVE_Order); |
| if (rng != null) |
| { |
| x = BIG.randomnum(r,rng); |
| x.toBytes(X); |
| } |
| else |
| { |
| x = BIG.fromBytes(X); |
| } |
| ECP P; |
| if (type == 0) |
| { |
| P = ECP.fromBytes(G); |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| } |
| else |
| { |
| P = mapit(G); |
| } |
| |
| PAIR.G1mul(P,x).toBytes(W); |
| return 0; |
| } |
| |
| /* Client secret CST=S*H(CID) where CID is client ID and S is master secret */ |
| /* CID is hashed externally */ |
| public static int GET_CLIENT_SECRET(sbyte[] S, sbyte[] CID, sbyte[] CST) |
| { |
| return GET_G1_MULTIPLE(null,1,S,CID,CST); |
| } |
| |
| /* Time Permit CTT=S*(date|H(CID)) where S is master secret */ |
| public static int GET_CLIENT_PERMIT(int date, sbyte[] S, sbyte[] CID, sbyte[] CTT) |
| { |
| sbyte[] h = hashit(date,CID); |
| ECP P = mapit(h); |
| |
| BIG s = BIG.fromBytes(S); |
| PAIR.G1mul(P,s).toBytes(CTT); |
| return 0; |
| } |
| |
| /* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */ |
| public static void SERVER_1(int date, sbyte[] CID, sbyte[] HID, sbyte[] HTID) |
| { |
| sbyte[] h = hashit(0,CID); |
| ECP R , P = mapit(h); |
| |
| if (date != 0) |
| { |
| if (HID != null) |
| { |
| P.toBytes(HID); |
| } |
| h = hashit(date,h); |
| R = mapit(h); |
| P.add(R); |
| P.toBytes(HTID); |
| } |
| else |
| { |
| P.toBytes(HID); |
| } |
| } |
| |
| /* Implement step 2 of MPin protocol on server side */ |
| public static int SERVER_2(int date, sbyte[] HID, sbyte[] HTID, sbyte[] Y, sbyte[] SST, sbyte[] xID, sbyte[] xCID, sbyte[] mSEC, sbyte[] E, sbyte[] F) |
| { |
| BIG q = new BIG(ROM.Modulus); |
| ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb))); |
| ECP2 sQ = ECP2.fromBytes(SST); |
| if (sQ.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| ECP R; |
| if (date != 0) |
| { |
| R = ECP.fromBytes(xCID); |
| } |
| else |
| { |
| if (xID == null) |
| { |
| return BAD_PARAMS; |
| } |
| R = ECP.fromBytes(xID); |
| } |
| if (R.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| BIG y = BIG.fromBytes(Y); |
| ECP P; |
| if (date != 0) |
| { |
| P = ECP.fromBytes(HTID); |
| } |
| else |
| { |
| if (HID == null) |
| { |
| return BAD_PARAMS; |
| } |
| P = ECP.fromBytes(HID); |
| } |
| |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| P = PAIR.G1mul(P,y); |
| P.add(R); |
| R = ECP.fromBytes(mSEC); |
| if (R.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| FP12 g; |
| // FP12 g1=new FP12(0); |
| |
| g = PAIR.ate2(Q,R,sQ,P); |
| g = PAIR.fexp(g); |
| |
| if (!g.isunity()) |
| { |
| if (HID != null && xID != null && E != null && F != null) |
| { |
| g.toBytes(E); |
| if (date != 0) |
| { |
| P = ECP.fromBytes(HID); |
| if (P.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| R = ECP.fromBytes(xID); |
| if (R.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| P = PAIR.G1mul(P,y); |
| P.add(R); |
| } |
| g = PAIR.ate(Q,P); |
| g = PAIR.fexp(g); |
| g.toBytes(F); |
| } |
| return BAD_PIN; |
| } |
| |
| return 0; |
| } |
| |
| /* Pollards kangaroos used to return PIN error */ |
| public static int KANGAROO(sbyte[] E, sbyte[] F) |
| { |
| FP12 ge = FP12.fromBytes(E); |
| FP12 gf = FP12.fromBytes(F); |
| int[] distance = new int[TS]; |
| FP12 t = new FP12(gf); |
| FP12[] table = new FP12[TS]; |
| int i, j, m, s, dn, dm, res, steps; |
| |
| s = 1; |
| for (m = 0;m < TS;m++) |
| { |
| distance[m] = s; |
| table[m] = new FP12(t); |
| s *= 2; |
| t.usqr(); |
| } |
| t.one(); |
| dn = 0; |
| for (j = 0;j < TRAP;j++) |
| { |
| i = t.geta().geta().A.lastbits(8) % TS; |
| t.mul(table[i]); |
| dn += distance[i]; |
| } |
| gf.copy(t); |
| gf.conj(); |
| steps = 0; |
| dm = 0; |
| res = 0; |
| while (dm - dn < MAXPIN) |
| { |
| steps++; |
| if (steps > 4 * TRAP) |
| { |
| break; |
| } |
| i = ge.geta().geta().A.lastbits(8) % TS; |
| ge.mul(table[i]); |
| dm += distance[i]; |
| if (ge.Equals(t)) |
| { |
| res = dm - dn; |
| break; |
| } |
| if (ge.Equals(gf)) |
| { |
| res = dn - dm; |
| break; |
| } |
| |
| } |
| if (steps > 4 * TRAP || dm - dn >= MAXPIN) |
| { |
| res = 0; |
| } // Trap Failed - probable invalid token |
| return res; |
| } |
| |
| /* Functions to support M-Pin Full */ |
| |
| public static int PRECOMPUTE(sbyte[] TOKEN, sbyte[] CID, sbyte[] G1, sbyte[] G2) |
| { |
| ECP P, T; |
| FP12 g; |
| |
| T = ECP.fromBytes(TOKEN); |
| if (T.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| P = mapit(CID); |
| |
| ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa),new BIG(ROM.CURVE_Pxb)),new FP2(new BIG(ROM.CURVE_Pya),new BIG(ROM.CURVE_Pyb))); |
| |
| g = PAIR.ate(Q,T); |
| g = PAIR.fexp(g); |
| g.toBytes(G1); |
| |
| g = PAIR.ate(Q,P); |
| g = PAIR.fexp(g); |
| g.toBytes(G2); |
| |
| return 0; |
| } |
| |
| /* calculate common key on client side */ |
| /* wCID = w.(A+AT) */ |
| public static int CLIENT_KEY(sbyte[] G1, sbyte[] G2, int pin, sbyte[] R, sbyte[] X, sbyte[] wCID, sbyte[] CK) |
| { |
| HASH H = new HASH(); |
| sbyte[] t = new sbyte[EFS]; |
| |
| FP12 g1 = FP12.fromBytes(G1); |
| FP12 g2 = FP12.fromBytes(G2); |
| BIG z = BIG.fromBytes(R); |
| BIG x = BIG.fromBytes(X); |
| |
| ECP W = ECP.fromBytes(wCID); |
| if (W.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| W = PAIR.G1mul(W,x); |
| |
| FP2 f = new FP2(new BIG(ROM.CURVE_Fra),new BIG(ROM.CURVE_Frb)); |
| BIG r = new BIG(ROM.CURVE_Order); |
| BIG q = new BIG(ROM.Modulus); |
| |
| BIG m = new BIG(q); |
| m.mod(r); |
| |
| BIG a = new BIG(z); |
| a.mod(m); |
| |
| BIG b = new BIG(z); |
| b.div(m); |
| |
| g2.pinpow(pin,PBLEN); |
| g1.mul(g2); |
| |
| FP4 c = g1.trace(); |
| g2.copy(g1); |
| g2.frob(f); |
| FP4 cp = g2.trace(); |
| g1.conj(); |
| g2.mul(g1); |
| FP4 cpm1 = g2.trace(); |
| g2.mul(g1); |
| FP4 cpm2 = g2.trace(); |
| |
| c = c.xtr_pow2(cp,cpm1,cpm2,a,b); |
| |
| c.geta().A.toBytes(t); |
| H.process_array(t); |
| c.geta().B.toBytes(t); |
| H.process_array(t); |
| c.getb().A.toBytes(t); |
| H.process_array(t); |
| c.getb().B.toBytes(t); |
| H.process_array(t); |
| |
| W.X.toBytes(t); |
| H.process_array(t); |
| W.Y.toBytes(t); |
| H.process_array(t); |
| |
| t = H.hash(); |
| for (int i = 0;i < PAS;i++) |
| { |
| CK[i] = t[i]; |
| } |
| |
| return 0; |
| } |
| |
| /* calculate common key on server side */ |
| /* Z=r.A - no time permits involved */ |
| |
| public static int SERVER_KEY(sbyte[] Z, sbyte[] SST, sbyte[] W, sbyte[] xID, sbyte[] xCID, sbyte[] SK) |
| { |
| HASH H = new HASH(); |
| sbyte[] t = new sbyte[EFS]; |
| |
| ECP2 sQ = ECP2.fromBytes(SST); |
| if (sQ.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| ECP R = ECP.fromBytes(Z); |
| if (R.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| ECP U; |
| if (xCID != null) |
| { |
| U = ECP.fromBytes(xCID); |
| } |
| else |
| { |
| U = ECP.fromBytes(xID); |
| } |
| if (U.is_infinity()) |
| { |
| return INVALID_POINT; |
| } |
| |
| BIG w = BIG.fromBytes(W); |
| U = PAIR.G1mul(U,w); |
| FP12 g = PAIR.ate(sQ,R); |
| g = PAIR.fexp(g); |
| |
| FP4 c = g.trace(); |
| c.geta().A.toBytes(t); |
| H.process_array(t); |
| c.geta().B.toBytes(t); |
| H.process_array(t); |
| c.getb().A.toBytes(t); |
| H.process_array(t); |
| c.getb().B.toBytes(t); |
| H.process_array(t); |
| |
| U.X.toBytes(t); |
| H.process_array(t); |
| U.Y.toBytes(t); |
| H.process_array(t); |
| |
| t = H.hash(); |
| for (int i = 0;i < PAS;i++) |
| { |
| SK[i] = t[i]; |
| } |
| |
| return 0; |
| } |
| |
| /* return time since epoch */ |
| public static int GET_TIME() |
| { |
| DateTime date = DateTime.Now; |
| return (int)(date.Ticks / 1000); |
| } |
| |
| /* Generate Y = H(epoch, xCID/xID) */ |
| public static void GET_Y(int TimeValue, sbyte[] xCID, sbyte[] Y) |
| { |
| sbyte[] h = hashit(TimeValue,xCID); |
| BIG y = BIG.fromBytes(h); |
| BIG q = new BIG(ROM.CURVE_Order); |
| y.mod(q); |
| y.toBytes(Y); |
| } |
| |
| /* One pass MPIN Client */ |
| public static int CLIENT(int date, sbyte[] CLIENT_ID, RAND RNG, sbyte[] X, int pin, sbyte[] TOKEN, sbyte[] SEC, sbyte[] xID, sbyte[] xCID, sbyte[] PERMIT, int TimeValue, sbyte[] Y) |
| { |
| int rtn = 0; |
| |
| sbyte[] pID; |
| if (date == 0) |
| { |
| pID = xID; |
| } |
| else |
| { |
| pID = xCID; |
| } |
| |
| rtn = CLIENT_1(date,CLIENT_ID,RNG,X,pin,TOKEN,SEC,xID,xCID,PERMIT); |
| if (rtn != 0) |
| { |
| return rtn; |
| } |
| |
| GET_Y(TimeValue,pID,Y); |
| |
| rtn = CLIENT_2(X,Y,SEC); |
| if (rtn != 0) |
| { |
| return rtn; |
| } |
| |
| return 0; |
| } |
| |
| /* One pass MPIN Server */ |
| public static int SERVER(int date, sbyte[] HID, sbyte[] HTID, sbyte[] Y, sbyte[] SST, sbyte[] xID, sbyte[] xCID, sbyte[] SEC, sbyte[] E, sbyte[] F, sbyte[] CID, int TimeValue) |
| { |
| int rtn = 0; |
| |
| sbyte[] pID; |
| if (date == 0) |
| { |
| pID = xID; |
| } |
| else |
| { |
| pID = xCID; |
| } |
| |
| SERVER_1(date,CID,HID,HTID); |
| |
| GET_Y(TimeValue,pID,Y); |
| |
| rtn = SERVER_2(date,HID,HTID,Y,SST,xID,xCID,SEC,E,F); |
| if (rtn != 0) |
| { |
| return rtn; |
| } |
| |
| return 0; |
| } |
| |
| } |