Implement setup-kdf in smartpgp-cli
This commit is contained in:
parent
9b77f6c26b
commit
4be0fa442b
@ -50,6 +50,7 @@ VALID_COMMANDS={
|
|||||||
'decrypt-aes': CardConnectionContext.cmd_decrypt_aes,
|
'decrypt-aes': CardConnectionContext.cmd_decrypt_aes,
|
||||||
'get-kdf': CardConnectionContext.cmd_get_kdf,
|
'get-kdf': CardConnectionContext.cmd_get_kdf,
|
||||||
'set-kdf': CardConnectionContext.cmd_set_kdf,
|
'set-kdf': CardConnectionContext.cmd_set_kdf,
|
||||||
|
'setup-kdf': CardConnectionContext.cmd_setup_kdf,
|
||||||
}
|
}
|
||||||
|
|
||||||
def read_pin_interactive(name):
|
def read_pin_interactive(name):
|
||||||
|
@ -23,6 +23,10 @@ from smartcard.System import readers
|
|||||||
from smartcard.util import toHexString
|
from smartcard.util import toHexString
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
|
import os
|
||||||
|
import array
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
SELECT = [0x00, 0xA4, 0x04, 0x00,
|
SELECT = [0x00, 0xA4, 0x04, 0x00,
|
||||||
0x06,
|
0x06,
|
||||||
@ -110,6 +114,27 @@ def encode_len(data):
|
|||||||
l = [l & 0xff]
|
l = [l & 0xff]
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def kdf_itersalted_s2k(salt, value, algo, count):
|
||||||
|
if algo == 0x08: #SHA256
|
||||||
|
f = hashlib.new('sha256')
|
||||||
|
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()
|
||||||
|
datalen = len(data)
|
||||||
|
while datalen <= count:
|
||||||
|
f.update(data)
|
||||||
|
count -= datalen
|
||||||
|
if 0 < count:
|
||||||
|
f.update(data[0:count])
|
||||||
|
return f.digest()
|
||||||
|
|
||||||
|
|
||||||
def _raw_send_apdu(connection, text, apdu):
|
def _raw_send_apdu(connection, text, apdu):
|
||||||
print "%s" % text
|
print "%s" % text
|
||||||
apdu = [int(c) for c in apdu]
|
apdu = [int(c) for c in apdu]
|
||||||
@ -396,3 +421,22 @@ def get_kdf_do(connection):
|
|||||||
apdu = [0x00, 0xCA, 0x00, 0xF9, 0x00]
|
apdu = [0x00, 0xCA, 0x00, 0xF9, 0x00]
|
||||||
(data,sw1,sw2) = _raw_send_apdu(connection,"Get KDF-DO",apdu)
|
(data,sw1,sw2) = _raw_send_apdu(connection,"Get KDF-DO",apdu)
|
||||||
return (data,sw1,sw2)
|
return (data,sw1,sw2)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
return (sw1,sw2)
|
||||||
|
|
||||||
|
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)
|
||||||
|
return (sw1,sw2)
|
||||||
|
@ -24,6 +24,11 @@ import pyasn1
|
|||||||
from pyasn1.type import univ
|
from pyasn1.type import univ
|
||||||
from pyasn1.codec.der import encoder as der_encoder,decoder as der_decoder
|
from pyasn1.codec.der import encoder as der_encoder,decoder as der_decoder
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidKDF(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class ConnectionFailed(Exception):
|
class ConnectionFailed(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -343,3 +348,73 @@ class CardConnectionContext:
|
|||||||
with open(self.output, 'w') as f:
|
with open(self.output, 'w') as f:
|
||||||
f.write(kdf_do)
|
f.write(kdf_do)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_setup_kdf(self):
|
||||||
|
self.connect()
|
||||||
|
(kdf_do,_,_) = get_kdf_do(self.connection)
|
||||||
|
if 5 < len(kdf_do):
|
||||||
|
print "KDF already setup"
|
||||||
|
return
|
||||||
|
####### step 1
|
||||||
|
pw1 = self.read_pin("User")
|
||||||
|
resetting_code = self.read_pin("PUK")
|
||||||
|
if len(resetting_code) == 0:
|
||||||
|
resetting_code = None
|
||||||
|
pw3 = self.read_pin("Admin")
|
||||||
|
####### step 1bis
|
||||||
|
pw1 = pw1
|
||||||
|
if resetting_code <> None:
|
||||||
|
resetting_code = resetting_code
|
||||||
|
pw3 = pw3
|
||||||
|
####### step 2
|
||||||
|
salt_size = 8
|
||||||
|
algo = 0x08 #SHA256
|
||||||
|
nbiter = 200000
|
||||||
|
ndata81 = [0x81, 0x01, 0x03] #KDF_ITERSALTED_S2K
|
||||||
|
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
|
||||||
|
salt_resetting_code = os.urandom(salt_size)
|
||||||
|
ndata85 = assemble_with_len([0x85], [ord(c) for c in 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]
|
||||||
|
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]
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
nresetting_code = None
|
||||||
|
npw3 = kdf_itersalted_s2k(salt_pw3, pw3, algo, nbiter)
|
||||||
|
####### step 3
|
||||||
|
(_,sw1,sw2) = verif_admin_pin(self.connection, pw3)
|
||||||
|
if sw1==0x90 and sw2==0x00:
|
||||||
|
self.verified = True
|
||||||
|
else:
|
||||||
|
raise AdminPINFailed
|
||||||
|
####### step 3bis
|
||||||
|
if nresetting_code <> None:
|
||||||
|
set_resetting_code(self.connection, nresetting_code)
|
||||||
|
if sw1!=0x90 or sw2!=0x00:
|
||||||
|
print "set_resetting_code failed"
|
||||||
|
return
|
||||||
|
####### step 4
|
||||||
|
change_reference_data_pw1(self.connection, pw1, npw1)
|
||||||
|
if sw1!=0x90 or sw2!=0x00:
|
||||||
|
print "change_reference_data_pw1 failed"
|
||||||
|
return
|
||||||
|
####### step 4bis
|
||||||
|
change_reference_data_pw3(self.connection, pw3, npw3)
|
||||||
|
if sw1!=0x90 or sw2!=0x00:
|
||||||
|
print "change_reference_data_pw3 failed"
|
||||||
|
return
|
||||||
|
####### step 5
|
||||||
|
put_kdf_do(self.connection, nkdf_do)
|
||||||
|
Loading…
Reference in New Issue
Block a user