blob: 944a609960ac8e5633b1d140055e14407d24fec6 [file] [log] [blame]
#!/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 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")
# Group Size
PGS = @NB@
# Field Size
PFS = @NB@
CURVE_SECURITY = @CS@
if CURVE_SECURITY == 128:
G2 = 4 * PFS
HASH_TYPE_ZZZ = 32
AESKEY_ZZZ = 16
if CURVE_SECURITY == 192:
G2 = 8 * PFS
HASH_TYPE_ZZZ = 48
AESKEY_ZZZ = 24
if CURVE_SECURITY == 256:
G2 = 16 * PFS
HASH_TYPE_ZZZ = 64
AESKEY_ZZZ = 32
G1 = 2 * PFS + 1
GT = 3 * G2
# AES-GCM IV length
IVL = 12
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.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(AESKEY_ZZZ)
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(AESKEY_ZZZ)
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(AESKEY_ZZZ)
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(AESKEY_ZZZ)
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
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_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_ZZZ, date, ms1, hash_mpin_id)
if rtn != 0:
print "get_client_permit(HASH_TYPE_ZZZ, date, ms1, hash_mpin_id) Error %s" % rtn
rtn, tp2 = get_client_permit(
HASH_TYPE_ZZZ, date, ms2, hash_mpin_id)
if rtn != 0:
print "get_client_permit(HASH_TYPE_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_ZZZ, mpin_id, PIN, client_secret)
if rtn != 0:
print "extract_pin(HASH_TYPE_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_ZZZ, date, mpin_id, rng, None, PIN, token, time_permit, None, epoch_time)
if DEBUG:
print "y1 ", y.encode("hex")
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_ZZZ, date, server_secret, u, ut, v, mpin_id, None, epoch_time, None)
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_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
rtn, client_aes_key = client_key(
HASH_TYPE_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_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_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_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_ZZZ, hash_mpin_id, u, ut, v, y, Z, T)
rtn, client_aes_key = client_key(
HASH_TYPE_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_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 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
del pc1
del pc2
kill_csprng(rng)