In-house removal of PyCrypto dependency in keystonemiddleware. This
patch is Solaris-specific and not suitable for upstream.
--- keystonemiddleware-1.5.0/keystonemiddleware/auth_token/_memcache_crypt.py.~1~ 2015-03-11 11:41:14.000000000 -0600
+++ keystonemiddleware-1.5.0/keystonemiddleware/auth_token/_memcache_crypt.py 2015-04-27 17:30:54.664848743 -0600
@@ -17,7 +17,7 @@
Utilities for memcache encryption and integrity check.
Data should be serialized before entering these functions. Encryption
-has a dependency on the pycrypto. If pycrypto is not available,
+has a dependency on M2Crypto. If M2Crypto is not available,
CryptoUnavailableError will be raised.
This module will not be called unless signing or encryption is enabled
@@ -38,9 +38,10 @@ import sys
from keystonemiddleware.i18n import _
-# make sure pycrypto is available
+# make sure M2Crypto is available
try:
- from Crypto.Cipher import AES
+ from M2Crypto.EVP import Cipher
+ AES = Cipher
except ImportError:
AES = None
@@ -73,6 +74,13 @@ class CryptoUnavailableError(Exception):
pass
+class InvalidKeyLength(Exception):
+ """raise when AES key length is an invalid value.
+
+ """
+ pass
+
+
def assert_crypto_availability(f):
"""Ensure Crypto module is available."""
@@ -132,31 +140,44 @@ def sign_data(key, data):
return base64.b64encode(mac)
+def _key_to_alg(key):
+ """Return a M2Crypto-compatible AES-CBC algorithm name given a key."""
+ aes_algs = {
+ 128: 'aes_128_cbc',
+ 192: 'aes_192_cbc',
+ 256: 'aes_256_cbc'
+ }
+
+ keylen = 8 * len(key)
+ if keylen not in aes_algs:
+ msg = ('Invalid AES key length, %d bits') % keylen
+ raise InvalidKeyLength(msg)
+ return aes_algs[keylen]
+
+
@assert_crypto_availability
def encrypt_data(key, data):
"""Encrypt the data with the given secret key.
- Padding is n bytes of the value n, where 1 <= n <= blocksize.
"""
iv = os.urandom(16)
- cipher = AES.new(key, AES.MODE_CBC, iv)
- padding = 16 - len(data) % 16
- return iv + cipher.encrypt(data + six.int2byte(padding) * padding)
+ cipher = Cipher(alg=_key_to_alg(key), key=key, iv=iv, op=1)
+ result = cipher.update(data)
+ return iv + result + cipher.final()
@assert_crypto_availability
def decrypt_data(key, data):
"""Decrypt the data with the given secret key."""
iv = data[:16]
- cipher = AES.new(key, AES.MODE_CBC, iv)
+ cipher = Cipher(alg=_key_to_alg(key), key=key, iv=iv, op=0)
try:
- result = cipher.decrypt(data[16:])
+ result = cipher.update(data[16:])
+ result = result + cipher.final()
except Exception:
raise DecryptError(_('Encrypted data appears to be corrupted.'))
- # Strip the last n padding bytes where n is the last value in
- # the plaintext
- return result[:-1 * six.byte2int([result[-1]])]
+ return result
def protect_data(keys, data):