Source code for malduck.crypto.aes

# Copyright (C) 2018 Jurriaan Bremer.
# This file is part of Roach - https://github.com/jbremer/roach.
# See the file 'docs/LICENSE.txt' for copying permission.

import io
import warnings

from Cryptodome.Cipher import AES as AESCipher

from .winhdr import BLOBHEADER, BaseBlob
from ..string.bin import uint32

__all__ = ["PlaintextKeyBlob", "AES", "aes"]


[docs]class PlaintextKeyBlob(BaseBlob): r""" `BLOB` object (`PLAINTEXTKEYBLOB`) for `CALG_AES` .. seealso:: :class:`malduck.crypto.BLOBHEADER` """ types = { 16: "AES-128", 24: "AES-192", 32: "AES-256", } def __init__(self): BaseBlob.__init__(self) self.key = None
[docs] def parse(self, buf): """ Parse structure from buffer :param buf: Buffer with structure data :type buf: :class:`io.BytesIO` """ length = uint32(buf.read(4)) value = buf.read() if length != len(value): return self.key = value
[docs] def export_key(self): """ Exports key from structure :return: Tuple (`algorithm`, `key`). `Algorithm` is one of: "AES-128", "AES-192", "AES-256" :rtype: Tuple[str, bytes] """ return self.types[len(self.key)], self.key
BlobTypes = { 8: PlaintextKeyBlob, } class AesCbc(object): def encrypt(self, key, iv, data): """ Encrypts buffer using AES algorithm in CBC mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param iv: Initialization vector :type iv: bytes :param data: Buffer to be encrypted :type data: bytes :return: Encrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_CBC, iv=iv) return cipher.encrypt(data) def decrypt(self, key, iv, data): """ Decrypts buffer using AES algorithm in CBC mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param iv: Initialization vector :type iv: bytes :param data: Buffer to be decrypted :type data: bytes :return: Decrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_CBC, iv=iv) return cipher.decrypt(data) def __call__(self, key, iv, data): warnings.warn( "malduck.aes.cbc() is deprecated, please use malduck.aes.cbc.decrypt()", DeprecationWarning, ) return self.decrypt(key, iv, data) class AesEcb(object): def encrypt(self, key, data): """ Encrypts buffer using AES algorithm in ECB mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param data: Buffer to be encrypted :type data: bytes :return: Encrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_ECB) return cipher.encrypt(data) def decrypt(self, key, data): """ Decrypts buffer using AES algorithm in ECB mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param data: Buffer to be decrypted :type data: bytes :return: Decrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_ECB) return cipher.decrypt(data) def __call__(self, key, iv, data): warnings.warn( "malduck.aes.ecb() is deprecated, please use malduck.aes.ecb.decrypt()", DeprecationWarning, ) return self.decrypt(key, data) class AesCtr(object): def encrypt(self, key, nonce, data): """ Encrypts buffer using AES algorithm in CTR mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param nonce: Initial counter value, big-endian encoded :type nonce: bytes :param data: Buffer to be encrypted :type data: bytes :return: Encrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_CTR, nonce=b"", initial_value=nonce) return cipher.encrypt(data) def decrypt(self, key, nonce, data): """ Decrypts buffer using AES algorithm in CTR mode. :param key: Cryptographic key (128, 192 or 256 bits) :type key: bytes :param nonce: Initial counter value, big-endian encoded :type nonce: bytes :param data: Buffer to be decrypted :type data: bytes :return: Decrypted data :rtype: bytes """ cipher = AESCipher.new(key, AESCipher.MODE_CTR, nonce=b"", initial_value=nonce) return cipher.decrypt(data) def __call__(self, key, nonce, data): warnings.warn( "malduck.aes.ctr() is deprecated, please use malduck.aes.ctr.decrypt()", DeprecationWarning, ) return self.decrypt(key, nonce, data) class Aes(object): cbc = AesCbc() ecb = AesEcb() ctr = AesCtr() def encrypt(self, key, iv, data): warnings.warn( "malduck.aes.encrypt is deprecated, please use malduck.aes.cbc.encrypt", DeprecationWarning, ) return self.cbc.encrypt(key, iv, data) def decrypt(self, key, iv, data): warnings.warn( "malduck.aes.decrypt is deprecated, please use malduck.aes.cbc.decrypt", DeprecationWarning, ) return self.cbc.decrypt(key, iv, data) def __call__(self, mode): warnings.warn( "malduck.aes('<mode>') is deprecated, please use malduck.aes.<mode>", DeprecationWarning, ) return getattr(self, mode) @staticmethod def import_key(data): """ Extracts key from buffer containing :class:`PlaintextKeyBlob` data :param data: Buffer with `BLOB` structure data :type data: bytes :return: Tuple (`algorithm`, `key`). `Algorithm` is one of: "AES-128", "AES-192", "AES-256" """ if len(data) < BLOBHEADER.sizeof(): return buf = io.BytesIO(data) header = BLOBHEADER.parse(buf.read(BLOBHEADER.sizeof())) algorithms = ( 0x0000660E, # AES 128 0x0000660F, # AES 192 0x00006610, # AES 256 ) if header.bType not in BlobTypes: return if header.aiKeyAlg not in algorithms: return obj = BlobTypes[header.bType]() obj.parse(buf) return obj.export_key() class AES(object): r""" AES encryption/decryption object Deprecated, use `malduck.aes` :param key: Encryption key :type key: bytes :param iv: Initialization vector (IV for CBC mode, nonce for CTR) :type iv: bytes, optional :param mode: Block cipher mode (default: "cbc") :type mode: str ("cbc", "ecb", "ctr") """ algorithms = ( 0x0000660E, # AES 128 0x0000660F, # AES 192 0x00006610, # AES 256 ) modes = { "cbc": Aes.cbc, "ecb": Aes.ecb, "ctr": Aes.ctr, } def __init__(self, key, iv=None, mode="cbc"): warnings.warn( "malduck.crypto.AES is deprecated, please use malduck.aes.<mode> variants", DeprecationWarning, ) self.key = key self.iv = iv self.mode = mode self.aes = self.modes[mode] def encrypt(self, data): """ Encrypt provided data :param data: Buffer with data :type data: bytes :return: Encrypted data """ if self.mode == "ecb": return self.aes.encrypt(self.key, data) else: return self.aes.encrypt(self.key, self.iv, data) def decrypt(self, data): """ Decrypt provided data :param data: Buffer with encrypted data :type data: bytes :return: Decrypted data """ if self.mode == "ecb": return self.aes.decrypt(self.key, data) else: return self.aes.decrypt(self.key, self.iv, data) @staticmethod def import_key(data): """ Extracts key from buffer containing :class:`PlaintextKeyBlob` data :param data: Buffer with `BLOB` structure data :type data: bytes :return: Tuple (`algorithm`, `key`). `Algorithm` is one of: "AES-128", "AES-192", "AES-256" """ return Aes.import_key(data) aes = Aes()