Add support for AES commands in smartpgp-cli

This commit is contained in:
Arnaud Fontaine 2017-07-11 16:57:11 +02:00
parent ec84edb737
commit 60b6b09192
3 changed files with 133 additions and 7 deletions

View File

@ -43,6 +43,9 @@ VALID_COMMANDS={
'put-sm-key': CardConnectionContext.cmd_put_sm_key, 'put-sm-key': CardConnectionContext.cmd_put_sm_key,
'put-sm-certificate': CardConnectionContext.cmd_put_sm_certificate, 'put-sm-certificate': CardConnectionContext.cmd_put_sm_certificate,
'get-sm-certificate': CardConnectionContext.cmd_get_sm_certificate, 'get-sm-certificate': CardConnectionContext.cmd_get_sm_certificate,
'put-aes-key': CardConnectionContext.cmd_put_aes_key,
'encrypt-aes': CardConnectionContext.cmd_encrypt_aes,
'decrypt-aes': CardConnectionContext.cmd_decrypt_aes,
} }
def read_pin_interactive(name): def read_pin_interactive(name):

View File

@ -29,7 +29,8 @@ SELECT = [0x00, 0xA4, 0x04, 0x00,
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
0x00] 0x00]
VERIFY = [0x00, 0x20, 0x00, 0x83] VERIFY_ADMIN = [0x00, 0x20, 0x00, 0x83]
VERIFY_USER_82 = [0x00, 0x20, 0x00, 0x82]
TERMINATE = [0x00, 0xe6, 0x00, 0x00] TERMINATE = [0x00, 0xe6, 0x00, 0x00]
ACTIVATE = [0x00, 0x44, 0x00, 0x00] ACTIVATE = [0x00, 0x44, 0x00, 0x00]
ACTIVATE_FULL = [0x00, 0x44, 0x00, 0x01] ACTIVATE_FULL = [0x00, 0x44, 0x00, 0x01]
@ -111,9 +112,10 @@ def encode_len(data):
def _raw_send_apdu(connection, text, apdu): def _raw_send_apdu(connection, text, apdu):
print "%s" % text print "%s" % text
data, sw1, sw2 = connection.transmit(apdu) #print ' '.join('{:02X}'.format(c) for c in apdu)
print data (data, sw1, sw2) = connection.transmit(apdu)
print "%s: %02X %02X" % (text, sw1, sw2) #print ' '.join('{:02X}'.format(c) for c in data)
print "%02X %02X" % (sw1, sw2)
return (data,sw1,sw2) return (data,sw1,sw2)
def list_readers(): def list_readers():
@ -136,9 +138,13 @@ def select_applet(connection):
return _raw_send_apdu(connection,"Select OpenPGP Applet",SELECT) return _raw_send_apdu(connection,"Select OpenPGP Applet",SELECT)
def verif_admin_pin(connection, admin_pin): def verif_admin_pin(connection, admin_pin):
verif_apdu = assemble_with_len(VERIFY,ascii_encode_pin(admin_pin)) verif_apdu = assemble_with_len(VERIFY_ADMIN,ascii_encode_pin(admin_pin))
return _raw_send_apdu(connection,"Verify Admin PIN",verif_apdu) return _raw_send_apdu(connection,"Verify Admin PIN",verif_apdu)
def verif_user_pin(connection, user_pin):
verif_apdu = assemble_with_len(VERIFY_USER_82,ascii_encode_pin(user_pin))
return _raw_send_apdu(connection,"Verify User PIN",verif_apdu)
def full_reset_card(connection): def full_reset_card(connection):
_raw_send_apdu(connection,"Terminate",TERMINATE) _raw_send_apdu(connection,"Terminate",TERMINATE)
_raw_send_apdu(connection,"Activate",ACTIVATE_FULL) _raw_send_apdu(connection,"Activate",ACTIVATE_FULL)
@ -259,7 +265,7 @@ def get_sm_certificate(connection):
apdu = [0x00, 0xCA, 0x7F, 0x21, 0x00] apdu = [0x00, 0xCA, 0x7F, 0x21, 0x00]
(data,sw1,sw2) = _raw_send_apdu(connection,"Receiving SM certificate chunk",apdu) (data,sw1,sw2) = _raw_send_apdu(connection,"Receiving SM certificate chunk",apdu)
while sw1 == 0x61: while sw1 == 0x61:
apdu = [0x00, 0xC0, 0x00, 0x00, 0x00] apdu = [0x00, 0xC0, 0x00, 0x00, sw2]
(ndata,sw1,sw2) = _raw_send_apdu(connection,"Receiving SM certificate chunk",apdu) (ndata,sw1,sw2) = _raw_send_apdu(connection,"Receiving SM certificate chunk",apdu)
data = data + ndata data = data + ndata
return (data,sw1,sw2) return (data,sw1,sw2)
@ -282,3 +288,55 @@ def get_sm_curve_oid(connection):
#print ' '.join('{:02X}'.format(c) for c in curve) #print ' '.join('{:02X}'.format(c) for c in curve)
# Add DER OID header manually ... # Add DER OID header manually ...
return '\x06' + struct.pack('B',len(curve)) + curve return '\x06' + struct.pack('B',len(curve)) + curve
def put_aes_key(connection, key):
prefix = [0x00, 0xDA, 0x00, 0xD5]
data = key
apdu = assemble_with_len(prefix, data)
_raw_send_apdu(connection,"Put AES key",apdu)
def encrypt_aes(connection, msg):
ins_p1_p2 = [0x2A, 0x86, 0x80]
i = 0
cl = 255
l = len(msg)
while i < l:
if (l - i) <= cl:
cla = 0x00
data = msg[i:]
i = l
else:
cla = 0x10
data = msg[i:i+cl]
i = i + cl
apdu = assemble_with_len([cla] + ins_p1_p2, data)
(res,sw1,sw2) = _raw_send_apdu(connection,"Encrypt AES chunk",apdu)
while sw1 == 0x61:
apdu = [0x00, 0xC0, 0x00, 0x00, sw2]
(nres,sw1,sw2) = _raw_send_apdu(connection,"Receiving encrypted chunk",apdu)
res = res + nres
return (res[1:],sw1,sw2)
def decrypt_aes(connection, msg):
ins_p1_p2 = [0x2A, 0x80, 0x86]
i = 0
cl = 255
msg = [0x02] + msg
l = len(msg)
while i < l:
if (l - i) <= cl:
cla = 0x00
data = msg[i:]
i = l
else:
cla = 0x10
data = msg[i:i+cl]
i = i + cl
apdu = assemble_with_len([cla] + ins_p1_p2, data)
(res,sw1,sw2) = _raw_send_apdu(connection,"Decrypt AES chunk",apdu)
while sw1 == 0x61:
apdu = [0x00, 0xC0, 0x00, 0x00, sw2]
(nres,sw1,sw2) = _raw_send_apdu(connection,"Receiving decrypted chunk",apdu)
res = res + nres
return (res,sw1,sw2)

