components/python/keystoneclient/patches/nopycrypto.patch
changeset 6825 a251fb776d3d
parent 6824 75d8f5b88459
child 6826 5b442f6fdcfd
equal deleted inserted replaced
6824:75d8f5b88459 6825:a251fb776d3d
     1 In-house removal of PyCrypto dependency in keystoneclient. This patch
       
     2 is Solaris-specific and not suitable for upstream.
       
     3 
       
     4 --- python-keystoneclient-1.3.0/keystoneclient/middleware/memcache_crypt.py.~1~	2015-03-25 14:00:24.000000000 -0600
       
     5 +++ python-keystoneclient-1.3.0/keystoneclient/middleware/memcache_crypt.py	2015-04-27 17:29:37.082689412 -0600
       
     6 @@ -17,7 +17,7 @@
       
     7  Utilities for memcache encryption and integrity check.
       
     8  
       
     9  Data should be serialized before entering these functions. Encryption
       
    10 -has a dependency on the pycrypto. If pycrypto is not available,
       
    11 +has a dependency on M2Crypto. If M2Crypto is not available,
       
    12  CryptoUnavailableError will be raised.
       
    13  
       
    14  This module will not be called unless signing or encryption is enabled
       
    15 @@ -37,9 +37,10 @@ import sys
       
    16  
       
    17  import six
       
    18  
       
    19 -# make sure pycrypto is available
       
    20 +# make sure M2Crypto is available
       
    21  try:
       
    22 -    from Crypto.Cipher import AES
       
    23 +    from M2Crypto.EVP import Cipher
       
    24 +    AES = Cipher
       
    25  except ImportError:
       
    26      AES = None
       
    27  
       
    28 @@ -72,6 +73,12 @@ class CryptoUnavailableError(Exception):
       
    29      pass
       
    30  
       
    31  
       
    32 +class InvalidKeyLength(Exception):
       
    33 +    """raise when AES key length is an invalid value.
       
    34 +
       
    35 +    """
       
    36 +    pass
       
    37 +
       
    38  def assert_crypto_availability(f):
       
    39      """Ensure Crypto module is available."""
       
    40  
       
    41 @@ -131,31 +138,44 @@ def sign_data(key, data):
       
    42      return base64.b64encode(mac)
       
    43  
       
    44  
       
    45 +def _key_to_alg(key):
       
    46 +    """Return a M2Crypto-compatible AES-CBC algorithm name given a key."""
       
    47 +    aes_algs = {
       
    48 +        128: 'aes_128_cbc',
       
    49 +        192: 'aes_192_cbc',
       
    50 +        256: 'aes_256_cbc'
       
    51 +    }
       
    52 +
       
    53 +    keylen = 8 * len(key)
       
    54 +    if keylen not in aes_algs:
       
    55 +        msg = ('Invalid AES key length, %d bits') % keylen
       
    56 +        raise InvalidKeyLength(msg)
       
    57 +    return aes_algs[keylen]
       
    58 +
       
    59 +
       
    60  @assert_crypto_availability
       
    61  def encrypt_data(key, data):
       
    62      """Encrypt the data with the given secret key.
       
    63  
       
    64 -    Padding is n bytes of the value n, where 1 <= n <= blocksize.
       
    65      """
       
    66      iv = os.urandom(16)
       
    67 -    cipher = AES.new(key, AES.MODE_CBC, iv)
       
    68 -    padding = 16 - len(data) % 16
       
    69 -    return iv + cipher.encrypt(data + six.int2byte(padding) * padding)
       
    70 +    cipher = Cipher(alg=_key_to_alg(key), key=key, iv=iv, op=1)
       
    71 +    result = cipher.update(data)
       
    72 +    return iv + result + cipher.final()
       
    73  
       
    74  
       
    75  @assert_crypto_availability
       
    76  def decrypt_data(key, data):
       
    77      """Decrypt the data with the given secret key."""
       
    78      iv = data[:16]
       
    79 -    cipher = AES.new(key, AES.MODE_CBC, iv)
       
    80 +    cipher = Cipher(alg=_key_to_alg(key), key=key, iv=iv, op=0)
       
    81      try:
       
    82 -        result = cipher.decrypt(data[16:])
       
    83 +        result = cipher.update(data[16:])
       
    84 +        result = result + cipher.final()
       
    85      except Exception:
       
    86          raise DecryptError('Encrypted data appears to be corrupted.')
       
    87  
       
    88 -    # Strip the last n padding bytes where n is the last value in
       
    89 -    # the plaintext
       
    90 -    return result[:-1 * six.byte2int([result[-1]])]
       
    91 +    return result
       
    92  
       
    93  
       
    94  def protect_data(keys, data):