| /* |
| 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. |
| */ |
| |
| /* test driver and function exerciser for MPIN Functions */ |
| /* Version 3.0 - supports Time Permits */ |
| |
| /* Build executible after installation: |
| |
| gcc -std=c99 -g ./testmpin.c -I/opt/amcl/include -L/opt/amcl/lib -lamcl_mpin_ZZZ -lamcl_pairing_ZZZ -lamcl_curve_ZZZ -lamcl_core -o testmpin_ZZZ |
| |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include "config_curve_ZZZ.h" |
| #include "randapi.h" |
| #if CURVE_SECURITY_ZZZ == 128 |
| #include "mpin_ZZZ.h" |
| #elif CURVE_SECURITY_ZZZ == 192 |
| #include "mpin192_ZZZ.h" |
| #elif CURVE_SECURITY_ZZZ == 256 |
| #include "mpin256_ZZZ.h" |
| #endif |
| |
| // Support multiple security levels |
| #if CURVE_SECURITY_ZZZ == 128 |
| #define G2LEN 4*PFS_ZZZ |
| #elif CURVE_SECURITY_ZZZ == 192 |
| #define G2LEN 8*PFS_ZZZ |
| #elif CURVE_SECURITY_ZZZ == 256 |
| #define G2LEN 16*PFS_ZZZ |
| #endif |
| #define GTLEN 3*G2LEN |
| |
| //#define PERMITS /* for time permits ON or OFF */ |
| #define PINERROR /* For PIN ERROR detection ON or OFF */ |
| #define FULL /* for M-Pin Full or M-Pin regular */ |
| //#define SINGLE_MPIN_PASS /* SINGLE MPIN_PASS M-Pin */ |
| |
| int mpin(csprng *RNG) |
| { |
| int pin,pin2,rtn,err; |
| #ifdef PERMITS |
| int date=today(); |
| #else |
| int date=0; |
| #endif |
| char x[PGS_ZZZ],s[PGS_ZZZ],y[PGS_ZZZ],client_id[100],sst[G2LEN],token[2*PFS_ZZZ+1],sec[2*PFS_ZZZ+1],permit[2*PFS_ZZZ+1],xcid[2*PFS_ZZZ+1],xid[2*PFS_ZZZ+1],e[GTLEN],f[GTLEN]; |
| char hcid[PFS_ZZZ],hsid[PFS_ZZZ],hid[2*PFS_ZZZ+1],htid[2*PFS_ZZZ+1],h[PGS_ZZZ]; |
| #ifdef FULL |
| char r[PGS_ZZZ],z[2*PFS_ZZZ+1],w[PGS_ZZZ],t[2*PFS_ZZZ+1]; |
| char g1[GTLEN],g2[GTLEN]; |
| char ck[AESKEY_ZZZ],sk[AESKEY_ZZZ]; |
| #endif |
| octet S= {0,sizeof(s),s}; |
| octet X= {0,sizeof(x),x}; |
| octet Y= {0,sizeof(y),y}; |
| octet H= {0,sizeof(h),h}; |
| octet CLIENT_ID= {0,sizeof(client_id),client_id}; |
| octet SST= {0,sizeof(sst),sst}; |
| octet TOKEN= {0,sizeof(token),token}; |
| octet SEC= {0,sizeof(sec),sec}; |
| octet PERMIT= {0,sizeof(permit),permit}; |
| octet xCID= {0,sizeof(xcid),xcid}; |
| octet xID= {0,sizeof(xid),xid}; |
| octet HCID= {0,sizeof(hcid),hcid}; |
| octet HSID= {0,sizeof(hsid),hsid}; |
| octet HID= {0,sizeof(hid),hid}; |
| octet HTID= {0,sizeof(htid),htid}; |
| octet E= {0,sizeof(e),e}; |
| octet F= {0,sizeof(f),f}; |
| #ifdef FULL |
| octet R= {0,sizeof(r),r}; |
| octet Z= {0,sizeof(z),z}; |
| octet W= {0,sizeof(w),w}; |
| octet T= {0,sizeof(t),t}; |
| octet G1= {0,sizeof(g1),g1}; |
| octet G2= {0,sizeof(g2),g2}; |
| octet SK= {0,sizeof(sk),sk}; |
| octet CK= {0,sizeof(ck),ck}; |
| #endif |
| octet *pxID,*pxCID,*pHID,*pHTID,*pE,*pF,*pPERMIT,*prHID; |
| char idhex[100]; |
| |
| /* Trusted Authority set-up */ |
| MPIN_ZZZ_RANDOM_GENERATE(RNG,&S); |
| printf("Master Secret= "); |
| OCT_output(&S); |
| |
| /* Create Client Identity */ |
| OCT_jstring(&CLIENT_ID,"testUser@milagro.com"); |
| HASH_ID(HASH_TYPE_ZZZ,&CLIENT_ID,&HCID); /* Either Client or TA calculates Hash(ID) - you decide! */ |
| |
| printf("Client ID Hash= "); |
| OCT_output(&HCID); |
| printf("\n"); |
| |
| OCT_toHex(&CLIENT_ID,idhex); |
| printf("Client ID= %s\n",idhex);// OCT_toHex(&CLIENT_ID); printf("\n"); |
| |
| /* Client and Server are issued secrets by DTA */ |
| MPIN_ZZZ_GET_SERVER_SECRET(&S,&SST); |
| printf("Server Secret= "); |
| OCT_output(&SST); |
| |
| MPIN_ZZZ_GET_CLIENT_SECRET(&S,&HCID,&TOKEN); |
| printf("Client Secret= "); |
| OCT_output(&TOKEN); |
| |
| /* Client extracts PIN from secret to create Token */ |
| pin=1234; |
| printf("Client extracts PIN= %d\n",pin); |
| MPIN_ZZZ_EXTRACT_PIN(HASH_TYPE_ZZZ,&CLIENT_ID,pin,&TOKEN); |
| printf("Client Token= "); |
| OCT_output(&TOKEN); |
| |
| #ifdef FULL |
| MPIN_ZZZ_PRECOMPUTE(&TOKEN,&HCID,NULL,&G1,&G2); |
| #endif |
| |
| /* Client extracts PIN2 generated from bio-metric from token */ |
| pin2=1212; |
| printf("Client extracts PIN= %d\n",pin2); |
| MPIN_ZZZ_EXTRACT_FACTOR(HASH_TYPE_ZZZ,&CLIENT_ID,pin2,14,&TOKEN); |
| printf("Client Token= "); |
| OCT_output(&TOKEN); |
| |
| #ifdef PERMITS |
| /* Client gets "Time Permit" from DTA */ |
| printf("Client gets Time Permit\n"); |
| |
| MPIN_ZZZ_GET_CLIENT_PERMIT(HASH_TYPE_ZZZ,date,&S,&HCID,&PERMIT); |
| printf("Time Permit= "); |
| OCT_output(&PERMIT); |
| |
| /* This encoding makes Time permit look random */ |
| if (MPIN_ZZZ_ENCODING(RNG,&PERMIT)!=0) printf("Encoding error\n"); |
| /* printf("Encoded Time Permit= "); OCT_output(&PERMIT); */ |
| if (MPIN_ZZZ_DECODING(&PERMIT)!=0) printf("Decoding error\n"); |
| /* printf("Decoded Time Permit= "); OCT_output(&PERMIT); */ |
| #endif |
| |
| /* MPin Protocol */ |
| |
| /* Client adds PIN2 generated from bio-metric to token */ |
| printf("Client adds PIN= %d\n",pin2); |
| MPIN_ZZZ_RESTORE_FACTOR(HASH_TYPE_ZZZ,&CLIENT_ID,pin2,14,&TOKEN); |
| printf("Client Token= "); |
| OCT_output(&TOKEN); |
| |
| /* Client enters PIN */ |
| printf("\nPIN= "); |
| if(scanf("%d",&pin)) {}; |
| /* to avoid silly compile error */ |
| getchar(); |
| |
| /* Set date=0 and PERMIT=NULL if time permits not in use |
| |
| Client First pass: Inputs CLIENT_ID, optional RNG, pin, TOKEN and PERMIT. Output xID = x.H(CLIENT_ID) and re-combined secret SEC |
| If PERMITS are is use, then date!=0 and PERMIT is added to secret and xCID = x.(H(CLIENT_ID)+H(date|H(CLIENT_ID))) |
| Random value x is supplied externally if RNG=NULL, otherwise generated and passed out by RNG |
| |
| HSID - hashed client ID as calculated by the server |
| HCID - hashed client ID as calculated by the client |
| |
| IMPORTANT: To save space and time.. |
| If Time Permits OFF set xCID = NULL, HTID=NULL and use xID and HID only |
| If Time permits are ON, AND pin error detection is required then all of xID, xCID, HID and HTID are required |
| If Time permits are ON, AND pin error detection is NOT required, set xID=NULL, HID=NULL and use xCID and HTID only. |
| |
| */ |
| |
| pxID=&xID; |
| pxCID=&xCID; |
| pHID=&HID; |
| pHTID=&HTID; |
| pE=&E; |
| pF=&F; |
| pPERMIT=&PERMIT; |
| |
| #ifdef PERMITS |
| prHID=pHTID; |
| #ifndef PINERROR |
| pxID=NULL; |
| // pHID=NULL; //new |
| #endif |
| #else |
| prHID=pHID; |
| pPERMIT=NULL; |
| pxCID=NULL; |
| pHTID=NULL; |
| #endif |
| #ifndef PINERROR |
| pE=NULL; |
| pF=NULL; |
| #endif |
| |
| #ifdef SINGLE_MPIN_PASS |
| int timeValue; |
| printf("MPIN Single Pass\n"); |
| timeValue = GET_TIME(); |
| |
| rtn=MPIN_ZZZ_CLIENT(HASH_TYPE_ZZZ,date,&CLIENT_ID,RNG,&X,pin,&TOKEN,&SEC,pxID,pxCID,pPERMIT,NULL,timeValue,&Y); |
| |
| if (rtn != 0) |
| { |
| printf("MPIN_ZZZ_CLIENT ERROR %d\n", rtn); |
| return 1; |
| } |
| |
| #ifdef FULL |
| MPIN_ZZZ_GET_G1_MULTIPLE(RNG,1,&R,&HCID,&Z); /* Also Send Z=r.ID to Server, remember random r */ |
| #endif |
| |
| |
| |
| rtn=MPIN_ZZZ_SERVER(HASH_TYPE_ZZZ,date,pHID,pHTID,&Y,&SST,pxID,pxCID,&SEC,pE,pF,&CLIENT_ID,NULL,timeValue,NULL); |
| |
| |
| #ifdef FULL |
| HASH_ID(HASH_TYPE_ZZZ,&CLIENT_ID,&HSID); // new |
| MPIN_ZZZ_GET_G1_MULTIPLE(RNG,0,&W,prHID,&T); /* Also send T=w.ID to client, remember random w */ |
| #endif |
| |
| #else // SINGLE_MPIN_PASS |
| printf("MPIN Multi Pass\n"); |
| if (MPIN_ZZZ_CLIENT_1(HASH_TYPE_ZZZ,date,&CLIENT_ID,RNG,&X,pin,&TOKEN,&SEC,pxID,pxCID,pPERMIT)!=0) |
| { |
| printf("Error from Client side - First pass\n"); |
| return 0; |
| } |
| |
| /* Send U=x.ID to server, and recreate secret from token and pin */ |
| |
| #ifdef FULL |
| HASH_ID(HASH_TYPE_ZZZ,&CLIENT_ID,&HCID); |
| MPIN_ZZZ_GET_G1_MULTIPLE(RNG,1,&R,&HCID,&Z); /* Also Send Z=r.ID to Server, remember random r, DH component */ |
| #endif |
| |
| /* Server calculates H(ID) and H(ID)+H(T|H(ID)) (if time permits enabled), and maps them to points on the curve HID and HTID resp. */ |
| MPIN_ZZZ_SERVER_1(HASH_TYPE_ZZZ,date,&CLIENT_ID,pHID,pHTID); |
| |
| /* Server generates Random number Y and sends it to Client */ |
| MPIN_ZZZ_RANDOM_GENERATE(RNG,&Y); |
| |
| #ifdef FULL |
| HASH_ID(HASH_TYPE_ZZZ,&CLIENT_ID,&HSID); //new |
| MPIN_ZZZ_GET_G1_MULTIPLE(RNG,0,&W,prHID,&T); /* Also send T=w.ID to client, remember random w, DH component */ |
| #endif |
| |
| /* Client Second pass: Inputs Client secret SEC, x and y. Outputs -(x+y)*SEC */ |
| if (MPIN_ZZZ_CLIENT_2(&X,&Y,&SEC)!=0) |
| { |
| printf("Error from Client side - Second MPIN pass\n"); |
| return 1; |
| } |
| |
| /* Server Second phase. Inputs hashed client id, random Y, -(x+y)*SEC, xID and xCID and Server secret SST. E and F help kangaroos to find error. */ |
| /* If PIN error not required, set E and F = NULL */ |
| |
| rtn=MPIN_ZZZ_SERVER_2(date,pHID,pHTID,&Y,&SST,pxID,pxCID,&SEC,pE,pF,NULL); |
| |
| #endif // SINGLE_MPIN_PASS |
| |
| if (rtn!=0) |
| { |
| printf("Server says - Bad Pin.\n"); |
| #ifdef PINERROR |
| |
| err=MPIN_ZZZ_KANGAROO(&E,&F); |
| if (err) printf("(Client PIN is out by %d)\n",err); |
| |
| #endif |
| return 1; |
| } |
| else |
| { |
| printf("Server says - PIN is good! You really are "); |
| OCT_output_string(&CLIENT_ID); |
| printf(".\n"); |
| } |
| |
| #ifdef FULL |
| HASH_ALL(HASH_TYPE_ZZZ,&HCID,pxID,pxCID,&SEC,&Y,&Z,&T,&H); // new |
| MPIN_ZZZ_CLIENT_KEY(HASH_TYPE_ZZZ,&G1,&G2,pin,&R,&X,&H,&T,&CK); // new H |
| printf("Client Key = "); |
| OCT_output(&CK); |
| |
| HASH_ALL(HASH_TYPE_ZZZ,&HSID,pxID,pxCID,&SEC,&Y,&Z,&T,&H); |
| MPIN_ZZZ_SERVER_KEY(HASH_TYPE_ZZZ,&Z,&SST,&W,&H,pHID,pxID,pxCID,&SK); // new H,pHID |
| printf("Server Key = "); |
| OCT_output(&SK); |
| #endif |
| |
| /* clear memory */ |
| OCT_clear(&S); |
| OCT_clear(&X); |
| OCT_clear(&Y); |
| OCT_clear(&H); |
| OCT_clear(&CLIENT_ID); |
| OCT_clear(&SST); |
| OCT_clear(&TOKEN); |
| OCT_clear(&SEC); |
| OCT_clear(&PERMIT); |
| OCT_clear(&xCID); |
| OCT_clear(&xID); |
| OCT_clear(&HCID); |
| OCT_clear(&HSID); |
| OCT_clear(&HID); |
| OCT_clear(&HTID); |
| OCT_clear(&E); |
| OCT_clear(&F); |
| #ifdef FULL |
| OCT_clear(&R); |
| OCT_clear(&Z); |
| OCT_clear(&W); |
| OCT_clear(&T); |
| OCT_clear(&G1); |
| OCT_clear(&G2); |
| OCT_clear(&SK); |
| OCT_clear(&CK); |
| #endif |
| |
| return 0; |
| } |
| |
| int main() |
| { |
| int i; |
| unsigned long ran; |
| |
| char raw[100]; |
| octet RAW= {0,sizeof(raw),raw}; |
| /* Crypto Strong RNG */ |
| csprng RNG; |
| |
| time((time_t *)&ran); |
| |
| /* fake random seed source */ |
| RAW.len=100; |
| RAW.val[0]=ran; |
| RAW.val[1]=ran>>8; |
| RAW.val[2]=ran>>16; |
| RAW.val[3]=ran>>24; |
| for (i=0; i<100; i++) RAW.val[i]=i+1; |
| |
| /* initialise strong RNG */ |
| CREATE_CSPRNG(&RNG,&RAW); |
| |
| mpin(&RNG); |
| |
| KILL_CSPRNG(&RNG); |
| } |
| |