Source code for covata.delta.crypto

#   Copyright 2017 Covata Limited or its affiliates
#
#   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
import os
from binascii import hexlify

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

__all__ = ["generate_private_key", "serialize_public_key",
           "calculate_sha256hex", "generate_secret_key",
           "generate_initialisation_vector", "encrypt", "decrypt",
           "encrypt_key_with_public_key", "decrypt_with_private_key",
           "deserialize_public_key"]


[docs]def generate_private_key(): """ Generates a :class:`~rsa.RSAPrivateKey` object. The public key object can be extracted by calling public_key() method on the generated key object. :return: the generated private key object :rtype: :class:`~rsa.RSAPrivateKey` """ return rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend())
[docs]def serialize_public_key(public_key): """ Serializes the provided public key object as base-64-encoded DER format using X.509 SubjectPublicKeyInfo with PKCS1. :param public_key: the public key object :type public_key: :class:`~rsa.RSAPublicKey` :return: the key as base64 encoded unicode string :rtype: str """ der = public_key.public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo) return base64.b64encode(der).decode(encoding='utf-8')
[docs]def deserialize_public_key(b64_encoded_public_key): """ loads a :class:`~rsa.RSAPublicKey` object from a serialized public key. :param str b64_encoded_public_key: the key as base64 encoded string :return: the public key object :rtype: :class:`~rsa.RSAPublicKey` """ return serialization.load_der_public_key( data=base64.b64decode(b64_encoded_public_key.encode('utf-8')), backend=default_backend())
[docs]def calculate_sha256hex(payload): """ Calculates the SHA256 hex digest of the given payload. :param str payload: the payload to be calculated :return: SHA256 hex digest :rtype: bytes """ digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) digest.update(payload if payload is bytes else payload.encode('utf-8')) x = digest.finalize() # type: bytes return hexlify(x)
[docs]def generate_initialisation_vector(): """ Generates a 128 bits initialisation vector. Uses ``/dev/urandom`` on UNIX platforms, and ``CryptGenRandom`` on Windows. :return: the 128 bits initialisation vector :rtype: bytes """ return os.urandom(16)
[docs]def generate_secret_key(): """ Generates a 256 bits secret key. Uses ``/dev/urandom`` on UNIX platforms, and ``CryptGenRandom`` on Windows. :return: the 256 bits secret key :rtype: bytes """ return os.urandom(32)
[docs]def encrypt(data, secret_key, initialisation_vector): """ Encrypts data using the given secret key and initialisation vector. :param bytes data: the plaintext bytes to be encrypted :param bytes secret_key: the key to be used for encryption :param bytes initialisation_vector: the initialisation vector :return: the cipher text and GCM authentication tag tuple :rtype: (bytes, bytes) """ cipher = Cipher(algorithm=algorithms.AES(secret_key), mode=modes.GCM(initialization_vector=initialisation_vector, min_tag_length=16), backend=default_backend()) encryptor = cipher.encryptor() ciphertext = encryptor.update(data) + encryptor.finalize() return ciphertext, encryptor.tag
[docs]def decrypt(ciphertext, tag, secret_key, initialisation_vector): """ Decrypts a cipher text using the given GCM authentication tag, secret key and initialisation vector. :param bytes ciphertext: the cipher text to be decrypted :param bytes tag: the GCM authentication tag :param bytes secret_key: the key to be used for encryption :param bytes initialisation_vector: the initialisation vector :return: the decrypted plaintext :rtype: bytes """ cipher = Cipher(algorithm=algorithms.AES(secret_key), mode=modes.GCM(initialization_vector=initialisation_vector, tag=tag), backend=default_backend()) decryptor = cipher.decryptor() return decryptor.update(ciphertext) + decryptor.finalize()
[docs]def encrypt_key_with_public_key(secret_key, public_encryption_key): """ Encrypts the given secret key with the public key. :param bytes secret_key: the key to encrypt :param public_encryption_key: the public encryption key :type public_encryption_key: :class:`~rsa.RSAPublicKey` :return: the encrypted key :rtype: bytes """ return public_encryption_key.encrypt( secret_key, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None))
[docs]def decrypt_with_private_key(secret_key, private_encryption_key): """ Decrypts the given secret key with the private key. :param bytes secret_key: the secret key to decrypt :param private_encryption_key: the private encryption key :type private_encryption_key: :class:`~rsa.RSAPrivateKey` :return: the decrypted key :rtype: bytes """ return private_encryption_key.decrypt( secret_key, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None))