| #!/usr/bin/env python |
| |
| """ |
| 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 |
| |
| This module use cffi to access the c functions in the mpin library. |
| |
| There is also an example usage program in this file. |
| |
| """ |
| import cffi |
| import platform |
| import os |
| |
| |
| ffi = cffi.FFI() |
| ffi.cdef(""" |
| typedef struct { |
| unsigned int ira[21]; /* random number... */ |
| int rndptr; /* ...array & pointer */ |
| unsigned int borrow; |
| int pool_ptr; |
| char pool[32]; /* random pool */ |
| } csprng; |
| |
| typedef struct |
| { |
| int len; |
| int max; |
| char *val; |
| } octet; |
| |
| |
| extern void CREATE_CSPRNG(csprng *R,octet *S); |
| extern void KILL_CSPRNG(csprng *R); |
| extern void OCT_clear(octet *O); |
| |
| extern void HASH_ID(int h,octet *ID,octet *HID); |
| extern unsigned int MPIN_ZZZ_GET_TIME(void); |
| extern void MPIN_ZZZ_GET_Y(int h,int t,octet *O,octet *Y); |
| extern int MPIN_ZZZ_EXTRACT_PIN(int h,octet *ID,int pin,octet *CS); |
| extern int MPIN_ZZZ_CLIENT(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet *T,octet *V,octet *U,octet *UT,octet *TP, octet* MESSAGE, int t, octet *y); |
| extern int MPIN_ZZZ_CLIENT_1(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet *T,octet *S,octet *U,octet *UT,octet *TP); |
| extern int MPIN_ZZZ_RANDOM_GENERATE(csprng *R,octet *S); |
| extern int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa); |
| extern int MPIN_ZZZ_CLIENT_2(octet *x,octet *y,octet *V); |
| extern int MPIN_ZZZ_SERVER(int h,int d,octet *HID,octet *HTID,octet *y,octet *SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE, int t,octet *Pa); |
| extern void MPIN_ZZZ_SERVER_1(int h,int d,octet *ID,octet *HID,octet *HTID); |
| extern int MPIN_ZZZ_SERVER_2(int d,octet *HID,octet *HTID,octet *y,octet *SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *Pa); |
| extern int MPIN_ZZZ_RECOMBINE_G1(octet *Q1,octet *Q2,octet *Q); |
| extern int MPIN_ZZZ_RECOMBINE_G2(octet *P1,octet *P2,octet *P); |
| extern int MPIN_ZZZ_KANGAROO(octet *E,octet *F); |
| extern int MPIN_ZZZ_ENCODING(csprng *R,octet *TP); |
| extern int MPIN_ZZZ_DECODING(octet *TP); |
| extern unsigned int today(void); |
| extern int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W); |
| extern int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W); |
| extern void HASH_ALL(int h,octet *I,octet *U,octet *CU,octet *Y,octet *V,octet *R,octet *W,octet *H); |
| extern int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *ID,octet *CS); |
| extern int MPIN_ZZZ_GET_CLIENT_PERMIT(int h,int d,octet *S,octet *ID,octet *TP); |
| extern int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SS); |
| extern int MPIN_ZZZ_PRECOMPUTE(octet *T,octet *ID,octet *CP,octet *g1,octet *g2); |
| extern int MPIN_ZZZ_SERVER_KEY(int h,octet *Z,octet *SS,octet *w,octet *p,octet *I,octet *U,octet *UT,octet *K); |
| extern int MPIN_ZZZ_CLIENT_KEY(int h,octet *g1,octet *g2,int pin,octet *r,octet *x,octet *p,octet *T,octet *K); |
| extern void AES_GCM_ENCRYPT(octet *K,octet *IV,octet *H,octet *P,octet *C,octet *T); |
| extern void AES_GCM_DECRYPT(octet *K,octet *IV,octet *H,octet *C,octet *P,octet *T); |
| extern void hex2bytes(char *hex, char *bin); |
| extern void generateRandom(csprng*, octet*); |
| extern int generateOTP(csprng*); |
| |
| |
| """) |
| |
| if (platform.system() == 'Windows'): |
| libamcl_mpin_ZZZ = ffi.dlopen("libamcl_mpin_ZZZ.dll") |
| libamcl_core = ffi.dlopen("libamcl_core.dll") |
| elif (platform.system() == 'Darwin'): |
| libamcl_mpin_ZZZ = ffi.dlopen("libamcl_mpin_ZZZ.dylib") |
| libamcl_core = ffi.dlopen("libamcl_core.dylib") |
| else: |
| libamcl_mpin_ZZZ = ffi.dlopen("libamcl_mpin_ZZZ.so") |
| libamcl_core = ffi.dlopen("libamcl_core.so") |
| |
| # MPIN Group Size |
| PGS = @NB@ |
| # MPIN Field Size |
| PFS = @NB@ |
| G1 = 2 * PFS + 1 |
| G2 = 4 * PFS |
| GT = 12 * PFS |
| # AES-GCM IV length |
| IVL = 12 |
| # MPIN Symmetric Key Size |
| PAS = 16 |
| |
| # Hash function choice |
| SHA256 = 32 |
| SHA384 = 48 |
| SHA512 = 64 |
| |
| |
| def to_hex(octet_value): |
| """Converts an octet type into a string |
| |
| Add all the values in an octet into an array. This arrays is then |
| converted to a string and hex encoded. |
| |
| Args:: |
| |
| octet_value. An octet pointer type |
| |
| Returns:: |
| |
| String |
| |
| Raises: |
| Exception |
| """ |
| i = 0 |
| val = [] |
| while i < octet_value.len: |
| val.append(octet_value.val[i]) |
| i = i + 1 |
| return ''.join(val).encode("hex") |
| |
| |
| def make_octet(length, value=None): |
| """Generates an octet pointer |
| |
| Generates an empty octet or one filled with the input value |
| |
| Args:: |
| |
| length: Length of empty octet |
| value: Data to assign to octet |
| |
| Returns:: |
| |
| oct_ptr: octet pointer |
| val: data associated with octet to prevent garbage collection |
| |
| Raises: |
| |
| """ |
| oct_ptr = ffi.new("octet*") |
| if value: |
| val = ffi.new("char [%s]" % len(value), value) |
| oct_ptr.val = val |
| oct_ptr.max = len(value) |
| oct_ptr.len = len(value) |
| else: |
| val = ffi.new("char []", length) |
| oct_ptr.val = val |
| oct_ptr.max = length |
| oct_ptr.len = length |
| return oct_ptr, val |
| |
| |
| def today(): |
| """Today's date as days elapsed from the epoch |
| |
| Today's date as days elapsed from the epoch. This function uses the system clock |
| |
| Args:: |
| |
| Returns:: |
| |
| epoch_date: epoch days |
| |
| Raises: |
| |
| """ |
| return libamcl_mpin_ZZZ.today() |
| |
| |
| def get_time(): |
| """Get time elapsed from the epoch |
| |
| Time elapsed from the epoch. This function uses the system clock |
| |
| Args:: |
| |
| Returns:: |
| |
| epoch_time: epoch time |
| |
| Raises: |
| |
| """ |
| return libamcl_mpin_ZZZ.MPIN_ZZZ_GET_TIME() |
| |
| |
| def create_csprng(seed): |
| """Make a Cryptographically secure pseudo-random number generator instance |
| |
| Make a Cryptographically secure pseudo-random number generator instance |
| |
| Args:: |
| |
| seed: random seed value |
| |
| Returns:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| |
| Raises: |
| |
| """ |
| seed_oct, seed_val = make_octet(None, seed) |
| |
| # random number generator |
| rng = ffi.new('csprng*') |
| libamcl_core.CREATE_CSPRNG(rng, seed_oct) |
| libamcl_core.OCT_clear(seed_oct) |
| |
| return rng |
| |
| |
| def kill_csprng(rng): |
| """Kill a random number generator |
| |
| Deletes all internal state |
| |
| Args:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| |
| Returns:: |
| |
| |
| |
| Raises: |
| |
| """ |
| libamcl_core.KILL_CSPRNG(rng) |
| |
| return 0 |
| |
| |
| def hash_id(hash_type, mpin_id): |
| """Hash an M-Pin Identity to an octet |
| |
| Hash an M-Pin Identity to an octet |
| |
| Args:: |
| |
| mpin_id: An octet pointer containing the M-Pin ID |
| |
| Returns:: |
| |
| hash_mpin_id: hash of the M-Pin ID |
| |
| Raises: |
| |
| """ |
| # Hash value of mpin_id |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| hash_mpin_id1, hash_mpin_id1_val = make_octet(PFS) |
| libamcl_core.HASH_ID(hash_type, mpin_id1, hash_mpin_id1) |
| |
| hash_mpin_id_hex = to_hex(hash_mpin_id1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(hash_mpin_id1) |
| |
| return hash_mpin_id_hex.decode("hex") |
| |
| |
| def random_generate(rng): |
| """Generate a random group element |
| |
| Generate a random group element |
| |
| Args:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| |
| Returns:: |
| |
| error_code: error from the C function |
| s: random group element |
| |
| Raises: |
| |
| """ |
| s1, s_val = make_octet(PGS) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_RANDOM_GENERATE(rng, s1) |
| |
| s_hex = to_hex(s1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(s1) |
| |
| return error_code, s_hex.decode("hex") |
| |
| |
| def get_dvs_keypair(rng): |
| """Create a public key in G2 for thee client |
| |
| Create a public in G2 for the client |
| |
| Args:: |
| |
| rng: a random number generator |
| |
| Returns:: |
| |
| error_code: error from the C function |
| z: private key |
| pa: public key |
| |
| Raises: |
| |
| """ |
| pa, pa_val = make_octet(G2) |
| z, z_val = make_octet(PFS) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_GET_DVS_KEYPAIR(rng, z, pa) |
| |
| pa_hex = to_hex(pa) |
| z_hex = to_hex(z) |
| |
| # clear memory |
| libamcl_core.OCT_clear(z) |
| libamcl_core.OCT_clear(pa) |
| |
| return error_code, z_hex.decode("hex"), pa_hex.decode("hex") |
| |
| |
| def get_server_secret(master_secret): |
| """Create a server secret in G2 from a master secret |
| |
| Create a server secret in G2 from a master secret |
| |
| Args:: |
| |
| master_secret: An octet pointer to the master secret |
| |
| Returns:: |
| |
| error_code: error from the C function |
| server_secret: Server secret |
| |
| Raises: |
| |
| """ |
| master_secret1, master_secret1_val = make_octet(None, master_secret) |
| server_secret1, server_secret1_val = make_octet(G2) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_GET_SERVER_SECRET( |
| master_secret1, server_secret1) |
| |
| server_secret_hex = to_hex(server_secret1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(master_secret1) |
| libamcl_core.OCT_clear(server_secret1) |
| |
| return error_code, server_secret_hex.decode("hex") |
| |
| |
| def recombine_G2(W1, W2): |
| """Add two members from the group G2 |
| |
| Add two members from the group G2 |
| |
| Args:: |
| |
| W1: An input member of G2 |
| W2: An input member of G2 |
| |
| Returns:: |
| |
| error_code: error from the C function |
| W: An output member of G1; W = W1+W2 |
| |
| Raises: |
| |
| """ |
| w11, w11_val = make_octet(None, W1) |
| w21, w21_val = make_octet(None, W2) |
| w1, w1_val = make_octet(G2) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_RECOMBINE_G2(w11, w21, w1) |
| |
| w_hex = to_hex(w1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(w11) |
| libamcl_core.OCT_clear(w21) |
| libamcl_core.OCT_clear(w1) |
| |
| return error_code, w_hex.decode("hex") |
| |
| |
| def get_client_secret(master_secret, hash_mpin_id): |
| """Create a client secret in G1 from a master secret and the hash of the M-Pin Id |
| |
| Create a client secret in G1 from a master secret and the hash of the M-Pin Id |
| |
| Args:: |
| |
| master_secret: An octet pointer to the master secret |
| hash_mpin_id: An octet pointer to the hash of the M-Pin ID |
| |
| Returns:: |
| |
| error_code: error from the C function |
| client_secret: Client secret |
| |
| Raises: |
| |
| """ |
| master_secret1, master_secret1_val = make_octet(None, master_secret) |
| hash_mpin_id1, hash_mpin_id1_val = make_octet(None, hash_mpin_id) |
| client_secret1, client_secret1_val = make_octet(G1) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_GET_CLIENT_SECRET( |
| master_secret1, hash_mpin_id1, client_secret1) |
| |
| client_secret_hex = to_hex(client_secret1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(master_secret1) |
| libamcl_core.OCT_clear(hash_mpin_id1) |
| libamcl_core.OCT_clear(client_secret1) |
| |
| return error_code, client_secret_hex.decode("hex") |
| |
| |
| def recombine_G1(q1, q2): |
| """Add two members from the group G1 |
| |
| Add two members from the group G1 |
| |
| Args:: |
| |
| q1: An input member of G1 |
| q2: An input member of G1 |
| |
| Returns:: |
| |
| error_code: error from the C function |
| q: An output member of G1 = Q1+Q2 |
| |
| Raises: |
| |
| """ |
| q11, q11_val = make_octet(None, q1) |
| q21, q21_val = make_octet(None, q2) |
| q1, q1_val = make_octet(G1) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_RECOMBINE_G1(q11, q21, q1) |
| |
| q_hex = to_hex(q1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(q11) |
| libamcl_core.OCT_clear(q21) |
| libamcl_core.OCT_clear(q1) |
| |
| return error_code, q_hex.decode("hex") |
| |
| |
| def get_client_permit(hash_type, epoch_date, master_secret, hash_mpin_id): |
| """Create a time permit in G1 from a master secret, hash of the M-Pin Id and epoch days |
| |
| Create a time permit in G1 from a master secret, hash of the M-Pin Id and epoch days |
| |
| Args:: |
| |
| epoch_date: Epoch days |
| master_secret: An octet pointer to the master secret |
| hash_mpin_id: An octet pointer to the hash of the M-Pin ID |
| |
| Returns:: |
| |
| error_code: error from the C function |
| time_permit: Time permit |
| |
| Raises: |
| |
| """ |
| master_secret1, master_secret1_val = make_octet(None, master_secret) |
| hash_mpin_id1, hash_mpin_id1_val = make_octet(None, hash_mpin_id) |
| time_permit1, time_permit1_val = make_octet(G1) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_GET_CLIENT_PERMIT( |
| hash_type, |
| epoch_date, |
| master_secret1, |
| hash_mpin_id1, |
| time_permit1) |
| |
| time_permit_hex = to_hex(time_permit1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(master_secret1) |
| libamcl_core.OCT_clear(hash_mpin_id1) |
| libamcl_core.OCT_clear(time_permit1) |
| |
| return error_code, time_permit_hex.decode("hex") |
| |
| |
| def extract_pin(hash_type, mpin_id, pin, client_secret): |
| """Extract a PIN from client secret |
| |
| Extract a PIN from client secret |
| |
| Args:: |
| |
| mpin_id: M-Pin ID |
| pin: PIN input by user |
| client_secret: User's client secret |
| |
| Returns:: |
| |
| error_code: error from the C function |
| token: Result of extracting a PIN from client secret |
| |
| Raises: |
| |
| """ |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| client_secret1, client_secret1_val = make_octet(None, client_secret) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_EXTRACT_PIN( |
| hash_type, mpin_id1, pin, client_secret1) |
| |
| client_secret_hex = to_hex(client_secret1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(client_secret1) |
| |
| return error_code, client_secret_hex.decode("hex") |
| |
| |
| def precompute(token, hash_mpin_id): |
| """Precompute values for use by the client side of M-Pin Full |
| |
| Precompute values for use by the client side of M-Pin Full |
| |
| Args:: |
| |
| token: M-Pin token |
| hash_mpin_id: hash of the M-Pin ID |
| |
| Returns:: |
| |
| error_code: error from the C function |
| pc1: Precomputed value one |
| pc2: Precomputed value two |
| |
| Raises: |
| |
| """ |
| token1, token1_val = make_octet(None, token) |
| hash_mpin_id1, hash_mpin_id1_val = make_octet(None, hash_mpin_id) |
| pc11, pc11_val = make_octet(GT) |
| pc21, pc21_val = make_octet(GT) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_PRECOMPUTE( |
| token1, hash_mpin_id1, ffi.NULL, pc11, pc21) |
| |
| pc1_hex = to_hex(pc11) |
| pc2_hex = to_hex(pc21) |
| |
| # clear memory |
| libamcl_core.OCT_clear(token1) |
| libamcl_core.OCT_clear(hash_mpin_id1) |
| libamcl_core.OCT_clear(pc11) |
| libamcl_core.OCT_clear(pc21) |
| |
| return error_code, pc1_hex.decode("hex"), pc2_hex.decode("hex") |
| |
| |
| def client_1(hash_type, epoch_date, mpin_id, rng, x, pin, token, time_permit): |
| """Perform first pass of the client side of the three pass version of the M-Pin protocol |
| |
| Perform first pass of the client side of the three pass version of the M-Pin protocol. |
| If Time Permits are disabled then set epoch_date = 0.In this case UT is not generated0 |
| and can be set to None. If Time Permits are enabled, and PIN error detection is OFF, |
| U is not generated and can be set to None. If Time Permits are enabled and PIN error |
| detection is ON then U and UT are both generated. |
| |
| |
| Args:: |
| |
| epoch_date: Date, in days since the epoch. Set to 0 if Time permits disabled |
| mpin_id: M-Pin ID |
| rng: cryptographically secure random number generator |
| pin: PIN entered by user |
| token: M-Pin token |
| time_permit: M-Pin time permit |
| |
| Returns:: |
| |
| error_code: error from the C function |
| x: Randomly generated integer if RNG!=None, otherwise must be provided as an input |
| u: u = x.H(ID) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| v: v = CS+TP, where CS is the reconstructed client secret and TP is the time permit |
| |
| Raises: |
| |
| """ |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| token1, token1_val = make_octet(None, token) |
| if time_permit: |
| time_permit1, time_permit1_val = make_octet(None, time_permit) |
| else: |
| time_permit1 = ffi.NULL |
| |
| if rng is None: |
| x1, x1_val = make_octet(None, x) |
| rng = ffi.NULL |
| else: |
| x1, x1_val = make_octet(PGS) |
| |
| u1, u1_val = make_octet(G1) |
| ut1, ut1_val = make_octet(G1) |
| v1, v1_val = make_octet(G1) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_CLIENT_1( |
| hash_type, |
| epoch_date, |
| mpin_id1, |
| rng, |
| x1, |
| pin, |
| token1, |
| v1, |
| u1, |
| ut1, |
| time_permit1) |
| |
| x_hex = to_hex(x1) |
| u_hex = to_hex(u1) |
| ut_hex = to_hex(ut1) |
| v_hex = to_hex(v1) |
| |
| # clear memory |
| if time_permit: |
| libamcl_core.OCT_clear(time_permit1) |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(token1) |
| libamcl_core.OCT_clear(x1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(v1) |
| |
| return error_code, x_hex.decode("hex"), u_hex.decode( |
| "hex"), ut_hex.decode("hex"), v_hex.decode("hex") |
| |
| |
| def client_2(x, y, sec): |
| """Perform second pass of the client side of the 3-pass version of the M-Pin protocol |
| |
| Perform second pass of the client side of the 3-pass version of the M-Pin protocol |
| |
| Args:: |
| |
| x: locally generated random number |
| y: random challenge from server |
| sec: CS+TP, where CS is the reconstructed client secret and TP is the time permit |
| |
| Returns:: |
| |
| error_code: error from the C function |
| v: v = -(x+y)(CS+TP), where CS is the reconstructed client secret and TP is the time permit |
| |
| Raises: |
| |
| """ |
| x1, x1_val = make_octet(None, x) |
| y1, y1_val = make_octet(None, y) |
| sec1, sec1_val = make_octet(None, sec) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_CLIENT_2(x1, y1, sec1) |
| |
| sec_hex = to_hex(sec1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(x1) |
| libamcl_core.OCT_clear(y1) |
| libamcl_core.OCT_clear(sec1) |
| |
| return error_code, sec_hex.decode("hex") |
| |
| |
| def client(hash_type, epoch_date, mpin_id, rng, x, pin, token, |
| time_permit, message, epoch_time): |
| """Perform client side of the one-pass version of the M-Pin protocol |
| |
| Perform client side of the one-pass version of the M-Pin protocol. If Time Permits are |
| disabled then set epoch_date = 0.In this case UT is not generated and can be set to None. |
| If Time Permits are enabled, and PIN error detection is OFF, U is not generated and |
| can be set to None. If Time Permits are enabled and PIN error detection is ON then U |
| and UT are both generated. |
| |
| Args:: |
| |
| epoch_date: Date, in days since the epoch. Set to 0 if Time permits disabled |
| mpin_id: M-Pin ID |
| rng: cryptographically secure random number generator |
| pin: PIN entered by user |
| token: M-Pin token |
| time_permit: M-Pin time permit |
| message: message to be signed |
| epoch_time: Epoch time in seconds |
| |
| Returns:: |
| |
| error_code: error from the C function |
| x: Randomly generated integer if RNG!=None, otherwise must be provided as an input |
| u: u = x.H(ID) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| v: v = -(x+y)(CS+TP), where CS is the reconstructed client secret and TP is the time permit |
| y: y = t H(t|U) or y = H(t|UT) if Time Permits enabled |
| |
| Raises: |
| |
| """ |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| token1, token1_val = make_octet(None, token) |
| if time_permit: |
| time_permit1, time_permit1_val = make_octet(None, time_permit) |
| else: |
| time_permit1 = ffi.NULL |
| |
| if rng is not None: |
| x1, x1_val = make_octet(PGS) |
| else: |
| x1, x1_val = make_octet(None, x) |
| |
| if message is None: |
| message1 = ffi.NULL |
| else: |
| message1, message1_val = make_octet(None, message) |
| |
| u1, u1_val = make_octet(G1) |
| ut1, ut1_val = make_octet(G1) |
| v1, v1_val = make_octet(G1) |
| y1, y1_val = make_octet(PGS) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_CLIENT( |
| hash_type, |
| epoch_date, |
| mpin_id1, |
| rng, |
| x1, |
| pin, |
| token1, |
| v1, |
| u1, |
| ut1, |
| time_permit1, |
| message1, |
| epoch_time, |
| y1) |
| |
| x_hex = to_hex(x1) |
| u_hex = to_hex(u1) |
| ut_hex = to_hex(ut1) |
| v_hex = to_hex(v1) |
| y_hex = to_hex(y1) |
| |
| # clear memory |
| if time_permit: |
| libamcl_core.OCT_clear(time_permit1) |
| if message: |
| libamcl_core.OCT_clear(message1) |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(token1) |
| libamcl_core.OCT_clear(x1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(v1) |
| libamcl_core.OCT_clear(y1) |
| |
| return error_code, x_hex.decode("hex"), u_hex.decode( |
| "hex"), ut_hex.decode("hex"), v_hex.decode("hex"), y_hex.decode("hex") |
| |
| |
| def get_G1_multiple(rng, type, x, P): |
| """Find a random multiple of a point in G1 |
| |
| Calculate W=x*P where random x < q is the order of the group of points on the curve. |
| When rng is None x is passed in otherwise it is passed out. |
| |
| If type=0 then P is. point on the curve or else P is an octet that has to be |
| mapped to the curve |
| |
| Args:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| type: determines type of action to be taken |
| P: if type=0 a point in G1, else an octet to be mapped to G1 |
| |
| Returns:: |
| |
| error_code: error from the C function |
| x: an output internally randomly generated if rng!=None, otherwise must be provided as an input |
| W: W = x.P or W = x.M(P), where M(.) is a mapping when type = 0 |
| |
| Raises: |
| |
| """ |
| if rng is not None: |
| x1, x1_val = make_octet(PGS) |
| rng_in = rng |
| else: |
| x1, x1_val = make_octet(None, x) |
| rng_in = ffi.NULL |
| P1, P1_val = make_octet(None, P) |
| W1, W1_val = make_octet(G1) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_GET_G1_MULTIPLE( |
| rng_in, type, x1, P1, W1) |
| |
| x_hex = to_hex(x1) |
| W_hex = to_hex(W1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(x1) |
| libamcl_core.OCT_clear(P1) |
| libamcl_core.OCT_clear(W1) |
| |
| return error_code, x_hex.decode("hex"), W_hex.decode("hex") |
| |
| |
| def server_1(hash_type, epoch_date, mpin_id): |
| """Perform first pass of the server side of the 3-pass version of the M-Pin protocol |
| |
| Perform first pass of the server side of the 3-pass version of the M-Pin protocol |
| If Time Permits are disabled, set epoch_date = 0, and UT and HTID are not generated |
| and can be set to None. If Time Permits are enabled, and PIN error detection is OFF, |
| U and HID are not needed and caxn be set to None. If Time Permits are enabled, |
| and PIN error detection is ON, U, UT, HID and HTID are all required. |
| |
| Args:: |
| |
| epoch_date: Date, in days since the epoch. Set to 0 if Time permits disabled |
| mpin_id: M-Pin ID or hash of the M-Pin ID in anonymous mode |
| |
| Returns:: |
| |
| HID: H(mpin_id). H is a map to a point on the curve |
| HTID: H(mpin_id)+H(epoch_date|H(mpin_id)). H is a map to a point on the curve |
| |
| Raises: |
| |
| """ |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| HTID1, HTID1_val = make_octet(G1) |
| HID1, HID1_val = make_octet(G1) |
| |
| libamcl_mpin_ZZZ.MPIN_ZZZ_SERVER_1( |
| hash_type, epoch_date, mpin_id1, HID1, HTID1) |
| |
| HID_hex = to_hex(HID1) |
| HTID_hex = to_hex(HTID1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(HTID1) |
| libamcl_core.OCT_clear(HID1) |
| |
| return HID_hex.decode("hex"), HTID_hex.decode("hex") |
| |
| |
| def server_2(epoch_date, HID, HTID, y, server_secret, u, ut, v, pa): |
| """Perform third pass on the server side of the 3-pass version of the M-Pin protocol |
| |
| Perform server side of the three-pass version of the M-Pin protocol. If Time |
| Permits are disabled, set epoch_date = 0, and UT and HTID are not generated and can |
| be set to None. If Time Permits are enabled, and PIN error detection is OFF, |
| U and HID are not needed and can be set to None. If Time Permits are enabled, |
| and PIN error detection is ON, U, UT, HID and HTID are all required. |
| |
| Args:: |
| |
| epoch_date: Date, in days since the epoch. Set to 0 if Time permits disabled |
| HID: H(mpin_id). H is a map to a point on the curve |
| HTID: H(mpin_id)+H(epoch_date|H(mpin_id)). H is a map to a point on the curve |
| y: locally generated random number |
| server_secret: Server secret |
| u: u = x.H(ID) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| v: v = -(x+y)(CS+TP), where CS is the reconstructed client secret and TP is the time permit |
| pa: client's public key for key-escrow-less |
| |
| Returns:: |
| |
| error_code: error from the C function |
| e: value to help the Kangaroos to find the PIN error, or None if not required |
| f: value to help the Kangaroos to find the PIN error, or None if not required |
| |
| Raises: |
| |
| """ |
| HID1, HID1_val = make_octet(None, HID) |
| HTID1, HTID1_val = make_octet(None, HTID) |
| y1, y1_val = make_octet(None, y) |
| server_secret1, server_secret1_val = make_octet(None, server_secret) |
| u1, u1_val = make_octet(None, u) |
| ut1, ut1_val = make_octet(None, ut) |
| v1, v1_val = make_octet(None, v) |
| if pa is None: |
| pa1 = ffi.NULL |
| else: |
| pa1, pa1_val = make_octet(None, pa) |
| |
| e1, e1_val = make_octet(GT) |
| f1, f1_val = make_octet(GT) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_SERVER_2( |
| epoch_date, |
| HID1, |
| HTID1, |
| y1, |
| server_secret1, |
| u1, |
| ut1, |
| v1, |
| e1, |
| f1, |
| pa1) |
| |
| e_hex = to_hex(e1) |
| f_hex = to_hex(f1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(HID1) |
| libamcl_core.OCT_clear(HTID1) |
| libamcl_core.OCT_clear(y1) |
| libamcl_core.OCT_clear(server_secret1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(v1) |
| libamcl_core.OCT_clear(e1) |
| libamcl_core.OCT_clear(f1) |
| |
| return error_code, e_hex.decode("hex"), f_hex.decode("hex") |
| |
| |
| def server(hash_type, epoch_date, server_secret, |
| u, ut, v, mpin_id, message, epoch_time, pa): |
| """Perform server side of the one-pass version of the M-Pin protocol |
| |
| Perform server side of the one-pass version of the M-Pin protocol. If Time |
| Permits are disabled, set epoch_date = 0, and UT and HTID are not generated and can |
| be set to None. If Time Permits are enabled, and PIN error detection is OFF, |
| U and HID are not needed and can be set to None. If Time Permits are enabled, |
| and PIN error detection is ON, U, UT, HID and HTID are all required. |
| |
| Args:: |
| |
| epoch_date: Date, in days since the epoch. Set to 0 if Time permits disabled |
| server_secret: Server secret |
| u: u = x.H(ID) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| v: v = -(x+y)(CS+TP), where CS is the reconstructed client secret and TP is the time permit |
| mpin_id: M-Pin ID or hash of the M-Pin ID in anonymous mode |
| message: message to be signed |
| epoch_time: Epoch time in seconds |
| pa: client's public key for key-escrow-less |
| |
| Returns:: |
| |
| error_code: error from the C function |
| HID: H(mpin_id). H is a map to a point on the curve |
| HTID: H(mpin_id)+H(epoch_date|H(mpin_id)). H is a map to a point on the curve |
| e: value to help the Kangaroos to find the PIN error, or None if not required |
| f: value to help the Kangaroos to find the PIN error, or None if not required |
| y: y = t H(t|U) or y = H(t|UT) if Time Permits enabled used for debug |
| |
| Raises: |
| |
| """ |
| if message is None: |
| message1 = ffi.NULL |
| else: |
| message1, message1_val = make_octet(None, message) |
| |
| server_secret1, server_secret1_val = make_octet(None, server_secret) |
| u1, u1_val = make_octet(None, u) |
| ut1, ut1_val = make_octet(None, ut) |
| v1, v1_val = make_octet(None, v) |
| mpin_id1, mpin_id1_val = make_octet(None, mpin_id) |
| |
| HTID1, HTID1_val = make_octet(G1) |
| HID1, HID1_val = make_octet(G1) |
| e1, e1_val = make_octet(GT) |
| f1, f1_val = make_octet(GT) |
| y1, y1_val = make_octet(PGS) |
| if pa is None: |
| pa1 = ffi.NULL |
| else: |
| pa1, pa1_val = make_octet(None, pa) |
| |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_SERVER( |
| hash_type, |
| epoch_date, |
| HID1, |
| HTID1, |
| y1, |
| server_secret1, |
| u1, |
| ut1, |
| v1, |
| e1, |
| f1, |
| mpin_id1, |
| message1, |
| epoch_time, |
| pa1) |
| |
| HID_hex = to_hex(HID1) |
| HTID_hex = to_hex(HTID1) |
| e_hex = to_hex(e1) |
| f_hex = to_hex(f1) |
| y_hex = to_hex(y1) |
| |
| # clear memory |
| if message: |
| libamcl_core.OCT_clear(message1) |
| libamcl_core.OCT_clear(server_secret1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(mpin_id1) |
| libamcl_core.OCT_clear(v1) |
| libamcl_core.OCT_clear(HID1) |
| libamcl_core.OCT_clear(HTID1) |
| libamcl_core.OCT_clear(e1) |
| libamcl_core.OCT_clear(f1) |
| libamcl_core.OCT_clear(y1) |
| |
| return error_code, HID_hex.decode("hex"), HTID_hex.decode( |
| "hex"), e_hex.decode("hex"), f_hex.decode("hex"), y_hex.decode("hex") |
| |
| |
| def kangaroo(e, f): |
| """Use Pollards Kangaroos to find PIN error |
| |
| Use Pollards Kangaroos to find PIN error |
| |
| Args:: |
| |
| e: a member of the group GT |
| f: a member of the group GT = E^pin_error |
| |
| Returns:: |
| |
| pin_error: error in PIN or 0 if Kangaroos failed |
| |
| Raises: |
| |
| """ |
| e1, e1_val = make_octet(None, e) |
| f1, f1_val = make_octet(None, f) |
| |
| # clear memory |
| libamcl_core.OCT_clear(e1) |
| libamcl_core.OCT_clear(f1) |
| |
| pin_error = libamcl_mpin_ZZZ.MPIN_ZZZ_KANGAROO(e1, f1) |
| |
| return pin_error |
| |
| |
| def hash_all(hash_type, hash_mpin_id, u, ut, v, y, z, t): |
| """Hash the session transcript |
| |
| Hash the session transcript |
| |
| Args:: |
| |
| hash_mpin_id: An octet pointer to the hash of the M-Pin ID |
| u: u = x.H(mpin_id) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| v: v = -(x+y)(CS+TP), where CS is the reconstructed client secret and TP is the time permit |
| y: server challenge |
| z: client part response |
| t: server part response |
| |
| Returns:: |
| |
| hm: hash of the input values |
| |
| Raises: |
| |
| """ |
| if ut is None: |
| ut1 = ffi.NULL |
| else: |
| ut1, ut1_val = make_octet(None, ut) |
| hash_mpin_id1, hash_mpin_id1_val = make_octet(None, hash_mpin_id) |
| u1, u1_val = make_octet(None, u) |
| v1, v1_val = make_octet(None, v) |
| y1, y1_val = make_octet(None, y) |
| z1, z1_val = make_octet(None, z) |
| t1, w1_val = make_octet(None, t) |
| |
| hm1, hm1_val = make_octet(PFS) |
| libamcl_core.HASH_ALL(hash_type, hash_mpin_id1, |
| u1, ut1, v1, y1, z1, t1, hm1) |
| |
| hm_hex = to_hex(hm1) |
| |
| # clear memory |
| if ut: |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(hash_mpin_id1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(v1) |
| libamcl_core.OCT_clear(y1) |
| libamcl_core.OCT_clear(z1) |
| libamcl_core.OCT_clear(t1) |
| |
| return hm_hex.decode("hex") |
| |
| |
| def client_key(hash_type, pc1, pc2, pin, r, x, hm, t): |
| """Calculate Key on Client side for M-Pin Full |
| |
| Calculate Key on Client side for M-Pin Full |
| |
| Args:: |
| |
| pc1: precomputed input |
| pc2: precomputed input |
| pin: PIN number |
| r: locally generated random number |
| x: locally generated random number |
| hm: hash of the protocol transcript |
| t: Server-side Diffie-Hellman component |
| |
| Returns:: |
| |
| error_code: error code from the C function |
| client_aes_key: client AES key |
| |
| Raises: |
| |
| """ |
| pc11, pc11_val = make_octet(None, pc1) |
| pc21, pc21_val = make_octet(None, pc2) |
| r1, r1_val = make_octet(None, r) |
| x1, x1_val = make_octet(None, x) |
| hm1, hm1_val = make_octet(None, hm) |
| t1, t1_val = make_octet(None, t) |
| client_aes_key1, client_aes_key_val1 = make_octet(PAS) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_CLIENT_KEY( |
| hash_type, |
| pc11, |
| pc21, |
| pin, |
| r1, |
| x1, |
| hm1, |
| t1, |
| client_aes_key1) |
| |
| client_aes_key_hex = to_hex(client_aes_key1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(pc11) |
| libamcl_core.OCT_clear(pc21) |
| libamcl_core.OCT_clear(r1) |
| libamcl_core.OCT_clear(x1) |
| libamcl_core.OCT_clear(hm1) |
| libamcl_core.OCT_clear(t1) |
| libamcl_core.OCT_clear(client_aes_key1) |
| |
| return error_code, client_aes_key_hex.decode("hex") |
| |
| |
| def server_key(hash_type, z, server_secret, w, hm, HID, u, ut): |
| """Calculate Key on Server side for M-Pin Full |
| |
| Calculate Key on Server side for M-Pin Full.Uses UT internally for the |
| key calculation or uses U if UT is set to None |
| |
| Args:: |
| |
| z: Client-side Diffie-Hellman component |
| server_secret: server secret |
| w: random number generated by the server |
| hm: hash of the protocol transcript |
| HID: H(mpin_id). H is a map to a point on the curve |
| u: u = x.H(ID) |
| ut: ut = x.(H(ID)+H(epoch_date|H(ID))) |
| |
| Returns:: |
| |
| error_code: error code from the C function |
| server_aes_key: server AES key |
| |
| Raises: |
| |
| """ |
| if ut is None: |
| ut1 = ffi.NULL |
| else: |
| ut1, ut1_val = make_octet(None, ut) |
| z1, z1_val = make_octet(None, z) |
| server_secret1, server_secret1_val = make_octet(None, server_secret) |
| w1, w1_val = make_octet(None, w) |
| hm1, hm1_val = make_octet(None, hm) |
| HID1, HID1_val = make_octet(None, HID) |
| u1, u1_val = make_octet(None, u) |
| |
| server_aes_key1, server_aes_key1_val = make_octet(PAS) |
| error_code = libamcl_mpin_ZZZ.MPIN_ZZZ_SERVER_KEY( |
| hash_type, |
| z1, |
| server_secret1, |
| w1, |
| hm1, |
| HID1, |
| u1, |
| ut1, |
| server_aes_key1) |
| |
| server_aes_key_hex = to_hex(server_aes_key1) |
| |
| # clear memory |
| if ut: |
| libamcl_core.OCT_clear(ut1) |
| libamcl_core.OCT_clear(z1) |
| libamcl_core.OCT_clear(server_secret1) |
| libamcl_core.OCT_clear(w1) |
| libamcl_core.OCT_clear(hm1) |
| libamcl_core.OCT_clear(HID1) |
| libamcl_core.OCT_clear(u1) |
| libamcl_core.OCT_clear(server_aes_key1) |
| |
| return error_code, server_aes_key_hex.decode("hex") |
| |
| |
| def aes_gcm_encrypt(aes_key, iv, header, plaintext): |
| """AES-GCM Encryption |
| |
| AES-GCM Encryption |
| |
| Args:: |
| |
| aes_key: AES Key |
| iv: Initialization vector |
| header: header |
| plaintext: Plaintext to be encrypted |
| |
| Returns:: |
| |
| ciphertext: resultant ciphertext |
| tag: MAC |
| |
| |
| Raises: |
| |
| """ |
| aes_key1, aes_key1_val = make_octet(None, aes_key) |
| iv1, iv1_val = make_octet(None, iv) |
| header1, header1_val = make_octet(None, header) |
| plaintext1, plaintext1_val = make_octet(None, plaintext) |
| tag1, tag1_val = make_octet(PAS) |
| ciphertext1, ciphertext1_val = make_octet(len(plaintext)) |
| |
| libamcl_core.AES_GCM_ENCRYPT( |
| aes_key1, |
| iv1, |
| header1, |
| plaintext1, |
| ciphertext1, |
| tag1) |
| tag = to_hex(tag1) |
| ciphertext = to_hex(ciphertext1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(aes_key1) |
| libamcl_core.OCT_clear(iv1) |
| libamcl_core.OCT_clear(header1) |
| libamcl_core.OCT_clear(plaintext1) |
| libamcl_core.OCT_clear(tag1) |
| libamcl_core.OCT_clear(ciphertext1) |
| |
| return ciphertext.decode("hex"), tag.decode("hex") |
| |
| |
| def aes_gcm_decrypt(aes_key, iv, header, ciphertext): |
| """AES-GCM Decryption |
| |
| AES-GCM Deryption |
| |
| Args:: |
| |
| aes_key: AES Key |
| iv: Initialization vector |
| header: header |
| ciphertext: ciphertext |
| |
| Returns:: |
| |
| plaintext: resultant plaintext |
| tag: MAC |
| |
| Raises: |
| |
| """ |
| aes_key1, aes_key1_val = make_octet(None, aes_key) |
| iv1, iv1_val = make_octet(None, iv) |
| header1, header1_val = make_octet(None, header) |
| ciphertext1, ciphertext1_val = make_octet(None, ciphertext) |
| tag1, tag1_val = make_octet(PAS) |
| plaintext1, plaintext1_val = make_octet(len(ciphertext)) |
| |
| libamcl_core.AES_GCM_DECRYPT( |
| aes_key1, |
| iv1, |
| header1, |
| ciphertext1, |
| plaintext1, |
| tag1) |
| |
| tag = to_hex(tag1) |
| plaintext = to_hex(plaintext1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(aes_key1) |
| libamcl_core.OCT_clear(iv1) |
| libamcl_core.OCT_clear(header1) |
| libamcl_core.OCT_clear(plaintext1) |
| libamcl_core.OCT_clear(tag1) |
| libamcl_core.OCT_clear(ciphertext1) |
| |
| return plaintext.decode("hex"), tag.decode("hex") |
| |
| |
| def generate_otp(rng): |
| """Generate a random six digit one time password |
| |
| Generate a random six digit one time password |
| |
| Args:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| |
| Returns:: |
| |
| OTP: One time password |
| |
| Raises: |
| |
| """ |
| OTP = libamcl_mpin_ZZZ.generateOTP(rng) |
| |
| return OTP |
| |
| |
| def generate_random(rng, length): |
| """Generate a random string |
| |
| Generate a random string |
| |
| Args:: |
| |
| rng: Pointer to cryptographically secure pseudo-random number generator instance |
| length: Gives length of random byte array |
| |
| Returns:: |
| |
| random_value: Random value |
| |
| Raises: |
| |
| """ |
| random_value1, random_value1_val = make_octet(length) |
| libamcl_mpin_ZZZ.generateRandom(rng, random_value1) |
| |
| random_value_hex = to_hex(random_value1) |
| |
| # clear memory |
| libamcl_core.OCT_clear(random_value1) |
| |
| return random_value_hex.decode("hex") |
| |
| |
| if __name__ == "__main__": |
| # Print hex values |
| DEBUG = True |
| |
| # Require user input |
| INPUT = True |
| |
| ONE_PASS = False |
| TIME_PERMITS = True |
| MPIN_ZZZ_FULL = True |
| PIN_ERROR = True |
| |
| HASH_TYPE_MPIN_ZZZ = SHA256 |
| |
| if TIME_PERMITS: |
| date = today() |
| else: |
| date = 0 |
| |
| # Seed |
| seedHex = "b75e7857fa17498c333d3c8d42e10f8c3cb8a66f7a84d85f86cd5acb537fa211" |
| seed = seedHex.decode("hex") |
| |
| # random number generator |
| rng = create_csprng(seed) |
| |
| # Identity |
| if INPUT: |
| mpin_id = raw_input("Please enter identity:") |
| else: |
| mpin_id = "user@milagro.com" |
| |
| # Hash mpin_id |
| hash_mpin_id = hash_id(HASH_TYPE_MPIN_ZZZ, mpin_id) |
| if DEBUG: |
| print "mpin_id: %s" % mpin_id.encode("hex") |
| print "hash_mpin_id: %s" % hash_mpin_id.encode("hex") |
| |
| # Generate master secret for MILAGRO and Customer |
| rtn, ms1 = random_generate(rng) |
| if rtn != 0: |
| print "random_generate(rng) Error %s", rtn |
| rtn, ms2 = random_generate(rng) |
| if rtn != 0: |
| print "random_generate(rng) Error %s", rtn |
| if DEBUG: |
| print "ms1: %s" % ms1.encode("hex") |
| print "ms2: %s" % ms2.encode("hex") |
| |
| # Generate server secret shares |
| rtn, ss1 = get_server_secret(ms1) |
| if rtn != 0: |
| print "get_server_secret(ms1) Error %s" % rtn |
| rtn, ss2 = get_server_secret(ms2) |
| if rtn != 0: |
| print "get_server_secret(ms2) Error %s" % rtn |
| if DEBUG: |
| print "ss1: %s" % ss1.encode("hex") |
| print "ss2: %s" % ss2.encode("hex") |
| |
| # Combine server secret shares |
| rtn, server_secret = recombine_G2(ss1, ss2) |
| if rtn != 0: |
| print "recombine_G2(ss1, ss2) Error %s" % rtn |
| if DEBUG: |
| print "server_secret: %s" % server_secret.encode("hex") |
| |
| # Generate client secret shares |
| rtn, cs1 = get_client_secret(ms1, hash_mpin_id) |
| if rtn != 0: |
| print "get_client_secret(ms1, hash_mpin_id) Error %s" % rtn |
| rtn, cs2 = get_client_secret(ms2, hash_mpin_id) |
| if rtn != 0: |
| print "get_client_secret(ms2, hash_mpin_id) Error %s" % rtn |
| if DEBUG: |
| print "cs1: %s" % cs1.encode("hex") |
| print "cs2: %s" % cs2.encode("hex") |
| |
| # Combine client secret shares |
| rtn, client_secret = recombine_G1(cs1, cs2) |
| if rtn != 0: |
| print "recombine_G1(cs1, cs2) Error %s" % rtn |
| print "Client Secret: %s" % client_secret.encode("hex") |
| |
| if TIME_PERMITS: |
| # Generate Time Permit shares |
| if DEBUG: |
| print "Date %s" % date |
| rtn, tp1 = get_client_permit( |
| HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id) |
| if rtn != 0: |
| print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn |
| rtn, tp2 = get_client_permit( |
| HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id) |
| if rtn != 0: |
| print "get_client_permit(HASH_TYPE_MPIN_ZZZ, date, ms2, hash_mpin_id) Error %s" % rtn |
| if DEBUG: |
| print "tp1: %s" % tp1.encode("hex") |
| print "tp2: %s" % tp2.encode("hex") |
| |
| # Combine Time Permit shares |
| rtn, time_permit = recombine_G1(tp1, tp2) |
| if rtn != 0: |
| print "recombine_G1(tp1, tp2) Error %s" % rtn |
| if DEBUG: |
| print "time_permit: %s" % time_permit.encode("hex") |
| else: |
| time_permit = None |
| |
| # Client extracts PIN from secret to create Token |
| if INPUT: |
| PIN = int( |
| raw_input("Please enter four digit PIN to create M-Pin Token:")) |
| else: |
| PIN = 1234 |
| rtn, token = extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, client_secret) |
| if rtn != 0: |
| print "extract_pin(HASH_TYPE_MPIN_ZZZ, mpin_id, PIN, token) Error %s" % rtn |
| print "Token: %s" % token.encode("hex") |
| |
| if ONE_PASS: |
| print "M-Pin One Pass" |
| if INPUT: |
| PIN = int(raw_input("Please enter PIN to authenticate:")) |
| else: |
| PIN = 1234 |
| epoch_time = get_time() |
| if DEBUG: |
| print "epoch_time %s" % epoch_time |
| |
| # Client precomputation |
| if MPIN_ZZZ_FULL: |
| rtn, pc1, pc2 = precompute(token, hash_mpin_id) |
| |
| # Client MPIN |
| rtn, x, u, ut, v, y = client( |
| HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time) |
| if rtn != 0: |
| print "MPIN_ZZZ_CLIENT ERROR %s" % rtn |
| |
| # Client sends Z=r.ID to Server |
| if MPIN_ZZZ_FULL: |
| rtn, r, Z = get_G1_multiple(rng, 1, None, hash_mpin_id) |
| |
| # Server MPIN |
| rtn, HID, HTID, E, F, y2 = server( |
| HASH_TYPE_MPIN_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time) |
| if DEBUG: |
| print "y2 ", y2.encode("hex") |
| if rtn != 0: |
| print "ERROR: %s is not authenticated" % mpin_id |
| if PIN_ERROR: |
| err = kangaroo(E, F) |
| print "Client PIN error %d " % err |
| raise SystemExit(0) |
| else: |
| print "SUCCESS: %s is authenticated" % mpin_id |
| |
| if date: |
| prHID = HTID |
| else: |
| prHID = HID |
| ut = None |
| |
| # Server sends T=w.ID to client |
| if MPIN_ZZZ_FULL: |
| rtn, w, T = get_G1_multiple(rng, 0, None, prHID) |
| if rtn != 0: |
| print "ERROR: Generating T %s" % rtn |
| |
| if MPIN_ZZZ_FULL: |
| HM = hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T) |
| |
| rtn, client_aes_key = client_key( |
| HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T) |
| if rtn != 0: |
| print "ERROR: Generating client_aes_key %s" % rtn |
| print "Client AES Key: %s" % client_aes_key.encode("hex") |
| |
| rtn, server_aes_key = server_key( |
| HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut) |
| if rtn != 0: |
| print "ERROR: Generating server_aes_key %s" % rtn |
| print "Server AES Key: %s" % server_aes_key.encode("hex") |
| |
| else: |
| print "M-Pin Three Pass" |
| if INPUT: |
| PIN = int(raw_input("Please enter PIN to authenticate:")) |
| else: |
| PIN = 1234 |
| if MPIN_ZZZ_FULL: |
| rtn, pc1, pc2 = precompute(token, hash_mpin_id) |
| if rtn != 0: |
| print "precompute(token, hash_mpin_id) ERROR %s" % rtn |
| |
| # Client first pass |
| rtn, x, u, ut, sec = client_1( |
| HASH_TYPE_MPIN_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit) |
| if rtn != 0: |
| print "client_1 ERROR %s" % rtn |
| if DEBUG: |
| print "x: %s" % x.encode("hex") |
| |
| # Server calculates H(ID) and H(T|H(ID)) (if time permits enabled), |
| # and maps them to points on the curve HID and HTID resp. |
| HID, HTID = server_1(HASH_TYPE_MPIN_ZZZ, date, mpin_id) |
| |
| # Server generates Random number y and sends it to Client |
| rtn, y = random_generate(rng) |
| if rtn != 0: |
| print "random_generate(rng) Error %s" % rtn |
| |
| # Client second pass |
| rtn, v = client_2(x, y, sec) |
| if rtn != 0: |
| print "client_2(x, y, sec) Error %s" % rtn |
| |
| # Server second pass |
| rtn, E, F = server_2(date, HID, HTID, y, server_secret, u, ut, v, None) |
| if rtn != 0: |
| print "ERROR: %s is not authenticated" % mpin_id |
| if PIN_ERROR: |
| err = kangaroo(E, F) |
| print "Client PIN error %d " % err |
| raise SystemExit(0) |
| else: |
| print "SUCCESS: %s is authenticated" % mpin_id |
| |
| # Client sends Z=r.ID to Server |
| if MPIN_ZZZ_FULL: |
| rtn, r, Z = get_G1_multiple(rng, 1, None, hash_mpin_id) |
| if rtn != 0: |
| print "ERROR: Generating Z %s" % rtn |
| |
| if date: |
| prHID = HTID |
| else: |
| prHID = HID |
| ut = None |
| |
| # Server sends T=w.ID to client |
| if MPIN_ZZZ_FULL: |
| rtn, w, T = get_G1_multiple(rng, 0, None, prHID) |
| if rtn != 0: |
| print "ERROR: Generating T %s" % rtn |
| |
| HM = hash_all(HASH_TYPE_MPIN_ZZZ, hash_mpin_id, u, ut, v, y, Z, T) |
| |
| rtn, client_aes_key = client_key( |
| HASH_TYPE_MPIN_ZZZ, pc1, pc2, PIN, r, x, HM, T) |
| if rtn != 0: |
| print "ERROR: Generating client_aes_key %s" % rtn |
| print "Client AES Key: %s" % client_aes_key.encode("hex") |
| |
| rtn, server_aes_key = server_key( |
| HASH_TYPE_MPIN_ZZZ, Z, server_secret, w, HM, HID, u, ut) |
| if rtn != 0: |
| print "ERROR: Generating server_aes_key %s" % rtn |
| print "Server AES Key: %s" % server_aes_key.encode("hex") |
| |
| if MPIN_ZZZ_FULL: |
| plaintext = "A test message" |
| print "message to encrypt: ", plaintext |
| header_hex = "1554a69ecbf04e507eb6985a234613246206c85f8af73e61ab6e2382a26f457d" |
| header = header_hex.decode("hex") |
| iv_hex = "2b213af6b0edf6972bf996fb" |
| iv = iv_hex.decode("hex") |
| ciphertext, tag = aes_gcm_encrypt( |
| client_aes_key, iv, header, plaintext) |
| print "ciphertext ", ciphertext.encode("hex") |
| print "tag1 ", tag.encode("hex") |
| |
| plaintext2, tag2 = aes_gcm_decrypt( |
| server_aes_key, iv, header, ciphertext) |
| print "decrypted message: ", plaintext2 |
| print "tag2 ", tag2.encode("hex") |
| |
| # Clear memory |
| del seed |
| del hash_mpin_id |
| del mpin_id |
| del ms1 |
| del ms2 |
| del ss1 |
| del ss2 |
| del server_secret |
| del cs1 |
| del cs2 |
| del client_secret |
| del token |
| del pc1 |
| del pc2 |
| del x |
| del u |
| del ut |
| del v |
| del y |
| del HID |
| del HTID |
| if PIN_ERROR: |
| del E |
| del F |
| if ONE_PASS: |
| del y2 |
| else: |
| del sec |
| if TIME_PERMITS: |
| del tp1 |
| del tp2 |
| del time_permit |
| if MPIN_ZZZ_FULL: |
| del r |
| del Z |
| del w |
| del T |
| del HM |
| del client_aes_key |
| del server_aes_key |
| |
| kill_csprng(rng) |