Add support for AES commands in smartpgp-cli
This commit is contained in:
parent
ec84edb737
commit
60b6b09192
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user