Skip to content

Commit

Permalink
Add chacha20 and salsa20 ciphers (#46)
Browse files Browse the repository at this point in the history
* Add salsa20 and chacha20 ciphers

* Fix the hex escapes in documentation
  • Loading branch information
nazywam authored Oct 1, 2020
1 parent 939ef01 commit c194965
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 7 deletions.
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`)
: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

0 comments on commit c194965

Please sign in to comment.