Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add chacha20 and salsa20 ciphers #46

Merged
merged 5 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions docs/crypto.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,25 @@ Supported modes: ECB.
.. autofunction:: malduck.blowfish.ecb.encrypt
.. autofunction:: malduck.blowfish.ecb.decrypt

ChaCha20
--------

ChaCha20 stream cipher.

Assumes empty nonce if none given.

.. code-block:: python

from malduck import chacha20

key = b'chachaKeyHereNow' * 2
nonce = b'\x01\x02\x03\x04\x05\0x6\0x7'
plaintext = b'data'*16
ciphertext = chacha20.decrypt(key, plaintext, nonce)

.. autofunction:: malduck.chacha20.encrypt
.. autofunction:: malduck.chacha20.decrypt

DES/DES3 (CBC only)
-------------------

Expand All @@ -71,12 +90,32 @@ Supported modes: CBC.

key = b'des3des3'
iv = b'3des3des'
plaintext = b'data'*16
ciphertext = des3.cbc.decrypt(key, plaintext)
plaintext = b'data' * 16
ciphertext = des3.cbc.encrypt(key, plaintext)

.. autofunction:: malduck.des3.cbc.encrypt
.. autofunction:: malduck.des3.cbc.decrypt

Salsa20
--------

Salsa20 stream cipher.

Assumes empty nonce if none given.

.. code-block:: python

from malduck import salsa20

key = b'salsaFTW' * 4
nonce = b'\x01\x02\x03\x04\x05\0x6\0x7'
plaintext = b'data' * 16
ciphertext = salsa20.decrypt(key, plaintext, nonce)

.. autofunction:: malduck.salsa20.encrypt
.. autofunction:: malduck.salsa20.decrypt


Serpent (CBC only)
------------------

Expand Down
15 changes: 14 additions & 1 deletion malduck/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,18 @@

from .compression import aplib, gzip, lznt1

from .crypto import aes, blowfish, des3, rabbit, rc4, rsa, serpent, xor
from .crypto import (
aes,
blowfish,
chacha20,
des3,
rabbit,
rc4,
rsa,
salsa20,
serpent,
xor,
)

from .disasm import disasm, insn

Expand Down Expand Up @@ -125,10 +136,12 @@
# crypto
"aes",
"blowfish",
"chacha20",
"des3",
"rabbit",
"rc4",
"rsa",
"salsa20",
"serpent",
"xor",
# disasm
Expand Down
15 changes: 14 additions & 1 deletion malduck/crypto/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
from .aes import aes
from .blowfish import blowfish
from .chacha20 import chacha20
from .des3 import des3
from .rabbit import rabbit
from .rc import rc4
from .rsa import rsa
from .salsa20 import salsa20
from .serpent import serpent
from .xor import xor

__all__ = ["aes", "blowfish", "des3", "rabbit", "rc4", "rsa", "serpent", "xor"]
__all__ = [
"aes",
"blowfish",
"chacha20",
"des3",
"rabbit",
"rc4",
"rsa",
"salsa20",
"serpent",
"xor",
]
44 changes: 44 additions & 0 deletions malduck/crypto/chacha20.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import Optional
from Cryptodome.Cipher import ChaCha20 as ChaCha20Cipher


__all__ = ["chacha20"]


class ChaCha20:
def encrypt(self, key: bytes, data: bytes, nonce: Optional[bytes] = None) -> bytes:
"""
Encrypts buffer using ChaCha20 algorithm.

:param key: Cryptographic key (32 bytes)
:type key: bytes
:param data: Buffer to be encrypted
:type data: bytes
:param nonce: Nonce value (8/12 bytes, defaults to `b"\\\\x00"*8` )
:type nonce: bytes, optional
:return: Encrypted data
:rtype: bytes
"""
if nonce is None:
nonce = b"\x00" * 8
return ChaCha20Cipher.new(key=key, nonce=nonce).encrypt(data)

def decrypt(self, key: bytes, data: bytes, nonce: Optional[bytes] = None) -> bytes:
"""
Decrypts buffer using ChaCha20 algorithm.

:param key: Cryptographic key (32 bytes)
:type key: bytes
:param data: Buffer to be decrypted
:type data: bytes
:param nonce: Nonce value (8/12 bytes, defaults to `b"\\\\x00"*8` )
:type nonce: bytes, optional
:return: Decrypted data
:rtype: bytes
"""
if nonce is None:
nonce = b"\x00" * 8
return ChaCha20Cipher.new(key=key, nonce=nonce).decrypt(data)


