Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2017-09-30 18:28:37 +0200
committerArthur de Jong <arthur@arthurdejong.org>2017-10-01 14:07:39 +0200
commit2c8a9b7b1b87a3cc07aac800d77db4652165d3e1 (patch)
tree6993ac83f643cbb4fb76e61d984f2be5e2947492
parentd0eddf88287bce398cb7a55ee20b384e3f764a4d (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.py21
-rw-r--r--pskc/crypto/tripledeskw.py6
-rw-r--r--pskc/encryption.py20
-rw-r--r--pskc/mac.py4
-rw-r--r--tests/test_aeskw.doctest8
-rw-r--r--tests/test_write.doctest4
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)