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 <laforge(a)osmocom.org>
Gerrit-MessageType: newchange