Implement setup-kdf in smartpgp-cli

This commit is contained in:
Arnaud Fontaine 2020-01-23 19:37:41 +01:00
parent 9b77f6c26b
commit 4be0fa442b
3 changed files with 120 additions and 0 deletions

View File

@ -50,6 +50,7 @@ VALID_COMMANDS={
'decrypt-aes': CardConnectionContext.cmd_decrypt_aes,
'get-kdf': CardConnectionContext.cmd_get_kdf,
'set-kdf': CardConnectionContext.cmd_set_kdf,
'setup-kdf': CardConnectionContext.cmd_setup_kdf,
}
def read_pin_interactive(name):

View File

@ -23,6 +23,10 @@ from smartcard.System import readers
from smartcard.util import toHexString
import struct
import os
import array
import hashlib
SELECT = [0x00, 0xA4, 0x04, 0x00,
0x06,
@ -110,6 +114,27 @@ def encode_len(data):
l = [l & 0xff]
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):
print "%s" % text
apdu = [int(c) for c in apdu]
@ -396,3 +421,22 @@ def get_kdf_do(connection):
apdu = [0x00, 0xCA, 0x00, 0xF9, 0x00]
(data,sw1,sw2) = _raw_send_apdu(connection,"Get KDF-DO",apdu)
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)

View File

@ -24,6 +24,11 @@ import pyasn1
from pyasn1.type import univ
from pyasn1.codec.der import encoder as der_encoder,decoder as der_decoder
class InvalidKDF(Exception):
pass
class ConnectionFailed(Exception):
pass
@ -343,3 +348,73 @@ class CardConnectionContext:
with open(self.output, 'w') as f:
f.write(kdf_do)
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)