diff options
-rw-r--r-- | cryptech/libhal.py | 27 | ||||
-rwxr-xr-x | cryptech_backup | 16 | ||||
-rw-r--r-- | 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) -@unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package") +@unittest.skipUnless(pycrypto_loaded, "Requires Python Cryptodome package") class TestPKeyRSAInterop(TestCaseLoggedIn): @staticmethod @@ -1575,7 +1573,7 @@ class TestPkeyECDSAVerificationNIST(TestCaseLoggedIn): py_hash = SHA384) -@unittest.skipUnless(pycrypto_loaded, "Requires Python Crypto package") +@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): |