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): |
|