You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classInvalidDUKPTArguments(Exception):
passclassDUKPT:
"""Base DUKPT class with common functions of both client and server"""_pin_mask=BitArray(hex="0x00000000000000FF00000000000000FF")
_mac_req_mask=BitArray(hex="0x000000000000FF00000000000000FF00")
_mac_resp_mask=BitArray(hex="0x00000000FF00000000000000FF000000")
_mac_data_req=BitArray(hex="0x0000000000FF00000000000000FF0000")
_mac_data_resp=BitArray(hex="0x000000FF00000000000000FF00000000")
_ipek=None_tdes_key=None_cur_key=None_ksn=NoneBDK_LEN=16KSN_LEN=10def__init__(self, bdk=None, ksn=None, ipek=None):
"""Initialization Keyword arguments: bdk (raw or BitArray) -- Base Derivation Key (16 bytes) ksn (raw or BitArray) -- Key Serial Number (10 bytes) ipek (raw or BitArray) -- Initial Pin Encryption Key (16 bytes) """ifipek:
ifisinstance(ipek, BitArray):
self._ipek=ipekelse:
self._ipek=BitArray(bytes=ipek)
ifisinstance(ksn, BitArray):
self._ksn=ksnelse:
self._ksn=BitArray(bytes=ksn)
else:
ifnotbdk:
raiseInvalidDUKPTArguments("Must have either ipek or bdk")
iflen(bdk) !=self.BDK_LEN:
raiseInvalidDUKPTArguments("BDK must have a length of %d"%self.BDK_LEN)
self._bdk=BitArray(bytes=bdk)
defderive_key(self, ipek, ksn):
"""Derive a unique key given the ipek and ksn Keyword arguments: ipek (BitArray) -- Initial Pin Encryption Key ksn (BitArray) -- Key Serial Number """c_mask=BitArray(hex='0xc0c0c0c000000000c0c0c0c000000000')
ksn_offset=2ctr_offset=-3right_offset=8# Registers taken from documentationcurkey=ipekksnr=BitArray(bytes=ksn.bytes[ksn_offset:])
r3=self.copy_counter(ksnr)
r8=self.reset_counter(ksnr.bytes)
sr=BitArray(hex='0x100000')
while (sr.bytes[0] !='\x00') or (sr.bytes[1] !='\x00') or (sr.bytes[2] !='\x00'):
tmp=self.copy_counter(sr)
tmp=tmp&r3if (tmp.bytes[0] !='\x00') or (tmp.bytes[1] !='\x00') or (tmp.bytes[2] !='\x00'):
# Step 2n_ctr=BitArray(bytes=r8.bytes[ctr_offset:]) |srr8=BitArray(bytes=r8.bytes[:ctr_offset]+n_ctr.bytes)
# Step 3r8a=r8^BitArray(bytes=curkey.bytes[right_offset:])
# Step 4cipher=DES.new(curkey.bytes[:DES.key_size], DES.MODE_ECB)
r8a=BitArray(bytes=cipher.encrypt(r8a.bytes))
# Step 5r8a=BitArray(bytes=curkey.bytes[right_offset:]) ^r8a# Step 6curkey=curkey^c_mask# Step 7r8b=BitArray(bytes=curkey.bytes[right_offset:]) ^r8# Step 8cipher=DES.new(curkey.bytes[:DES.key_size], DES.MODE_ECB)
r8b=BitArray(bytes=cipher.encrypt(r8b.bytes))
# Step 9r8b=BitArray(bytes=curkey.bytes[right_offset:]) ^r8b# Step 10 / 11curkey=BitArray(bytes=r8b.bytes+r8a.bytes)
sr >>= 1self._cur_key=curkeyreturncurkeydefreset_counter(self, data):
"""Reset the counter to zero Keyword arguments: data (raw or BitArray) -- Must be at least 3 bytes Return: BitArray of the data passed in """ifisinstance(data, BitArray):
data=data.bytesiflen(data) <3:
returnNonemask=BitArray(hex='0xe00000')
ctr=BitArray(bytes=data[len(data)-3:])
returnBitArray(bytes=data[:-3] + (mask&ctr).bytes)
defcopy_counter(self, data):
"""Copy only the counter bytes from a given string or BitArray Keyword arguments: data (raw or BitArray) -- Must be at least 3 bytes Return: BitArray of only the counter bytes """mask=BitArray(hex='0x1fffff')
iflen(data.bytes) >3:
ctr=BitArray(bytes=data.bytes[-3:])
else:
ctr=datareturnmask&ctrdefincrease_counter(self):
"""Increase the counter bytes of the stored ksn by one"""ctr=self._ksn.cut(21, start=59).next().int+1self._ksn.overwrite('0b'+BitArray(int=ctr, length=21).bin, 59)
classServer(DUKPT):
def__init__(self, bdk=None):
ifbdk:
DUKPT.__init__(self, bdk=bdk)
else:
self.bdk=self.generate_bdk()
DUKPT.__init__(self, bdk=self.bdk)
defgenerate_ksn(self):
"""Genereate a new random KSN with counter bits zeroed Return: BitArray of the new KSN """returnself.reset_counter(get_random_bytes(self.KSN_LEN))
defgenerate_bdk(self):
"""Generate a new random BDK Return: bytes of the new KSN """returnget_random_bytes(self.BDK_LEN)
defgenerate_ipek(self, ksn):
"""Generate a new IPEK based on the given KSN Keyword arguments: ksn (raw or BitArray) -- Key Serial Number Return: BitArray of the new IPEK """ifisinstance(ksn, str):
ksn=BitArray(bytes=ksn)
self._tdes_key=self._bdk.bytes+self._bdk.bytes[:DES.key_size]
self.generate_left_ipek(ksn)
self.generate_right_ipek(ksn)
returnself._ipekdefgenerate_left_ipek(self, ksn):
"""Generate the left portion of the IPEK (8 bytes) Keyword arguments: ksn (raw or BitArray) -- Key Serial Number) """ksn=self.reset_counter(ksn.bytes)
cipher=DES3.new(self._tdes_key, DES3.MODE_ECB)
self._ipek=BitArray(bytes=cipher.encrypt(ksn.bytes[:8]))
defgenerate_right_ipek(self, ksn):
"""Generate the right portion of the IPEK (8 bytes) Keyword arguments: ksn (raw or BitArray) -- Key Serial Number """mask=BitArray(hex="0xc0c0c0c000000000c0c0c0c000000000c0c0c0c000000000")
key=mask^BitArray(bytes=self._tdes_key)
cipher=DES3.new(key.bytes, DES3.MODE_ECB)
self._ipek=BitArray(bytes=self._ipek.bytes+cipher.encrypt(ksn.bytes[:8]))
defgen_key(self, ksn):
"""Generate the next key given the KSN Keyword arguments: ksn (raw or BitArray) -- Key Serial Number (10 bytes) Return: key in bytes """ipek=self.generate_ipek(ksn)
key=self.derive_key(ipek, BitArray(bytes=ksn))
returnkey.bytesclassClient(DUKPT):
def__init__(self, ipek, ksn):
"""Initialization of client Keyword arguments: ipek (raw or BitArray) -- Initial Pin Encryption Key ksn (raw or BitArray) -- Key Serial Number """DUKPT.__init__(self, ipek=ipek, ksn=ksn)
self.increase_counter()
defgen_key(self):
"""Generate the next key in the sequence Return: key in bytes """key=self.derive_key(self._ipek, self._ksn)
info= {'ksn': self._ksn.bytes, 'key': key.bytes}
self.increase_counter()
returninfo
The text was updated successfully, but these errors were encountered:
The text was updated successfully, but these errors were encountered: