diff --git a/docs/crypto.rst b/docs/crypto.rst index f117e14..4194006 100644 --- a/docs/crypto.rst +++ b/docs/crypto.rst @@ -56,6 +56,48 @@ Supported modes: ECB. .. autofunction:: malduck.blowfish.ecb.encrypt .. autofunction:: malduck.blowfish.ecb.decrypt +Camellia +-------------- + +Camellia block cipher. + +Supported modes: ECB, CBC, CTR, CFB, OFB. + +.. code-block:: python + + from malduck import camellia + + key = b'A'*16 + iv = b'B'*16 + plaintext = b'data'*16 + ciphertext = camellia.ecb.encrypt(key, iv, plaintext) + + +Camellia-ECB mode +~~~~~~~~~~~~ +.. autofunction:: malduck.camellia.ecb.encrypt +.. autofunction:: malduck.camellia.ecb.decrypt + +Camellia-CBC mode +~~~~~~~~~~~~ +.. autofunction:: malduck.camellia.cbc.encrypt +.. autofunction:: malduck.camellia.cbc.decrypt + +Camellia-CTR mode +~~~~~~~~~~~~ +.. autofunction:: malduck.camellia.ctr.encrypt +.. autofunction:: malduck.camellia.ctr.decrypt + +Camellia-CFB mode +~~~~~~~~~~~~ +.. autofunction:: malduck.camellia.cfb.encrypt +.. autofunction:: malduck.camellia.cfb.decrypt + +Camellia-OFB mode +~~~~~~~~~~~~ +.. autofunction:: malduck.camellia.ofb.encrypt +.. autofunction:: malduck.camellia.ofb.decrypt + ChaCha20 -------- diff --git a/malduck/__init__.py b/malduck/__init__.py index ba6586a..6fdd0ab 100644 --- a/malduck/__init__.py +++ b/malduck/__init__.py @@ -8,6 +8,7 @@ from .crypto import ( aes, + camellia, blowfish, chacha20, des3, @@ -135,6 +136,7 @@ "lznt1", # crypto "aes", + "camellia", "blowfish", "chacha20", "des3", diff --git a/malduck/crypto/__init__.py b/malduck/crypto/__init__.py index b1ab647..3707bf9 100644 --- a/malduck/crypto/__init__.py +++ b/malduck/crypto/__init__.py @@ -1,4 +1,5 @@ from .aes import aes +from .camellia import camellia from .blowfish import blowfish from .chacha20 import chacha20 from .des3 import des3 @@ -11,6 +12,7 @@ __all__ = [ "aes", + "camellia", "blowfish", "chacha20", "des3", diff --git a/malduck/crypto/camellia.py b/malduck/crypto/camellia.py new file mode 100644 index 0000000..78725e9 --- /dev/null +++ b/malduck/crypto/camellia.py @@ -0,0 +1,201 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + + +__all__ = ["camellia"] + + +class CamelliaCbc: + def encrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Encrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CBC(iv)) + enc = cipher.encryptor() + return enc.update(data) + enc.finalize() + + def decrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Decrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CBC(iv)) + dec = cipher.decryptor() + return dec.update(data) + dec.finalize() + + +class CamelliaCfb: + def encrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Encrypts buffer using Camellia algorithm in CFB 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CFB(iv)) + enc = cipher.encryptor() + return enc.update(data) + enc.finalize() + + def decrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Decrypts buffer using Camellia algorithm in CFB 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CFB(iv)) + dec = cipher.decryptor() + return dec.update(data) + dec.finalize() + + +class CamelliaOfb: + def encrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Encrypts buffer using Camellia algorithm in OFB 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.OFB(iv)) + enc = cipher.encryptor() + return enc.update(data) + enc.finalize() + + def decrypt(self, key: bytes, iv: bytes, data: bytes) -> bytes: + """ + Decrypts buffer using Camellia algorithm in OFB 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.OFB(iv)) + dec = cipher.decryptor() + return dec.update(data) + dec.finalize() + + +class CamelliaEcb: + def encrypt(self, key: bytes, data: bytes) -> bytes: + """ + Encrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.ECB()) + enc = cipher.encryptor() + return enc.update(data) + enc.finalize() + + def decrypt(self, key: bytes, data: bytes) -> bytes: + """ + Decrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.ECB()) + dec = cipher.decryptor() + return dec.update(data) + dec.finalize() + + +class CamelliaCtr: + def encrypt(self, key: bytes, nonce: bytes, data: bytes) -> bytes: + """ + Encrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CTR(nonce)) + enc = cipher.encryptor() + return enc.update(data) + enc.finalize() + + def decrypt(self, key: bytes, nonce: bytes, data: bytes) -> bytes: + """ + Decrypts buffer using Camellia 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 + """ + algo = algorithms.Camellia(key) + cipher = Cipher(algo, modes.CTR(nonce)) + dec = cipher.decryptor() + return dec.update(data) + dec.finalize() + + +class Camellia: + cbc = CamelliaCbc() + ecb = CamelliaEcb() + ctr = CamelliaCtr() + cfb = CamelliaCfb() + ofb = CamelliaOfb() + + +camellia = Camellia() diff --git a/requirements.txt b/requirements.txt index 9f60e8e..2955a6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ pycryptodomex>=3.8.2 capstone>=4.0.1 yara-python typing-extensions>=3.7.4.2 +cryptography>=3.1 diff --git a/tests/test_crypto.py b/tests/test_crypto.py index 45e3306..0cc6c48 100644 --- a/tests/test_crypto.py +++ b/tests/test_crypto.py @@ -2,7 +2,22 @@ # This file is part of Roach - https://github.com/jbremer/roach. # See the file 'docs/LICENSE.txt' for copying permission. -from malduck import aes, blowfish, des3, rc4, rsa, xor, base64, unhex, rabbit, p8, serpent, chacha20, salsa20 +from malduck import ( + aes, + camellia, + blowfish, + des3, + rc4, + rsa, + xor, + base64, + unhex, + rabbit, + p8, + serpent, + chacha20, + salsa20, +) def test_aes(): @@ -45,6 +60,96 @@ def test_aes(): ) == ("AES-128", b"A"*16) +def test_camellia(): + + from binascii import unhexlify + + #### ECB + # test data from https://tools.ietf.org/html/rfc3713 + + k = unhexlify("0123456789ABCDEFFEDCBA9876543210") + p = unhexlify("0123456789ABCDEFFEDCBA9876543210") + c = unhexlify("67673138549669730857065648EABE43") + + assert camellia.ecb.encrypt(k, p) == c + assert camellia.ecb.decrypt(k, c) == p + + k = unhexlify("0123456789ABCDEFFEDCBA98765432100011223344556677") + c = unhexlify("B4993401B3E996F84EE5CEE7D79B09B9") + + assert camellia.ecb.encrypt(k, p) == c + assert camellia.ecb.decrypt(k, c) == p + + k = unhexlify("0123456789ABCDEFFEDCBA987654321000112233445566778899AABBCCDDEEFF") + c = unhexlify("9ACC237DFF16D76C20EF7C919E3A7509") + + assert camellia.ecb.encrypt(k, p) == c + assert camellia.ecb.decrypt(k, c) == p + + #### CBC + # test data from https://github.com/openssl/openssl/blob/master/test/recipes/30-test_evp_data/evpciph_camellia.txt + + k = unhexlify("2B7E151628AED2A6ABF7158809CF4F3C") + iv = unhexlify("000102030405060708090A0B0C0D0E0F") + p = unhexlify("6BC1BEE22E409F96E93D7E117393172A") + c = unhexlify("1607CF494B36BBF00DAEB0B503C831AB") + + assert camellia.cbc.encrypt(k, iv, p) == c + assert camellia.cbc.decrypt(k, iv, c) == p + + k = unhexlify("8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B") + c = unhexlify("2A4830AB5AC4A1A2405955FD2195CF93") + + assert camellia.cbc.decrypt(k, iv, c) == p + assert camellia.cbc.encrypt(k, iv, p) == c + + k = unhexlify("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") + c = unhexlify("E6CFA35FC02B134A4D2C0B6737AC3EDA") + + assert camellia.cbc.encrypt(k, iv, p) == c + assert camellia.cbc.decrypt(k, iv, c) == p + + #### CFB + + k = unhexlify("2B7E151628AED2A6ABF7158809CF4F3C") + c = unhexlify("14F7646187817EB586599146B82BD719") + + assert camellia.cfb.encrypt(k, iv, p) == c + assert camellia.cfb.decrypt(k, iv, c) == p + + k = unhexlify("8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B") + c = unhexlify("C832BB9780677DAA82D9B6860DCD565E") + + assert camellia.cfb.encrypt(k, iv, p) == c + assert camellia.cfb.decrypt(k, iv, c) == p + + k = unhexlify("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") + c = unhexlify("CF6107BB0CEA7D7FB1BD31F5E7B06C93") + + assert camellia.cfb.encrypt(k, iv, p) == c + assert camellia.cfb.decrypt(k, iv, c) == p + + #### OFB + + k = unhexlify("2B7E151628AED2A6ABF7158809CF4F3C") + c = unhexlify("14F7646187817EB586599146B82BD719") + + assert camellia.ofb.encrypt(k, iv, p) == c + assert camellia.ofb.decrypt(k, iv, c) == p + + k = unhexlify("8E73B0F7DA0E6452C810F32B809079E562F8EAD2522C6B7B") + c = unhexlify("C832BB9780677DAA82D9B6860DCD565E") + + assert camellia.ofb.encrypt(k, iv, p) == c + assert camellia.ofb.decrypt(k, iv, c) == p + + k = unhexlify("603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4") + c = unhexlify("CF6107BB0CEA7D7FB1BD31F5E7B06C93") + + assert camellia.ofb.encrypt(k, iv, p) == c + assert camellia.ofb.decrypt(k, iv, c) == p + + def test_blowfish(): assert blowfish.ecb.decrypt( b"blowfish", b"\x91;\x92\xa9\x85\x83\xb36\xbb\xac\xa8r0\xf1$\x19"