components/python/keystoneclient/patches/nopycrypto.patch
changeset 3998 5bd484384122
child 5405 66fd59fecd68
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/python/keystoneclient/patches/nopycrypto.patch	Thu Mar 19 14:41:20 2015 -0700
@@ -0,0 +1,95 @@
+In-house removal of PyCrypto dependency in keystoneclient. This patch
+is Solaris-specific and not suitable for upstream.
+
+--- python-keystoneclient-1.0.0/keystoneclient/middleware/memcache_crypt.py.~1~	2014-12-18 09:37:35.000000000 -0800
++++ python-keystoneclient-1.0.0/keystoneclient/middleware/memcache_crypt.py	2015-01-31 23:38:16.649757111 -0800
+@@ -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
+@@ -37,9 +37,10 @@ import sys
+ 
+ import six
+ 
+-# 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
+ 
+@@ -72,6 +73,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."""
+ 
+@@ -131,31 +139,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):