A configuration organization tool.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

138 lines
4.8 KiB

# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
from functools import lru_cache
import logging
from cryptography import fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
KEY_LENGTH = 32
ITERATIONS = 10000
LOG = logging.getLogger(__name__)
__all__ = ('encrypt', 'decrypt')
def encrypt(
unencrypted_data,
passphrase,
salt,
key_length=KEY_LENGTH,
iterations=ITERATIONS):
"""
Encrypt the data, using the provided passphrase and salt,
and return the encrypted data.
:param unencrypted_data: Secret data to encrypt
:type unencrypted_data: bytes
:param passphrase: Passphrase to use to generate encryption key. Must be
at least 24-byte long
:type passphrase: bytes
:param salt: salt to use to generate encryption key. Must be randomly
generated.
:type salt: bytes
:param key_length: Length of the encryption key to generate, in bytes.
Will default to 32, if not provided.
:type key_length: positive integer.
:param iterations: A large number, used as seed to increase the entropy
in randomness of the generated key for encryption, and hence greatly
increase the security of encrypted data. will default to 10000, if not
provided.
:type iterations: positive integer.
:return: Encrypted secret data
:rtype: bytes
"""
return fernet.Fernet(
_generate_key(passphrase, salt, key_length,
iterations)).encrypt(unencrypted_data)
def decrypt(
encrypted_data,
passphrase,
salt,
key_length=KEY_LENGTH,
iterations=ITERATIONS):
"""
Decrypt the data, using the provided passphrase and salt,
and return the decrypted data.
:param encrypted_data: Encrypted secret data
:type encrypted_data: bytes
:param passphrase: Passphrase to use to generate decryption key. Must be
at least 32-byte long.
:type passphrase: bytes
:param salt: salt to use to generate decryption key. Must be randomly
generated.
:type salt: bytes
:param key_length: Length of the decryption key to generate, in bytes.
will default to 32, if not provided.
:type key_length: positive integer.
:param iterations: A large number, used as seed to increase entropy in
the randomness of the generated key for decryption, and hence greatly
increase the security of encrypted data. Will default to 10000, if not
provided.
:type iterations: positive integer.
:return: Decrypted secret data
:rtype: bytes
:raises InvalidToken: If the provided passphrase, and/or
salt does not match the values used to encrypt the data.
"""
try:
return fernet.Fernet(
_generate_key(passphrase, salt, key_length,
iterations)).decrypt(encrypted_data)
except fernet.InvalidToken:
LOG.error(
'Signature verification to decrypt secrets failed. Please '
'check your provided passphrase and salt and try again.')
raise
@lru_cache(maxsize=None)
def _generate_key(passphrase, salt, key_length, iterations):
"""
Use the passphrase and salt and PBKDF2HMAC key derivation algorithm,
to generate and return a Fernet key to be used for encryption and
decryption of secret data.
:param passphrase: Passphrase to use to generate decryption key. Must be
at least 24-byte long.
:type passphrase: bytes
:param salt: salt to use to generate decryption key. Must be randomly
generated.
:type salt: bytes
:param key_length: Length of the decryption key to generate, in bytes.
Will default to 32, if not provided.
:type key_length: positive integer.
:param iterations: A large number, used as seed to increase the entropy
of the randomness of the generated key. will default to 10000, if not
provided.
:type iterations: positive integer.
:return: base64 encoded, URL safe Fernet key for encryption or decryption
"""
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=key_length,
salt=salt,
iterations=iterations,
backend=default_backend())
return base64.urlsafe_b64encode(kdf.derive(passphrase))