diff --git a/bin/smartpgp-cli b/bin/smartpgp-cli index 73a9494..7252a24 100755 --- a/bin/smartpgp-cli +++ b/bin/smartpgp-cli @@ -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__': diff --git a/bin/smartpgp/__init__.py b/bin/smartpgp/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/bin/smartpgp/commands.py b/bin/smartpgp/commands.py index fc776a5..cedad14 100644 --- a/bin/smartpgp/commands.py +++ b/bin/smartpgp/commands.py @@ -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) diff --git a/bin/smartpgp/highlevel.py b/bin/smartpgp/highlevel.py index 0d93bb4..426942a 100644 --- a/bin/smartpgp/highlevel.py +++ b/bin/smartpgp/highlevel.py @@ -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)