mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Use PBKDF2HMAC() from cryptography for vault keys.
When stretching the key for vault files, use PBKDF2HMAC() from the cryptography package instead of pycrypto. This will speed up the opening of vault files by ~10x. The problem is here in lib/ansible/utils/vault.py: hash_function = SHA256 # make two keys and one iv pbkdf2_prf = lambda p, s: HMAC.new(p, s, hash_function).digest() derivedkey = PBKDF2(password, salt, dkLen=(2 * keylength) + ivlength, count=10000, prf=pbkdf2_prf) `PBKDF2()` calls a Python callback function (`pbkdf2_pr()`) 10000 times. If one has several vault files, this will cause excessive start times with `ansible` or `ansible-playbook` (we experience ~15 second startup times). Testing the original implementation in 1.9.2 with a vault file: In [2]: %timeit v.decrypt(encrypted_data) 1 loops, best of 3: 265 ms per loop Having a recent OpenSSL version and using the vault.py changes in this commit: In [2]: %timeit v.decrypt(encrypted_data) 10 loops, best of 3: 23.2 ms per loop
This commit is contained in:
parent
e505a1b7c4
commit
58cccce384
1 changed files with 34 additions and 8 deletions
|
@ -81,6 +81,18 @@ try:
|
|||
except ImportError:
|
||||
HAS_AES = False
|
||||
|
||||
# OpenSSL pbkdf2_hmac
|
||||
HAS_PBKDF2HMAC = False
|
||||
try:
|
||||
from cryptography.hazmat.primitives.hashes import SHA256 as c_SHA256
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
HAS_PBKDF2HMAC = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
HAS_ANY_PBKDF2HMAC = HAS_PBKDF2 or HAS_PBKDF2HMAC
|
||||
|
||||
CRYPTO_UPGRADE = "ansible-vault requires a newer version of pycrypto than the one installed on your platform. You may fix this with OS-specific commands such as: yum install python-devel; rpm -e --nodeps python-crypto; pip install pycrypto"
|
||||
|
||||
HEADER=u'$ANSIBLE_VAULT'
|
||||
|
@ -89,7 +101,7 @@ CIPHER_WHITELIST=['AES', 'AES256']
|
|||
|
||||
def check_prereqs():
|
||||
|
||||
if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2 or not HAS_HASH:
|
||||
if not HAS_AES or not HAS_COUNTER or not HAS_ANY_PBKDF2HMAC or not HAS_HASH:
|
||||
raise AnsibleError(CRYPTO_UPGRADE)
|
||||
|
||||
class VaultLib(object):
|
||||
|
@ -551,13 +563,7 @@ class VaultAES256(object):
|
|||
|
||||
check_prereqs()
|
||||
|
||||
def gen_key_initctr(self, password, salt):
|
||||
# 16 for AES 128, 32 for AES256
|
||||
keylength = 32
|
||||
|
||||
# match the size used for counter.new to avoid extra work
|
||||
ivlength = 16
|
||||
|
||||
def create_key(self, password, salt, keylength, ivlength):
|
||||
hash_function = SHA256
|
||||
|
||||
# make two keys and one iv
|
||||
|
@ -566,6 +572,26 @@ class VaultAES256(object):
|
|||
|
||||
derivedkey = PBKDF2(password, salt, dkLen=(2 * keylength) + ivlength,
|
||||
count=10000, prf=pbkdf2_prf)
|
||||
return derivedkey
|
||||
|
||||
def gen_key_initctr(self, password, salt):
|
||||
# 16 for AES 128, 32 for AES256
|
||||
keylength = 32
|
||||
|
||||
# match the size used for counter.new to avoid extra work
|
||||
ivlength = 16
|
||||
|
||||
if HAS_PBKDF2HMAC:
|
||||
backend = default_backend()
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=c_SHA256(),
|
||||
length=2 * keylength + ivlength,
|
||||
salt=salt,
|
||||
iterations=10000,
|
||||
backend=backend)
|
||||
derivedkey = kdf.derive(password)
|
||||
else:
|
||||
derivedkey = self.create_key(password, salt, keylength, ivlength)
|
||||
|
||||
key1 = derivedkey[:keylength]
|
||||
key2 = derivedkey[keylength:(keylength * 2)]
|
||||
|
|
Loading…
Reference in a new issue