mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-16 18:38:32 +03:00
global_platform: KCV support for PUT KEY
GlobalPlatform requires the use of the KCV for DES + AES keys. Let's implement that. (11.8.2.3.3: "For all key types described in section B.6, the Key Check Value shall be present.") Change-Id: Ief168a66dee58b56f4126db12829b3a98906c8db
This commit is contained in:
@@ -539,7 +539,8 @@ class ADF_SD(CardADF):
|
||||
if opts.key_check and len(opts.key_check) > i:
|
||||
kcv = opts.key_check[i]
|
||||
else:
|
||||
kcv = ''
|
||||
kcv_bin = compute_kcv(opts.key_type[i], h2b(opts.key_data[i])) or b''
|
||||
kcv = b2h(kcv_bin)
|
||||
kdb.append({'key_type': opts.key_type[i], 'kcb': opts.key_data[i], 'kcv': kcv})
|
||||
p2 = opts.key_id
|
||||
if len(opts.key_type) > 1:
|
||||
@@ -770,3 +771,35 @@ class GpCardKeyset:
|
||||
def __str__(self):
|
||||
return "%s(KVN=%u, ENC=%s, MAC=%s, DEK=%s)" % (self.__class__.__name__,
|
||||
self.kvn, b2h(self.enc), b2h(self.mac), b2h(self.dek))
|
||||
|
||||
from Cryptodome.Cipher import DES, DES3, AES
|
||||
|
||||
def compute_kcv_des(key:bytes) -> bytes:
|
||||
# GP Card Spec B.6: For a DES key, the key check value is computed by encrypting 8 bytes, each with
|
||||
# value '00', with the key to be checked and retaining the 3 highest-order bytes of the encrypted
|
||||
# result.
|
||||
plaintext = b'\x00' * 8
|
||||
cipher = DES3.new(key, DES.MODE_ECB)
|
||||
return cipher.encrypt(plaintext)
|
||||
|
||||
def compute_kcv_aes(key:bytes) -> bytes:
|
||||
# GP Card Spec B.6: For a AES key, the key check value is computed by encrypting 16 bytes, each with
|
||||
# value '01', with the key to be checked and retaining the 3 highest-order bytes of the encrypted
|
||||
# result.
|
||||
plaintext = b'\x01' * 16
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
return cipher.encrypt(plaintext)
|
||||
|
||||
# dict is keyed by the string name of the KeyType enum above in this file
|
||||
KCV_CALCULATOR = {
|
||||
'aes': compute_kcv_aes,
|
||||
'des': compute_kcv_des,
|
||||
}
|
||||
|
||||
def compute_kcv(key_type: str, key: bytes) -> Optional[bytes]:
|
||||
"""Compute the KCV (Key Check Value) for given key type and key."""
|
||||
kcv_calculator = KCV_CALCULATOR.get(key_type)
|
||||
if not kcv_calculator:
|
||||
return None
|
||||
else:
|
||||
return kcv_calculator(key)[:3]
|
||||
|
||||
@@ -214,6 +214,12 @@ class SCP03_Test_AES256_33(SCP03_Test, unittest.TestCase):
|
||||
# FIXME: test auth with random (0x60) vs pseudo-random (0x70) challenge
|
||||
|
||||
|
||||
class SCP03_KCV_Test(unittest.TestCase):
|
||||
def test_kcv(self):
|
||||
self.assertEqual(compute_kcv('aes', KEYSET_AES128.enc), h2b('C35280'))
|
||||
self.assertEqual(compute_kcv('aes', KEYSET_AES128.mac), h2b('013808'))
|
||||
self.assertEqual(compute_kcv('aes', KEYSET_AES128.dek), h2b('840DE5'))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user