diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2017-09-30 18:28:37 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2017-10-01 14:07:39 +0200 |
commit | 2c8a9b7b1b87a3cc07aac800d77db4652165d3e1 (patch) | |
tree | 6993ac83f643cbb4fb76e61d984f2be5e2947492 | |
parent | d0eddf88287bce398cb7a55ee20b384e3f764a4d (diff) |
Replace use of pycrypto utility functions
This uses os.urandom() as a source for random data and replaces other
utility functions. This also removes one import for getting the lengths
of Tripple DES keys.
-rw-r--r-- | pskc/crypto/aeskw.py | 21 | ||||
-rw-r--r-- | pskc/crypto/tripledeskw.py | 6 | ||||
-rw-r--r-- | pskc/encryption.py | 20 | ||||
-rw-r--r-- | pskc/mac.py | 4 | ||||
-rw-r--r-- | tests/test_aeskw.doctest | 8 | ||||
-rw-r--r-- | tests/test_write.doctest | 4 |
6 files changed, 34 insertions, 29 deletions
diff --git a/pskc/crypto/aeskw.py b/pskc/crypto/aeskw.py index 416d79b..7396f26 100644 --- a/pskc/crypto/aeskw.py +++ b/pskc/crypto/aeskw.py @@ -1,7 +1,7 @@ # aeskw.py - implementation of AES key wrapping # coding: utf-8 # -# Copyright (C) 2014-2015 Arthur de Jong +# Copyright (C) 2014-2017 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -21,14 +21,21 @@ """Implement key wrapping as described in RFC 3394 and RFC 5649.""" import binascii +import struct from Crypto.Cipher import AES -from Crypto.Util.number import bytes_to_long, long_to_bytes -from Crypto.Util.strxor import strxor from pskc.exceptions import DecryptionError, EncryptionError +def _strxor(a, b): + """Return a XOR b.""" + if isinstance(b'', str): # pragma: no cover (Python 2 specific) + return b''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)) + else: # pragma: no cover (Python 3 specific) + return bytes(x ^ y for (x, y) in zip(a, b)) + + def _split(value): return value[:8], value[8:] @@ -60,7 +67,7 @@ def wrap(plaintext, key, iv=None, pad=None): if iv is None: if len(plaintext) != mli or pad is True: - iv = RFC5649_IV + long_to_bytes(mli, 4) + iv = RFC5649_IV + struct.pack('>I', mli) else: iv = RFC3394_IV @@ -77,7 +84,7 @@ def wrap(plaintext, key, iv=None, pad=None): for j in range(6): for i in range(n): A, R[i] = _split(encrypt(A + R[i])) - A = strxor(A, long_to_bytes(n * j + i + 1, 8)) + A = _strxor(A, struct.pack('>Q', n * j + i + 1)) return A + b''.join(R) @@ -107,7 +114,7 @@ def unwrap(ciphertext, key, iv=None, pad=None): for i in range(n)] for j in reversed(range(6)): for i in reversed(range(n)): - A = strxor(A, long_to_bytes(n * j + i + 1, 8)) + A = _strxor(A, struct.pack('>Q', n * j + i + 1)) A, R[i] = _split(decrypt(A + R[i])) plaintext = b''.join(R) @@ -115,7 +122,7 @@ def unwrap(ciphertext, key, iv=None, pad=None): if A == RFC3394_IV and pad is not True: return plaintext elif A[:4] == RFC5649_IV and pad is not False: - mli = bytes_to_long(A[4:]) + mli = struct.unpack('>I', A[4:])[0] # check padding length is valid and plaintext only contains zeros if 8 * (n - 1) < mli <= 8 * n and \ plaintext.endswith((len(plaintext) - mli) * b'\0'): diff --git a/pskc/crypto/tripledeskw.py b/pskc/crypto/tripledeskw.py index 0802141..9494026 100644 --- a/pskc/crypto/tripledeskw.py +++ b/pskc/crypto/tripledeskw.py @@ -1,7 +1,7 @@ # tripledeskw.py - implementation of Triple DES key wrapping # coding: utf-8 # -# Copyright (C) 2014-2015 Arthur de Jong +# Copyright (C) 2014-2017 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -21,8 +21,8 @@ """Implement Triple DES key wrapping as described in RFC 3217.""" import binascii +import os -from Crypto import Random from Crypto.Cipher import DES3 from Crypto.Hash import SHA @@ -47,7 +47,7 @@ def wrap(plaintext, key, iv=None): if len(plaintext) % DES3.block_size != 0: raise EncryptionError('Plaintext length wrong') if iv is None: - iv = Random.get_random_bytes(8) + iv = os.urandom(8) cipher = DES3.new(key, DES3.MODE_CBC, iv) tmp = iv + cipher.encrypt(plaintext + _cms_hash(plaintext)) cipher = DES3.new(key, DES3.MODE_CBC, RFC3217_IV) diff --git a/pskc/encryption.py b/pskc/encryption.py index 0da9f82..5ae31db 100644 --- a/pskc/encryption.py +++ b/pskc/encryption.py @@ -27,6 +27,9 @@ The encryption key can be derived using the KeyDerivation class. """ +import os + + def algorithm_key_lengths(algorithm): """Return the possible key lengths for the configured algorithm.""" from pskc.exceptions import DecryptionError @@ -38,8 +41,7 @@ def algorithm_key_lengths(algorithm): return [int(algorithm[-7:-4]) // 8] elif algorithm.endswith('#tripledes-cbc') or \ algorithm.endswith('#kw-tripledes'): - from Crypto.Cipher import DES3 - return list(DES3.key_size) + return [16, 24] elif algorithm.endswith('#kw-aes128') or \ algorithm.endswith('#kw-aes192') or \ algorithm.endswith('#kw-aes256'): @@ -98,17 +100,15 @@ def encrypt(algorithm, key, plaintext, iv=None): if algorithm.endswith('#aes128-cbc') or \ algorithm.endswith('#aes192-cbc') or \ algorithm.endswith('#aes256-cbc'): - from Crypto import Random from Crypto.Cipher import AES from pskc.crypto import pad - iv = iv or Random.get_random_bytes(AES.block_size) + iv = iv or os.urandom(AES.block_size) cipher = AES.new(key, AES.MODE_CBC, iv) return iv + cipher.encrypt(pad(plaintext, AES.block_size)) elif algorithm.endswith('#tripledes-cbc'): - from Crypto import Random from Crypto.Cipher import DES3 from pskc.crypto import pad - iv = iv or Random.get_random_bytes(DES3.block_size) + iv = iv or os.urandom(DES3.block_size) cipher = DES3.new(key, DES3.MODE_CBC, iv) return iv + cipher.encrypt(pad(plaintext, DES3.block_size)) elif algorithm.endswith('#kw-aes128') or \ @@ -195,10 +195,9 @@ class KeyDerivation(object): def setup_pbkdf2(self, password, salt=None, salt_length=16, key_length=None, iterations=None, prf=None): - from Crypto import Random self.algorithm = 'pbkdf2' if salt is None: - salt = Random.get_random_bytes(salt_length) + salt = os.urandom(salt_length) self.pbkdf2_salt = salt if iterations: self.pbkdf2_iterations = iterations @@ -298,9 +297,8 @@ class Encryption(object): self._setup_encryption(kwargs) self.key = kwargs.pop('key', self.key) if not self.key: - from Crypto import Random - self.key = Random.get_random_bytes(kwargs.pop( - 'key_length', self.algorithm_key_lengths[-1])) + self.key = os.urandom( + kwargs.pop('key_length', self.algorithm_key_lengths[-1])) def setup_pbkdf2(self, password, **kwargs): """Configure password-based PSKC encryption when writing the file. diff --git a/pskc/mac.py b/pskc/mac.py index 5ac1a92..5f258d0 100644 --- a/pskc/mac.py +++ b/pskc/mac.py @@ -29,6 +29,7 @@ with the PSKC encryption key. """ +import os import re @@ -145,5 +146,4 @@ class MAC(object): self.algorithm = 'hmac-sha1' # generate an HMAC key if not self.key: - from Crypto import Random - self.key = Random.get_random_bytes(self.algorithm_key_length) + self.key = os.urandom(self.algorithm_key_length) diff --git a/tests/test_aeskw.doctest b/tests/test_aeskw.doctest index c6ca659..a238a7f 100644 --- a/tests/test_aeskw.doctest +++ b/tests/test_aeskw.doctest @@ -1,6 +1,6 @@ test_keywrap.doctest - test keywrap functions -Copyright (C) 2014-2016 Arthur de Jong +Copyright (C) 2014-2017 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ->>> from Crypto.Util.number import long_to_bytes +>>> import struct >>> from binascii import a2b_hex >>> from pskc.crypto.aeskw import wrap, unwrap @@ -210,7 +210,7 @@ works because we have padded the plaintext with two 0 bytes. >>> key = a2b_hex('5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8') >>> plaintext = a2b_hex('c37b7e6492584340bed1220765460000') ->>> iv = a2b_hex('a65959a6') + long_to_bytes(14, 4) +>>> iv = a2b_hex('a65959a6') + struct.pack('>I', 14) >>> ciphertext = wrap(plaintext, key, iv=iv) >>> unwrap(ciphertext, key, iv=iv) == plaintext True @@ -221,7 +221,7 @@ True If we mangle the IV to look like an RFC 5649 value but with an invalid padding length we should get an exception. ->>> iv = a2b_hex('a65959a6') + long_to_bytes(12, 4) +>>> iv = a2b_hex('a65959a6') + struct.pack('>I', 12) >>> ciphertext = wrap(plaintext, key, iv=iv) >>> unwrap(ciphertext, key, iv=iv) == plaintext True diff --git a/tests/test_write.doctest b/tests/test_write.doctest index 890c99b..8e847f3 100644 --- a/tests/test_write.doctest +++ b/tests/test_write.doctest @@ -21,9 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA >>> from pskc import PSKC >>> import datetime +>>> import os >>> import sys >>> import tempfile ->>> from Crypto import Random >>> from binascii import a2b_hex >>> from dateutil.tz import tzutc @@ -412,7 +412,7 @@ decryption combinations. >>> def test_algorithm(algorithm): ... f = tempfile.NamedTemporaryFile() ... pskc1 = PSKC() -... pskc1.add_key(secret=Random.get_random_bytes(16)) +... pskc1.add_key(secret=os.urandom(16)) ... pskc1.encryption.setup_preshared_key(algorithm=algorithm) ... pskc1.write(f.name) ... pskc2 = PSKC(f.name) |