| 1 | from warnings import warn |
|---|
| 2 | |
|---|
| 3 | from beaker.crypto.pbkdf2 import PBKDF2, strxor |
|---|
| 4 | from beaker.exceptions import InvalidCryptoBackendError |
|---|
| 5 | |
|---|
| 6 | _implementations = ('pycrypto', 'jcecrypto') |
|---|
| 7 | |
|---|
| 8 | keyLength = None |
|---|
| 9 | for impl_name in _implementations: |
|---|
| 10 | try: |
|---|
| 11 | package = 'beaker.crypto.%s' % impl_name |
|---|
| 12 | module = __import__(package, fromlist=('aesEncrypt', 'getKeyLength')) |
|---|
| 13 | keyLength = module.getKeyLength() |
|---|
| 14 | aesEncrypt = module.aesEncrypt |
|---|
| 15 | if keyLength >= 32: |
|---|
| 16 | break |
|---|
| 17 | except: |
|---|
| 18 | pass |
|---|
| 19 | |
|---|
| 20 | if not keyLength: |
|---|
| 21 | raise InvalidCryptoBackendError |
|---|
| 22 | |
|---|
| 23 | if keyLength < 32: |
|---|
| 24 | warn('Crypto implementation only supports key lengths up to %d bits. ' |
|---|
| 25 | 'Generated session cookies may be incompatible with other ' |
|---|
| 26 | 'environments' % (keyLength * 8)) |
|---|
| 27 | |
|---|
| 28 | def generateCryptoKeys(master_key, salt, iterations): |
|---|
| 29 | # NB: We XOR parts of the keystream into the randomly-generated parts, just |
|---|
| 30 | # in case os.urandom() isn't as random as it should be. Note that if |
|---|
| 31 | # os.urandom() returns truly random data, this will have no effect on the |
|---|
| 32 | # overall security. |
|---|
| 33 | keystream = PBKDF2(master_key, salt, iterations=iterations) |
|---|
| 34 | cipher_key = keystream.read(keyLength) |
|---|
| 35 | return cipher_key |
|---|