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
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/LICENSE2.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 24byte 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 32byte 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 24byte 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))


