def encrypt()

in Python/Encrypt credentials/Encryption sample/helper/authenticatedencryption.py [0:0]


    def encrypt(self, key_enc, key_mac, message):
        ''' Encrypts the message with AES, CBC padding and PKCS7

        Args:
            key_enc (bytes): Encryption Key
            key_mac (bytes): MAC Key
            message (bytes): message to get encrypted

        Returns:
            String: Encrypted credentials
        '''

        if len(key_enc) < 32:
            raise ValueError(
                'Encryption Key must be at least 256 bits (32 bytes)')

        if len(key_mac) < 32:
            raise ValueError('Mac Key must be at least 256 bits (32 bytes)')

        if not message:
            raise TypeError('Credentials cannot be null')

        # Initialization vector
        iv = os.urandom(16)

        # PKC7 Padding
        padder = padding.PKCS7(algorithms.AES.block_size).padder()

        # Apply padding to the test data
        padded_data = padder.update(message) + padder.finalize()

        # Cipher object with CBC mode
        cipher = Cipher(algorithms.AES(key_enc), modes.CBC(iv),
                        backend=default_backend())
        encryptor = cipher.encryptor()

        # Cipher text
        cipher_text = encryptor.update(padded_data) + encryptor.finalize()

        # The IV and ciphertest both need to be included in the MAC to prevent
        # tampering.

        # By including the algorithm identifiers, we have technically moved from
        # simple Authenticated Encryption (AE) to Authenticated Encryption with
        # Additional Data (AEAD). By including the algorithm identifiers in the
        # MAC, it becomes harder for an attacker to change them as an attempt to
        # perform a downgrade attack.

        # Prepare the data on which MAC will be executed
        tag_data = bytearray(
            [0] * (len(self.algorithm_choices) + len(iv) + len(cipher_text)))
        tag_data_offset = 0

        # Copy algorithm choices array in tag_data
        tag_data[0:len(self.algorithm_choices)
                 ] = self.algorithm_choices[0:len(self.algorithm_choices)]
        tag_data_offset = len(self.algorithm_choices) + tag_data_offset

        # Copy initialization vector in tag_data
        tag_data[tag_data_offset:len(iv) + tag_data_offset] = iv[0:len(iv)]
        tag_data_offset = len(iv) + tag_data_offset

        # Copy cipher text vector in tag_data
        tag_data[tag_data_offset:len(
            cipher_text) + tag_data_offset] = cipher_text[0:len(cipher_text)]
        tag_data_offset = len(cipher_text) + tag_data_offset

        # Pass random generated key and hash algorithm to calculate authentication code
        hmac_instance = hmac.HMAC(
            key_mac, hashes.SHA256(), backend=default_backend())

        # Pass the bytes to hash and authenticate
        hmac_instance.update(tag_data)

        # Finalize the current context and return the message digest as bytes
        mac = hmac_instance.finalize()

        # Build the final result as the concatenation of everything except the keys
        output = bytearray(
            [0] * (len(self.algorithm_choices) + len(mac) + len(iv) + len(cipher_text)))
        output_offset = 0

        output[0: len(self.algorithm_choices)] = self.algorithm_choices[0:len(self.algorithm_choices)]
        output_offset = len(self.algorithm_choices) + output_offset

        output[output_offset:len(mac) + output_offset] = mac[0:len(mac)]
        output_offset = len(mac) + output_offset

        output[output_offset:len(iv) + output_offset] = iv[0:len(iv)]
        output_offset = len(iv) + output_offset

        output[output_offset:len(cipher_text) + output_offset] = cipher_text[0:len(cipher_text)]
        output_offset = len(cipher_text) + output_offset

        return output