[Cryptech-Commits] [sw/libhal] branch master updated: Replace old PyCrypto with PyCryptodome

git at cryptech.is git at cryptech.is
Tue Jan 4 14:16:48 UTC 2022


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch master
in repository sw/libhal.

The following commit(s) were added to refs/heads/master by this push:
     new 6f0d823  Replace old PyCrypto with PyCryptodome
6f0d823 is described below

commit 6f0d8236b8622a68f42284ed1314d8acd86c89ed
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Tue Jan 4 09:12:47 2022 -0500

    Replace old PyCrypto with PyCryptodome
    
    PyCrypto is no longer present in Debian Bullseye and is abandonware in
    anycase.  PyCryptodome is about 98% of a drop-in replacement (but that
    last 2% can be tricky), so convert the most critical stuff to use
    PyCryptodome.
    
    A bunch of the test scripts and so forth still need to be converted,
    for today the goals are just to have the package install properly and
    to be able to run the unit tests.
---
 cryptech/libhal.py | 27 ++++++++++++--------
 cryptech_backup    | 16 ++++++------
 unit-tests.py      | 72 ++++++++++++++++++++++++++----------------------------
 3 files changed, 60 insertions(+), 55 deletions(-)

diff --git a/cryptech/libhal.py b/cryptech/libhal.py
index 102e663..105dd02 100644
--- a/cryptech/libhal.py
+++ b/cryptech/libhal.py
@@ -347,7 +347,8 @@ class LocalDigest(object):
     """
 
     def __init__(self, hsm, handle, algorithm, key):
-        from Crypto.Hash import HMAC, SHA, SHA224, SHA256, SHA384, SHA512
+        from Cryptodome.Hash import HMAC, SHA1, SHA224, SHA256, SHA384, SHA512
+        from Cryptodome.Util.asn1 import DerObjectId
         from struct import pack
         self.hsm       = hsm
         self.handle    = handle
@@ -356,16 +357,22 @@ class LocalDigest(object):
             h = self._algorithms[algorithm]
         except AttributeError:
             self._algorithms = {
-                HAL_DIGEST_ALGORITHM_SHA1   : SHA.SHA1Hash,
-                HAL_DIGEST_ALGORITHM_SHA224 : SHA224.SHA224Hash,
-                HAL_DIGEST_ALGORITHM_SHA256 : SHA256.SHA256Hash,
-                HAL_DIGEST_ALGORITHM_SHA384 : SHA384.SHA384Hash,
-                HAL_DIGEST_ALGORITHM_SHA512 : SHA512.SHA512Hash
+                HAL_DIGEST_ALGORITHM_SHA1   : SHA1,
+                HAL_DIGEST_ALGORITHM_SHA224 : SHA224,
+                HAL_DIGEST_ALGORITHM_SHA256 : SHA256,
+                HAL_DIGEST_ALGORITHM_SHA384 : SHA384,
+                HAL_DIGEST_ALGORITHM_SHA512 : SHA512
             }
             h = self._algorithms[algorithm]
         self.digest_length = h.digest_size
-        self.algorithm_id  = pack("BB", 0x30, 2 + len(h.oid)) + h.oid
-        self._context = HMAC.HMAC(key = key, digestmod = h) if key else h()
+        if key:
+            self._context = HMAC.new(key = key, digestmod = h)
+            oid = h.new().oid
+        else:
+            self._context = h.new()
+            oid = self._context.oid
+        self.oid = DerObjectId(oid).encode()
+        self.algorithm_id = pack("BB", 0x30, 2 + len(self.oid)) + self.oid
 
     def update(self, data):
         self._context.update(data)
@@ -377,8 +384,8 @@ class LocalDigest(object):
         if pkey.key_type not in (HAL_KEY_TYPE_RSA_PRIVATE, HAL_KEY_TYPE_RSA_PUBLIC):
             return self.finalize()
         # PKCS #1.5 requires the digest to be wrapped up in an ASN.1 DigestInfo object.
-        from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
-        return DerSequence([DerSequence([self._context.oid, DerNull().encode()]).encode(),
+        from Cryptodome.Util.asn1 import DerSequence, DerNull, DerOctetString
+        return DerSequence([DerSequence([self.oid, DerNull().encode()]).encode(),
                             DerOctetString(self.finalize()).encode()]).encode()
 
 
diff --git a/cryptech_backup b/cryptech_backup
index a15c9c0..99d2c38 100755
--- a/cryptech_backup
+++ b/cryptech_backup
@@ -21,7 +21,7 @@ We also implement a software-based variant on this backup mechanism,
 for cases where there is no second HSM.  The protocol is much the
 same, but the KEKEK is generated in software and encrypted using a
 symmetric key derived from a passphrase using PBKDF2.  This requires
-the PyCrypto library, and is only as secure as memory on the machine
+the PyCryptodome library, and is only as secure as memory on the machine
 where you're running it (so it's theoretically vulnerable to root or
 anybody with access to /dev/mem).  Don't use this mode unless you
 understand the risks, and see the "NOTE WELL" above.
@@ -305,7 +305,7 @@ class AESKeyWrapWithPadding(object):
         "Something went wrong during unwrap."
 
     def __init__(self, key):
-        from Crypto.Cipher import AES
+        from Cryptodome.Cipher import AES
         self.ctx = AES.new(key, AES.MODE_ECB)
 
     def _encrypt(self, b1, b2):
@@ -391,7 +391,7 @@ class SoftKEKEK(object):
         time.clock = time.process_time
 
     def parse_EncryptedPrivateKeyInfo(self, der):
-        from Crypto.Util.asn1 import DerObject, DerSequence, DerOctetString, DerObjectId
+        from Cryptodome.Util.asn1 import DerObject, DerSequence, DerOctetString, DerObjectId
         encryptedPrivateKeyInfo = DerSequence()
         encryptedPrivateKeyInfo.decode(der)
         encryptionAlgorithm = DerSequence()
@@ -405,7 +405,7 @@ class SoftKEKEK(object):
         return encryptedData.payload
 
     def encode_EncryptedPrivateKeyInfo(self, der):
-        from Crypto.Util.asn1 import DerSequence, DerOctetString
+        from Cryptodome.Util.asn1 import DerSequence, DerOctetString
         return DerSequence([
             DerSequence([
                 struct.pack("BB", 0x06, len(self.oid_aesKeyWrap)) + self.oid_aesKeyWrap
@@ -414,12 +414,12 @@ class SoftKEKEK(object):
         ]).encode()
 
     def gen_salt(self, bytes = 16):
-        from Crypto import Random
+        from Cryptodome import Random
         return Random.new().read(bytes)
 
     def wrapper(self, salt, keylen = 256, iterations = 8000):
-        from Crypto.Protocol.KDF import PBKDF2
-        from Crypto.Hash         import SHA256, HMAC
+        from Cryptodome.Protocol.KDF import PBKDF2
+        from Cryptodome.Hash         import SHA256, HMAC
         return AESKeyWrapWithPadding(PBKDF2(
             password = getpass.getpass("KEKEK Passphrase: "),
             salt     = salt,
@@ -433,7 +433,7 @@ class SoftKEKEK(object):
 
     @classmethod
     def generate(cls, args, result):
-        from Crypto.PublicKey import RSA
+        from Cryptodome.PublicKey import RSA
         self = cls()
         k = RSA.generate(args.keylen)
         salt  = self.gen_salt()
diff --git a/unit-tests.py b/unit-tests.py
index 526379c..bdb6f77 100644
--- a/unit-tests.py
+++ b/unit-tests.py
@@ -49,19 +49,17 @@ from struct import pack, unpack
 from cryptech.libhal import *
 
 try:
-    from Crypto.Util.number             import inverse
-    from Crypto.PublicKey               import RSA
-    from Crypto.Cipher                  import AES
-    from Crypto.Cipher.PKCS1_v1_5       import PKCS115_Cipher
-    from Crypto.Signature.PKCS1_v1_5    import PKCS115_SigScheme
-    from Crypto.Hash.SHA256             import SHA256Hash as SHA256
-    from Crypto.Hash.SHA384             import SHA384Hash as SHA384
-    from Crypto.Hash.SHA512             import SHA512Hash as SHA512
+    from Cryptodome.Util.number             import inverse
+    from Cryptodome.PublicKey               import RSA
+    from Cryptodome.Cipher                  import AES, PKCS1_v1_5
+    from Cryptodome.Signature               import pkcs1_15
+    from Cryptodome.Hash.SHA256             import new as SHA256
+    from Cryptodome.Hash.SHA384             import new as SHA384
+    from Cryptodome.Hash.SHA512             import new as SHA512
     pycrypto_loaded = True
 except ImportError:
     pycrypto_loaded = False
 
-
 try:
     from ecdsa                          import der as ECDSA_DER
     from ecdsa.keys                     import SigningKey as ECDSA_SigningKey
@@ -998,15 +996,15 @@ class TestPKeyHashing(TestCaseLoggedIn):
         k1.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
         k2.verify(signature = sig, hash = self.h(alg, mixed_mode = True))
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_1024_sha256_data(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_data)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_2048_sha384_data(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_data)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_4096_sha512_data(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_data)
 
@@ -1022,15 +1020,15 @@ class TestPKeyHashing(TestCaseLoggedIn):
     def test_load_sign_verify_ecdsa_p521_sha512_data(self):
         self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_data)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_1024_sha256_remote_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_remote_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_2048_sha384_remote_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_remote_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_4096_sha512_remote_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_remote_remote)
 
@@ -1046,15 +1044,15 @@ class TestPKeyHashing(TestCaseLoggedIn):
     def test_load_sign_verify_ecdsa_p521_sha512_remote_remote(self):
         self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_remote_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_1024_sha256_remote_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_remote_local)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_2048_sha384_remote_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_remote_local)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_4096_sha512_remote_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_remote_local)
 
@@ -1070,15 +1068,15 @@ class TestPKeyHashing(TestCaseLoggedIn):
     def test_load_sign_verify_ecdsa_p521_sha512_remote_local(self):
         self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_remote_local)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_1024_sha256_local_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_local_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_2048_sha384_local_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_local_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_4096_sha512_local_remote(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_local_remote)
 
@@ -1094,15 +1092,15 @@ class TestPKeyHashing(TestCaseLoggedIn):
     def test_load_sign_verify_ecdsa_p521_sha512_local_remote(self):
         self.load_sign_verify_ecdsa(HAL_DIGEST_ALGORITHM_SHA512, HAL_CURVE_P521, self.sign_verify_local_remote)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_1024_sha256_local_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA256, 1024, self.sign_verify_local_local)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_2048_sha384_local_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA384, 2048, self.sign_verify_local_local)
 
-    @unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+    @unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
     def test_load_sign_verify_rsa_4096_sha512_local_local(self):
         self.load_sign_verify_rsa(HAL_DIGEST_ALGORITHM_SHA512, 4096, self.sign_verify_local_local)
 
@@ -1131,7 +1129,7 @@ class TestPKeyHashing(TestCaseLoggedIn):
         self.gen_sign_verify_hashsig(1, HAL_LMS_SHA256_N32_H5, HAL_LMOTS_SHA256_N32_W4, 2352, self.sign_verify_local_local)
 
 
- at unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+ at unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
 class TestPKeyRSAInterop(TestCaseLoggedIn):
 
     @staticmethod
@@ -1575,7 +1573,7 @@ class TestPkeyECDSAVerificationNIST(TestCaseLoggedIn):
             py_hash   = SHA384)
 
 
- at unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package")
+ at unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package")
 class TestPKeyBackup(TestCaseLoggedIn):
 
     oid_rsaEncryption = b"\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"
@@ -1583,7 +1581,7 @@ class TestPKeyBackup(TestCaseLoggedIn):
 
     @staticmethod
     def parse_EncryptedPrivateKeyInfo(der, oid):
-        from Crypto.Util.asn1 import DerObject, DerSequence, DerOctetString, DerObjectId
+        from Cryptodome.Util.asn1 import DerObject, DerSequence, DerOctetString, DerObjectId
         encryptedPrivateKeyInfo = DerSequence()
         encryptedPrivateKeyInfo.decode(der)
         encryptionAlgorithm = DerSequence()
@@ -1606,7 +1604,7 @@ class TestPKeyBackup(TestCaseLoggedIn):
 
     @staticmethod
     def encode_EncryptedPrivateKeyInfo(der, oid):
-        from Crypto.Util.asn1 import DerSequence, DerOctetString
+        from Cryptodome.Util.asn1 import DerSequence, DerOctetString
         return DerSequence([
             DerSequence([pack("BB", 0x06, len(oid)) + oid]).encode(),
             DerOctetString(der).encode()
@@ -1614,15 +1612,15 @@ class TestPKeyBackup(TestCaseLoggedIn):
 
     @staticmethod
     def make_kek():
-        import Crypto.Random
-        return Crypto.Random.new().read(256//8)
+        import Cryptodome.Random
+        return Cryptodome.Random.new().read(256//8)
 
     def sig_check(self, pkey, der):
-        from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString
-        p115 = PKCS115_SigScheme(RSA.importKey(der))
+        from Cryptodome.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId
+        p115 = pkcs1_15.new(RSA.importKey(der))
         hash = SHA256("Your mother was a hamster".encode())
         data = DerSequence([
-            DerSequence([hash.oid, DerNull().encode()]).encode(),
+            DerSequence([DerObjectId(hash.oid).encode(), DerNull().encode()]).encode(),
             DerOctetString(hash.digest()).encode()
         ]).encode()
         sig1 = p115.sign(hash)
@@ -1643,7 +1641,7 @@ class TestPKeyBackup(TestCaseLoggedIn):
             flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE | HAL_KEY_FLAG_EXPORTABLE)
         self.addCleanup(pkey.delete)
         pkcs8_der, kek_der = kekek.export_pkey(pkey)
-        kek = PKCS115_Cipher(PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, 1024].obj).decrypt(
+        kek = PKCS1_v1_5.new(PreloadedKey.db[HAL_KEY_TYPE_RSA_PRIVATE, 1024].obj).decrypt(
             self.parse_EncryptedPrivateKeyInfo(kek_der, self.oid_rsaEncryption),
             self.make_kek())
         der = AESKeyWrapWithPadding(kek).unwrap(
@@ -1662,7 +1660,7 @@ class TestPKeyBackup(TestCaseLoggedIn):
                 AESKeyWrapWithPadding(kek).wrap(der),
                 self.oid_aesKeyWrap),
             kek = self.encode_EncryptedPrivateKeyInfo(
-                PKCS115_Cipher(RSA.importKey(kekek.public_key)).encrypt(kek),
+                PKCS1_v1_5.new(RSA.importKey(kekek.public_key)).encrypt(kek),
                 self.oid_rsaEncryption),
             flags = HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE)
         self.addCleanup(pkey.delete)
@@ -1800,10 +1798,10 @@ class PreloadedRSAKey(PreloadedKey):
                 k2, k2.exportKey(format = "DER"          ), keylen = keylen)
 
     def sign(self, text, hash):
-        return PKCS115_SigScheme(self.obj).sign(hash(text))
+        return pkcs1_15.new(self.obj).sign(hash(text))
 
     def verify(self, text, hash, signature):
-        return PKCS115_SigScheme(self.obj).verify(hash(text), signature)
+        return pkcs1_15.new(self.obj).verify(hash(text), signature)
 
 class PreloadedECKey(PreloadedKey):
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Commits mailing list