chacha20 = ChaCha20()
44 changes: 44 additions & 0 deletions malduck/crypto/salsa20.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import Optional
from Cryptodome.Cipher import Salsa20 as Salsa20Cipher


__all__ = ["salsa20"]


class Salsa20:
def encrypt(self, key: bytes, data: bytes, nonce: Optional[bytes] = None) -> bytes:
"""
Encrypts buffer using Salsa20 algorithm.

:param key: Cryptographic key (16/32 bytes)
:type key: bytes
:param data: Buffer to be encrypted
:type data: bytes
:param nonce: Nonce value (8 bytes, defaults to `b"\\\\x00"*8` )
:type nonce: bytes, optional
:return: Encrypted data
:rtype: bytes
"""
if nonce is None:
nonce = b"\x00" * 8
return Salsa20Cipher.new(key=key, nonce=nonce).encrypt(data)

def decrypt(self, key: bytes, data: bytes, nonce: Optional[bytes] = None) -> bytes:
"""
Decrypts buffer using Salsa20 algorithm.

:param key: Cryptographic key (16/32 bytes)
:type key: bytes
:param data: Buffer to be decrypted
:type data: bytes
:param nonce: Nonce value (8 bytes, defaults to `b"\\\\x00"*8` )
:type nonce: bytes, optional
:return: Decrypted data
:rtype: bytes
"""
if nonce is None:
nonce = b"\x00" * 8
return Salsa20Cipher.new(key=key, nonce=nonce).decrypt(data)


salsa20 = Salsa20()
4 changes: 2 additions & 2 deletions malduck/crypto/serpent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def encrypt(self, key: bytes, data: bytes, iv: Optional[bytes] = None) -> bytes:
:type key: bytes
:param data: Buffer to be encrypted
:type data: bytes
:param iv: Initialization vector (defaults to `b"\x00" * 16`)
nazywam marked this conversation as resolved.
Show resolved Hide resolved
:param iv: Initialization vector (defaults to `b"\\\\x00" * 16`)
:type iv: bytes, optional
:return: Encrypted data
:rtype: bytes
Expand All @@ -29,7 +29,7 @@ def decrypt(self, key: bytes, data: bytes, iv: Optional[bytes] = None) -> bytes:
:type key: bytes
:param data: Buffer to be decrypted
:type data: bytes
:param iv: Initialization vector (defaults to `b"\x00" * 16`)
:param iv: Initialization vector (defaults to `b"\\\\x00" * 16`)
:type iv: bytes, optional
:return: Decrypted data
:rtype: bytes
Expand Down
22 changes: 21 additions & 1 deletion tests/test_crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# 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
from malduck import aes, blowfish, des3, rc4, rsa, xor, base64, unhex, rabbit, p8, serpent, chacha20, salsa20


def test_aes():
Expand Down Expand Up @@ -65,6 +65,26 @@ def test_des():
) == b"\x1d\xed\xc37pV\x89S\xac\xaeT\xaf\xa1\xcfW\xa3"


def test_chacha20():
assert chacha20.decrypt(
key=b"A"*32, data=b'P\xb6\x12W\xf4\xd7\x83|,\xea\x04n\xba\x08Kj', nonce=b"C"*8
) == b"B"*16

assert chacha20.encrypt(
key=b"A"*32, data=b"B"*16, nonce=b"C"*8
) == b'P\xb6\x12W\xf4\xd7\x83|,\xea\x04n\xba\x08Kj'


def test_salsa20():
assert salsa20.decrypt(
key=b"A"*32, data=b'\x16\x0e\x8d\xe2\xef\x8d\xf1\xc0\xf1\x17\xdf3\xed\xc6\xb5y', nonce=b"C"*8
) == b"B"*16

assert salsa20.encrypt(
key=b"A"*32, data=b"B"*16, nonce=b"C"*8
) == b'\x16\x0e\x8d\xe2\xef\x8d\xf1\xc0\xf1\x17\xdf3\xed\xc6\xb5y'


def test_rc4():
assert rc4(b"Key", b"Plaintext") == unhex("bbf316e8d940af0ad3")
assert rc4(b"Wiki", b"pedia") == unhex("1021bf0420")
Expand Down