switch smartpgp-cli to Python3
This commit is contained in:
parent
461e5fd123
commit
1720a3494b
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SmartPGP : JavaCard implementation of OpenPGP card v3 specification
|
||||
# https://github.com/ANSSI-FR/SmartPGP
|
||||
@ -83,8 +83,8 @@ def parse_args(ctx):
|
||||
varname = args.pin[4:]
|
||||
try:
|
||||
ctx.admin_pin=os.environ[varname]
|
||||
except KeyError,e:
|
||||
print "Environment variable %s not found" % varname
|
||||
except KeyError:
|
||||
print("Environment variable %s not found" % varname)
|
||||
sys.exit(1)
|
||||
else:
|
||||
ctx.admin_pin = args.pin
|
||||
@ -103,8 +103,8 @@ def main():
|
||||
if args.command in VALID_COMMANDS:
|
||||
VALID_COMMANDS[args.command](ctx)
|
||||
else:
|
||||
print "Unknown command '%s'" % args.command
|
||||
print "Run '%s -h' for help" % sys.argv[0]
|
||||
print("Unknown command '%s'" % args.command)
|
||||
print("Run '%s -h' for help" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
if __name__=='__main__':
|
||||
|
@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# SmartPGP : JavaCard implementation of OpenPGP card v3 specification
|
||||
# https://github.com/ANSSI-FR/SmartPGP
|
||||
# Copyright (C) 2016 ANSSI
|
||||
@ -79,6 +77,9 @@ OID_ALGS = {
|
||||
'brainpoolP512r1': [0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D],
|
||||
}
|
||||
|
||||
class InvalidBitStringLength(Exception):
|
||||
pass
|
||||
|
||||
class WrongKeyRole(Exception):
|
||||
pass
|
||||
|
||||
@ -93,8 +94,8 @@ def assemble_with_len(prefix,data):
|
||||
|
||||
def asOctets(bs):
|
||||
l = len(bs)
|
||||
if l%8 is not 0:
|
||||
raise "BitString length is not a multiple of 8"
|
||||
if l%8 != 0:
|
||||
raise InvalidBitStringLength
|
||||
result = []
|
||||
i = 0
|
||||
while i < l:
|
||||
@ -122,11 +123,11 @@ def kdf_itersalted_s2k(salt, value, algo, count):
|
||||
elif algo == 0x0A: #SHA512
|
||||
f = hashlib.new('sha512')
|
||||
else:
|
||||
print "invalid KDF"
|
||||
salt = [ord(c) for c in salt]
|
||||
value = [ord(c) for c in value]
|
||||
data = salt + value
|
||||
data = array.array('B', data).tostring()
|
||||
print("invalid KDF")
|
||||
salt = list(salt)#[ord(c) for c in salt]
|
||||
value = list(value)#[ord(c) for c in value]
|
||||
data = bytes(salt + value)
|
||||
#data = array.array('B', data).tostring()
|
||||
datalen = len(data)
|
||||
while datalen <= count:
|
||||
f.update(data)
|
||||
@ -137,12 +138,12 @@ def kdf_itersalted_s2k(salt, value, algo, count):
|
||||
|
||||
|
||||
def _raw_send_apdu(connection, text, apdu):
|
||||
print "%s" % text
|
||||
print("%s" % text)
|
||||
apdu = [int(c) for c in apdu]
|
||||
#print ' '.join('{:02X}'.format(c) for c in apdu)
|
||||
(data, sw1, sw2) = connection.transmit(apdu)
|
||||
#print ' '.join('{:02X}'.format(c) for c in data)
|
||||
print "%02X %02X" % (sw1, sw2)
|
||||
print("%02X %02X" % (sw1, sw2))
|
||||
return (data,sw1,sw2)
|
||||
|
||||
def list_readers():
|
||||
@ -475,8 +476,6 @@ def get_kdf_do(connection):
|
||||
|
||||
def change_reference_data_pw1(connection, old, new):
|
||||
prefix = [0x00, 0x24, 0x00, 0x81]
|
||||
old = ascii_encode_pin(old)
|
||||
new = ascii_encode_pin(new)
|
||||
data = old + new
|
||||
apdu = assemble_with_len(prefix, data)
|
||||
(_,sw1,sw2) = _raw_send_apdu(connection,"Change PW1", apdu)
|
||||
@ -484,8 +483,6 @@ def change_reference_data_pw1(connection, old, new):
|
||||
|
||||
def change_reference_data_pw3(connection, old, new):
|
||||
prefix = [0x00, 0x24, 0x00, 0x83]
|
||||
old = ascii_encode_pin(old)
|
||||
new = ascii_encode_pin(new)
|
||||
data = old + new
|
||||
apdu = assemble_with_len(prefix, data)
|
||||
(_,sw1,sw2) = _raw_send_apdu(connection,"Change PW3", apdu)
|
||||
|
@ -17,7 +17,7 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
from commands import *
|
||||
from smartpgp.commands import *
|
||||
|
||||
import binascii
|
||||
import pyasn1
|
||||
@ -38,11 +38,15 @@ class AdminPINFailed(Exception):
|
||||
class UserPINFailed(Exception):
|
||||
pass
|
||||
|
||||
class InvalidPINType(Exception):
|
||||
pass
|
||||
|
||||
class CardConnectionContext:
|
||||
|
||||
def __init__(self):
|
||||
self.reader_index = 0
|
||||
self.admin_pin = "123456"
|
||||
self.resetting_code = None
|
||||
self.user_pin = "123456"
|
||||
self.admin_pin = "12345678"
|
||||
self.connection = None
|
||||
self.read_pin = self._default_pin_read_function
|
||||
@ -51,7 +55,13 @@ class CardConnectionContext:
|
||||
self.input = None
|
||||
|
||||
def _default_pin_read_function(self, pin_type):
|
||||
return self.admin_pin
|
||||
if pin_type == "Admin":
|
||||
return self.admin_pin
|
||||
if pin_type == "User":
|
||||
return self.user_pin
|
||||
if pin_type == "PUK":
|
||||
return self.resetting_code
|
||||
raise InvalidPINType
|
||||
|
||||
def set_pin_read_function(self, fun):
|
||||
self.read_pin = fun
|
||||
@ -154,29 +164,29 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_generate_sm_key(self):
|
||||
if not self.output:
|
||||
print "Missing output file name"
|
||||
print("Missing output file name")
|
||||
return
|
||||
self.connect()
|
||||
self.verify_admin_pin()
|
||||
(data,sw1,sw2) = generate_sm_key(self.connection)
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print "generate_sm_key failed"
|
||||
print("generate_sm_key failed")
|
||||
return
|
||||
if len(data) < 4 or data[0]!=0x7f or data[1]!=0x49:
|
||||
print "Strange reply for get_sm_certificate"
|
||||
print("Strange reply for get_sm_certificate")
|
||||
return
|
||||
blob_len = data[2]
|
||||
blob = data[3:]
|
||||
assert(blob_len == len(blob))
|
||||
if blob[0]!=0x86:
|
||||
print "get_sm_certificate return something not a public key"
|
||||
print("get_sm_certificate return something not a public key")
|
||||
return
|
||||
assert(blob[1]==len(blob[2:]))
|
||||
pubkey = blob[2:]
|
||||
# get curve OID
|
||||
curve_oid_der = get_sm_curve_oid(self.connection)
|
||||
if not curve_oid_der:
|
||||
print "Error getting SM curve OID"
|
||||
print("Error getting SM curve OID")
|
||||
return
|
||||
(curve_oid,_) = der_decoder.decode(str(curve_oid_der))
|
||||
# now format it to DER [RFC5480]
|
||||
@ -189,7 +199,7 @@ class CardConnectionContext:
|
||||
s2.setComponentByPosition(0,s)
|
||||
s2.setComponentByPosition(1,bs)
|
||||
pubkey_der = der_encoder.encode(s2)
|
||||
print binascii.hexlify(pubkey_der)
|
||||
print(binascii.hexlify(pubkey_der))
|
||||
# and write result
|
||||
with open(self.output,"wb") as f:
|
||||
f.write(pubkey_der)
|
||||
@ -197,28 +207,28 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_get_sm_key(self):
|
||||
if not self.output:
|
||||
print "Missing output file name"
|
||||
print("Missing output file name")
|
||||
return
|
||||
self.connect()
|
||||
(data,sw1,sw2) = get_sm_key(self.connection)
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print "get_sm_key failed"
|
||||
print("get_sm_key failed")
|
||||
return
|
||||
if len(data) < 4 or data[0]!=0x7f or data[1]!=0x49:
|
||||
print "Strange reply for get_sm_key"
|
||||
print("Strange reply for get_sm_key")
|
||||
return
|
||||
blob_len = data[2]
|
||||
blob = data[3:]
|
||||
assert(blob_len == len(blob))
|
||||
if blob[0]!=0x86:
|
||||
print "get_sm_key something not a public key"
|
||||
print("get_sm_key something not a public key")
|
||||
return
|
||||
assert(blob[1]==len(blob[2:]))
|
||||
pubkey = blob[2:]
|
||||
# get curve OID
|
||||
curve_oid_der = get_sm_curve_oid(self.connection)
|
||||
if not curve_oid_der:
|
||||
print "Error getting SM curve OID"
|
||||
print("Error getting SM curve OID")
|
||||
return
|
||||
(curve_oid,_) = der_decoder.decode(str(curve_oid_der))
|
||||
# now format it to DER [RFC5480]
|
||||
@ -231,7 +241,7 @@ class CardConnectionContext:
|
||||
s2.setComponentByPosition(0,s)
|
||||
s2.setComponentByPosition(1,bs)
|
||||
pubkey_der = der_encoder.encode(s2)
|
||||
print binascii.hexlify(pubkey_der)
|
||||
print(binascii.hexlify(pubkey_der))
|
||||
# and write result
|
||||
with open(self.output,"wb") as f:
|
||||
f.write(pubkey_der)
|
||||
@ -239,7 +249,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_put_sm_key(self):
|
||||
if self.input is None:
|
||||
print "No input key file"
|
||||
print("No input key file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
fstr = f.read()
|
||||
@ -254,11 +264,11 @@ class CardConnectionContext:
|
||||
oid = oid[2:]
|
||||
assert(oid_len == len(oid))
|
||||
curve = None
|
||||
for k,v in OID_ALGS.items():
|
||||
for k,v in list(OID_ALGS.items()):
|
||||
if bytearray(v) == oid:
|
||||
curve = k
|
||||
if curve is None:
|
||||
print "Curve not supported (%s)" % der[2]
|
||||
print("Curve not supported (%s)" % der[2])
|
||||
return
|
||||
self.connect()
|
||||
self.verify_admin_pin()
|
||||
@ -279,7 +289,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_put_sign_certificate(self):
|
||||
if self.input is None:
|
||||
print "No input certificate file"
|
||||
print("No input certificate file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
cert = f.read()
|
||||
@ -291,7 +301,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_put_auth_certificate(self):
|
||||
if self.input is None:
|
||||
print "No input certificate file"
|
||||
print("No input certificate file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
cert = f.read()
|
||||
@ -303,7 +313,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_put_sm_certificate(self):
|
||||
if self.input is None:
|
||||
print "No input certificate file"
|
||||
print("No input certificate file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
cert = f.read()
|
||||
@ -315,7 +325,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_get_sm_certificate(self):
|
||||
if self.output is None:
|
||||
print "No output file"
|
||||
print("No output file")
|
||||
return
|
||||
self.connect()
|
||||
(cert,_,_) = get_sm_certificate(self.connection)
|
||||
@ -326,7 +336,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_put_aes_key(self):
|
||||
if self.input is None:
|
||||
print "No input AES key file"
|
||||
print("No input AES key file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
key = f.read()
|
||||
@ -338,10 +348,10 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_encrypt_aes(self):
|
||||
if self.input is None:
|
||||
print "No input data file"
|
||||
print("No input data file")
|
||||
return
|
||||
if self.output is None:
|
||||
print "No output data file"
|
||||
print("No output data file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
data = f.read()
|
||||
@ -357,10 +367,10 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_decrypt_aes(self):
|
||||
if self.input is None:
|
||||
print "No input data file"
|
||||
print("No input data file")
|
||||
return
|
||||
if self.output is None:
|
||||
print "No output data file"
|
||||
print("No output data file")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
data = f.read()
|
||||
@ -376,7 +386,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_set_kdf(self):
|
||||
if self.input is None:
|
||||
print "No input KDF-DO"
|
||||
print("No input KDF-DO")
|
||||
return
|
||||
f = open(self.input, 'r')
|
||||
kdf_do = f.read()
|
||||
@ -388,7 +398,7 @@ class CardConnectionContext:
|
||||
|
||||
def cmd_get_kdf(self):
|
||||
if self.output is None:
|
||||
print "No output file"
|
||||
print("No output file")
|
||||
return
|
||||
self.connect()
|
||||
(kdf_do,_,_) = get_kdf_do(self.connection)
|
||||
@ -402,17 +412,17 @@ class CardConnectionContext:
|
||||
self.connect()
|
||||
(kdf_do,_,_) = get_kdf_do(self.connection)
|
||||
if 5 < len(kdf_do):
|
||||
print "KDF already setup"
|
||||
print("KDF already setup")
|
||||
return
|
||||
####### step 1
|
||||
pw1 = self.read_pin("User")
|
||||
resetting_code = self.read_pin("PUK")
|
||||
if len(resetting_code) == 0:
|
||||
if resetting_code != None and len(resetting_code) == 0:
|
||||
resetting_code = None
|
||||
pw3 = self.read_pin("Admin")
|
||||
####### step 1bis
|
||||
pw1 = pw1
|
||||
if resetting_code <> None:
|
||||
if resetting_code != None:
|
||||
resetting_code = resetting_code
|
||||
pw3 = pw3
|
||||
####### step 2
|
||||
@ -423,25 +433,27 @@ class CardConnectionContext:
|
||||
ndata82 = [0x82, 0x01, algo]
|
||||
ndata83 = [0x83, 0x04, nbiter >> 24, (nbiter >> 16) & 0xff, (nbiter >> 8) & 0xff, nbiter & 0xff] #NB ITERATIONS
|
||||
salt_pw1 = os.urandom(salt_size)
|
||||
ndata84 = assemble_with_len([0x84], [ord(c) for c in salt_pw1]) #SALT PW1
|
||||
ndata84 = assemble_with_len([0x84], list(salt_pw1)) #SALT PW1
|
||||
salt_resetting_code = os.urandom(salt_size)
|
||||
ndata85 = assemble_with_len([0x85], [ord(c) for c in salt_resetting_code]) #SALT RESETTING CODE
|
||||
ndata85 = assemble_with_len([0x85], list(salt_resetting_code)) #SALT RESETTING CODE
|
||||
salt_pw3 = os.urandom(salt_size)
|
||||
ndata86 = assemble_with_len([0x86], [ord(c) for c in salt_pw3]) #SALT PW3
|
||||
h87 = kdf_itersalted_s2k(salt_pw1, "123456", algo, nbiter) #HASH OF "123456"
|
||||
h87 = [ord(c) for c in h87]
|
||||
ndata86 = assemble_with_len([0x86], list(salt_pw3)) #SALT PW3
|
||||
h87 = kdf_itersalted_s2k(salt_pw1, ascii_encode_pin("123456"), algo, nbiter) #HASH OF "123456"
|
||||
#h87 = [ord(c) for c in h87]
|
||||
h87 = list(h87)
|
||||
ndata87 = assemble_with_len([0x87], h87)
|
||||
h88 = kdf_itersalted_s2k(salt_pw3, "12345678", algo, nbiter) #HASH OF "12345678"
|
||||
h88 = [ord(c) for c in h88]
|
||||
h88 = kdf_itersalted_s2k(salt_pw3, ascii_encode_pin("12345678"), algo, nbiter) #HASH OF "12345678"
|
||||
#h88 = [ord(c) for c in h88]
|
||||
h88 = list(h88)
|
||||
ndata88 = assemble_with_len([0x88], h88)
|
||||
nkdf_do = ndata81 + ndata82 + ndata83 + ndata84 + ndata85 + ndata86 + ndata87 + ndata88
|
||||
####### step 2bis
|
||||
npw1 = kdf_itersalted_s2k(salt_pw1, pw1, algo, nbiter)
|
||||
if resetting_code <> None:
|
||||
nresetting_code = kdf_itersalted_s2k(salt_resetting_code, resetting_code, algo, nbiter)
|
||||
npw1 = kdf_itersalted_s2k(salt_pw1, ascii_encode_pin(pw1), algo, nbiter)
|
||||
if resetting_code != None:
|
||||
nresetting_code = kdf_itersalted_s2k(salt_resetting_code, ascii_encode_pin(resetting_code), algo, nbiter)
|
||||
else:
|
||||
nresetting_code = None
|
||||
npw3 = kdf_itersalted_s2k(salt_pw3, pw3, algo, nbiter)
|
||||
npw3 = kdf_itersalted_s2k(salt_pw3, ascii_encode_pin(pw3), algo, nbiter)
|
||||
####### step 3
|
||||
(_,sw1,sw2) = verif_admin_pin(self.connection, pw3)
|
||||
if sw1==0x90 and sw2==0x00:
|
||||
@ -449,20 +461,20 @@ class CardConnectionContext:
|
||||
else:
|
||||
raise AdminPINFailed
|
||||
####### step 3bis
|
||||
if nresetting_code <> None:
|
||||
if nresetting_code != None:
|
||||
set_resetting_code(self.connection, nresetting_code)
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print "set_resetting_code failed"
|
||||
print("set_resetting_code failed")
|
||||
return
|
||||
####### step 4
|
||||
change_reference_data_pw1(self.connection, pw1, npw1)
|
||||
change_reference_data_pw1(self.connection, ascii_encode_pin(pw1), list(npw1))
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print "change_reference_data_pw1 failed"
|
||||
print("change_reference_data_pw1 failed")
|
||||
return
|
||||
####### step 4bis
|
||||
change_reference_data_pw3(self.connection, pw3, npw3)
|
||||
change_reference_data_pw3(self.connection, ascii_encode_pin(pw3), list(npw3))
|
||||
if sw1!=0x90 or sw2!=0x00:
|
||||
print "change_reference_data_pw3 failed"
|
||||
print("change_reference_data_pw3 failed")
|
||||
return
|
||||
####### step 5
|
||||
put_kdf_do(self.connection, nkdf_do)
|
||||
|
Loading…
Reference in New Issue
Block a user