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-certificate': CardConnectionContext.cmd_put_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):
|
||||
|
@ -29,7 +29,8 @@ SELECT = [0x00, 0xA4, 0x04, 0x00,
|
||||
0xD2, 0x76, 0x00, 0x01, 0x24, 0x01,
|
||||
0x00]
|
||||
|
||||
VERIFY = [0x00, 0x20, 0x00, 0x83]
|
||||
VERIFY_ADMIN = [0x00, 0x20, 0x00, 0x83]
|
||||
VERIFY_USER_82 = [0x00, 0x20, 0x00, 0x82]
|
||||
TERMINATE = [0x00, 0xe6, 0x00, 0x00]
|
||||
ACTIVATE = [0x00, 0x44, 0x00, 0x00]
|
||||
ACTIVATE_FULL = [0x00, 0x44, 0x00, 0x01]
|
||||
@ -111,9 +112,10 @@ def encode_len(data):
|
||||
|
||||
def _raw_send_apdu(connection, text, apdu):
|
||||
print "%s" % text
|
||||
data, sw1, sw2 = connection.transmit(apdu)
|
||||
print data
|
||||
print "%s: %02X %02X" % (text, sw1, sw2)
|
||||
#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)
|
||||
return (data,sw1,sw2)
|
||||
|
||||
def list_readers():
|
||||
@ -136,9 +138,13 @@ def select_applet(connection):
|
||||
return _raw_send_apdu(connection,"Select OpenPGP Applet",SELECT)
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
_raw_send_apdu(connection,"Terminate",TERMINATE)
|
||||
_raw_send_apdu(connection,"Activate",ACTIVATE_FULL)
|
||||
@ -259,7 +265,7 @@ def get_sm_certificate(connection):
|
||||
apdu = [0x00, 0xCA, 0x7F, 0x21, 0x00]
|
||||
(data,sw1,sw2) = _raw_send_apdu(connection,"Receiving SM certificate chunk",apdu)
|
||||
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)
|
||||
data = data + ndata
|
||||
return (data,sw1,sw2)
|
||||
@ -282,3 +288,55 @@ def get_sm_curve_oid(connection):
|
||||
#print ' '.join('{:02X}'.format(c) for c in curve)
|
||||
# Add DER OID header manually ...
|
||||
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):
|
||||
pass
|
||||
|
||||
class UserPINFailed(Exception):
|
||||
pass
|
||||
|
||||
class CardConnectionContext:
|
||||
|
||||
def __init__(self):
|
||||
self.reader_index = 0
|
||||
self.admin_pin = "123456"
|
||||
self.admin_pin = "12345678"
|
||||
self.connection = None
|
||||
self.read_pin = self._default_pin_read_function
|
||||
@ -57,6 +61,16 @@ class CardConnectionContext:
|
||||
else:
|
||||
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):
|
||||
if self.connected:
|
||||
return
|
||||
@ -220,7 +234,7 @@ class CardConnectionContext:
|
||||
f.close()
|
||||
self.connect()
|
||||
self.verify_admin_pin()
|
||||
put_sm_certificate(self.connection,cert)
|
||||
put_sm_certificate(self.connection, cert)
|
||||
|
||||
def cmd_get_sm_certificate(self):
|
||||
if self.output is None:
|
||||
@ -232,3 +246,54 @@ class CardConnectionContext:
|
||||
with open(self.output, 'w') as f:
|
||||
f.write(cert)
|
||||
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