laforge has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/35803?usp=email )


Change subject: global_platform: KCV support for PUT KEY
......................................................................

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
---
M pySim/global_platform/__init__.py
M tests/test_globalplatform.py
2 files changed, 55 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/03/35803/1

diff --git a/pySim/global_platform/__init__.py 
b/pySim/global_platform/__init__.py
index b6d2343..494cfe1 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -539,7 +539,8 @@
                 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 @@
     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]
diff --git a/tests/test_globalplatform.py b/tests/test_globalplatform.py
index 62eb43e..bf5ffdb 100644
--- a/tests/test_globalplatform.py
+++ b/tests/test_globalplatform.py
@@ -202,6 +202,12 @@
 # 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()

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/35803?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Ief168a66dee58b56f4126db12829b3a98906c8db
Gerrit-Change-Number: 35803
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <[email protected]>
Gerrit-MessageType: newchange

Reply via email to