View File

@ -30,10 +30,14 @@ class ConnectionFailed(Exception):
class AdminPINFailed(Exception): class AdminPINFailed(Exception):
pass pass
class UserPINFailed(Exception):
pass
class CardConnectionContext: class CardConnectionContext:
def __init__(self): def __init__(self):
self.reader_index = 0 self.reader_index = 0
self.admin_pin = "123456"
self.admin_pin = "12345678" self.admin_pin = "12345678"
self.connection = None self.connection = None
self.read_pin = self._default_pin_read_function self.read_pin = self._default_pin_read_function
@ -57,6 +61,16 @@ class CardConnectionContext:
else: else:
raise AdminPINFailed raise AdminPINFailed
def verify_user_pin(self):
if self.verified:
return
user_pin = self.read_pin("User")
(_,sw1,sw2)=verif_user_pin(self.connection, user_pin)
if sw1==0x90 and sw2==0x00:
self.verified = True
else:
raise UserPINFailed
def connect(self): def connect(self):
if self.connected: if self.connected:
return return
@ -220,7 +234,7 @@ class CardConnectionContext:
f.close() f.close()
self.connect() self.connect()
self.verify_admin_pin() self.verify_admin_pin()
put_sm_certificate(self.connection,cert) put_sm_certificate(self.connection, cert)
def cmd_get_sm_certificate(self): def cmd_get_sm_certificate(self):
if self.output is None: if self.output is None:
@ -232,3 +246,54 @@ class CardConnectionContext:
with open(self.output, 'w') as f: with open(self.output, 'w') as f:
f.write(cert) f.write(cert)
f.close() f.close()
def cmd_put_aes_key(self):
if self.input is None:
print "No input AES key file"
return
f = open(self.input, 'r')
key = f.read()
key = [ord(c) for c in key]
f.close()
self.connect()
self.verify_admin_pin()
put_aes_key(self.connection, key)
def cmd_encrypt_aes(self):
if self.input is None:
print "No input data file"
return
if self.output is None:
print "No output data file"
return
f = open(self.input, 'r')
data = f.read()
data = [ord(c) for c in data]
f.close()
self.connect()
self.verify_user_pin()
(data,_,_) = encrypt_aes(self.connection, data)
data = "".join([chr(c) for c in data])
with open(self.output, 'w') as f:
f.write(data)
f.close()
def cmd_decrypt_aes(self):
if self.input is None:
print "No input data file"
return
if self.output is None:
print "No output data file"
return
f = open(self.input, 'r')
data = f.read()
data = [ord(c) for c in data]
f.close()
self.connect()
self.verify_user_pin()
(data,_,_) = decrypt_aes(self.connection, data)
data = "".join([chr(c) for c in data])
with open(self.output, 'w') as f:
f.write(data)
f.close()