Skip to content

Commit

Permalink
πŸ—“ Sep 10, 2023 5:29:44 PM
Browse files Browse the repository at this point in the history
✨ 6.1.0
✨ automatically detect delimiter
βž• deps added/updated
✨ fernet encrypt/decrypt
πŸ€– types added/updated
πŸ§ͺ tests added/updated
  • Loading branch information
securisec committed Sep 10, 2023
1 parent f9d1700 commit 4b511a5
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 30 deletions.
3 changes: 3 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ New ideas:
☐ ✨ amf encode/decode
☐ ✨ aes cmac
☐ ✨ whitespace encoding https://www.dcode.fr/whitespace-language
☐ πŸ™ diff show results only
☐ ✨ brainfuck encoder/decoder

Bug:

Expand Down Expand Up @@ -57,6 +59,7 @@ Misc:
☐ cyberchef recipe to chepy recipe converter

Archive:
βœ” ✨ automatic delimiter detect
βœ” ✨ rabbit encryption
βœ” ✨ cetacean encode/decode
βœ” ✨ huffman encode/decode
Expand Down
4 changes: 2 additions & 2 deletions chepy/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__version__ = "6.0.0" # pragma: no cover
__author__ = "Hapsida @securisec" # pragma: no cover
__version__ = "6.1.0" # pragma: no cover
__author__ = "@securisec" # pragma: no cover
2 changes: 1 addition & 1 deletion chepy/chepy_plugins
45 changes: 28 additions & 17 deletions chepy/modules/dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import string
from random import randint
from .internal.constants import Encoding
from .internal.helpers import detect_delimiter

yaml = lazy_import.lazy_module("yaml")
import regex as re
Expand Down Expand Up @@ -572,15 +573,14 @@ def from_hex(self, delimiter: str = None, join_by: str = " ") -> DataFormatT:
>>> Chepy("414141").from_hex().out
b"AAA"
"""
data = self._convert_to_bytes()
delimiter = detect_delimiter(data, default_delimiter=None)
if delimiter is not None:
self.state = join_by.encode().join(
list(
binascii.unhexlify(x)
for x in self._convert_to_str().split(delimiter)
)
list(binascii.unhexlify(x) for x in data.split(delimiter))
)
else:
self.state = binascii.unhexlify(self._convert_to_str())
self.state = binascii.unhexlify(data)
return self

@ChepyDecorators.call_stack
Expand Down Expand Up @@ -873,14 +873,14 @@ def to_charcode(self, join_by: str = " ", base: int = 16) -> DataFormatT:

@ChepyDecorators.call_stack
def from_charcode(
self, delimiter: str = " ", join_by: str = "", base: int = 16
self, delimiter: str = None, join_by: str = "", base: int = 10
) -> DataFormatT:
"""Convert array of unicode chars to string
Args:
delimiter (str, optional): Delimiter. Defaults to " ".
join_by (str, optional): Join by. Defaults to "".
base (int, optional): Base. Defaults to 16.
base (int, optional): Base. Defaults to 10.
Returns:
Chepy: The Chepy object.
Expand All @@ -889,8 +889,10 @@ def from_charcode(
>>> Chepy("314e 61 20 41"]).from_charcode().o
"γ…Ža A"
"""
data = self._convert_to_str()
out = []
for c in self._convert_to_str().split(delimiter):
delimiter = detect_delimiter(data)
for c in data.split(delimiter):
out.append(chr(int(c, base)))
self.state = join_by.join(out)
return self
Expand All @@ -915,7 +917,7 @@ def to_decimal(self, join_by: str = " ") -> DataFormatT:
return self

@ChepyDecorators.call_stack
def from_decimal(self, delimiter: str = " ", join_by: str = "") -> DataFormatT:
def from_decimal(self, delimiter: str = None, join_by: str = "") -> DataFormatT:
"""Convert a list of decimal numbers to string
Args:
Expand All @@ -929,8 +931,10 @@ def from_decimal(self, delimiter: str = " ", join_by: str = "") -> DataFormatT:
>>> Chepy(12622).from_decimal().o
"γ…Ž"
"""
data = self._convert_to_str()
delimiter = detect_delimiter(data)
self.state = join_by.join(
list(chr(int(s)) for s in self._convert_to_str().strip().split(delimiter))
list(chr(int(s)) for s in data.strip().split(delimiter))
)
return self

Expand Down Expand Up @@ -960,7 +964,7 @@ def to_binary(
return self

@ChepyDecorators.call_stack
def from_binary(self, delimiter: str = " ", byte_length: int = 8) -> DataFormatT:
def from_binary(self, delimiter: str = None, byte_length: int = 8) -> DataFormatT:
"""Convert a list of binary numbers to string
Args:
Expand All @@ -974,10 +978,10 @@ def from_binary(self, delimiter: str = " ", byte_length: int = 8) -> DataFormatT
>>> Chepy("01100001 01100010 01100011").from_binary().o
"abc"
"""
data = self._convert_to_str()
delimiter = detect_delimiter(data)
n = int(
"".join(
[x[byte_length - 8 :] for x in self._convert_to_str().split(delimiter)]
),
"".join([x[byte_length - 8 :] for x in data.split(delimiter)]),
2,
)
self.state = n.to_bytes((n.bit_length() + 7) // 8, "big")
Expand Down Expand Up @@ -1017,8 +1021,10 @@ def from_octal(self, delimiter: str = None, join_by: str = "") -> DataFormatT:
>>> Chepy("141 142").from_octal().o
"ab"
"""
data = self._convert_to_str()
delimiter = detect_delimiter(data, default_delimiter=delimiter)
self.state = join_by.join(
list(chr(int(str(x), 8)) for x in self._convert_to_str().split(delimiter))
list(chr(int(str(x), 8)) for x in data.split(delimiter))
)
return self

Expand Down Expand Up @@ -1236,7 +1242,9 @@ def to_nato(self, join_by: str = " ") -> DataFormatT:
return self

@ChepyDecorators.call_stack
def from_nato(self, delimiter: str = " ", join_by: str = "") -> DataFormatT:
def from_nato(
self, delimiter: Union[str, None] = None, join_by: str = ""
) -> DataFormatT:
"""Translate NATO phoentic to words
Args:
Expand All @@ -1246,7 +1254,10 @@ def from_nato(self, delimiter: str = " ", join_by: str = "") -> DataFormatT:
Returns:
Chepy: The Chepy object
"""
data = self._convert_to_str().split(delimiter)
data = self._convert_to_str()
if delimiter is None:
delimiter = detect_delimiter(data)
data = data.split(delimiter)
d = {v: k for k, v in Encoding.NATO_CONSTANTS_DICT.items()}
self.state = join_by.join([d.get(p, p) for p in data])
return self
Expand Down
10 changes: 5 additions & 5 deletions chepy/modules/dataformat.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class DataFormat(ChepyCore):
def from_base64(self: DataFormatT, custom: str=..., url_safe: bool=...) -> DataFormatT: ...
def decode_bytes(self: DataFormatT, errors: Literal['ignore', 'backslashreplace', 'replace']=...) -> DataFormatT: ...
def to_hex(self: DataFormatT, delimiter: str=..., join_by: str=...) -> DataFormatT: ...
def from_hex(self: DataFormatT, delimiter: str=...) -> DataFormatT: ...
def from_hex(self: DataFormatT, delimiter: Union[str, None]=None) -> DataFormatT: ...
def hex_to_int(self: DataFormatT) -> DataFormatT: ...
def hex_to_bytes(self: DataFormatT) -> DataFormatT: ...
def hex_to_str(self: DataFormatT, ignore: bool=...) -> DataFormatT: ...
Expand All @@ -51,11 +51,11 @@ class DataFormat(ChepyCore):
def str_to_list(self: DataFormatT) -> DataFormatT: ...
def str_to_dict(self: DataFormatT) -> DataFormatT: ...
def to_charcode(self: DataFormatT, join_by: str=..., base: int=...) -> DataFormatT: ...
def from_charcode(self: DataFormatT, delimiter: str=..., join_by: str=..., base: int=...) -> DataFormatT: ...
def from_charcode(self: DataFormatT, delimiter: Union[str, None]=None, join_by: str=' ', base: int=10) -> DataFormatT: ...
def to_decimal(self: DataFormatT) -> DataFormatT: ...
def from_decimal(self: DataFormatT, delimiter: str=..., join_by: str=...) -> DataFormatT: ...
def from_decimal(self: DataFormatT, delimiter: Union[str, None]=None, join_by: str=...) -> DataFormatT: ...
def to_binary(self: DataFormatT, join_by: Union[bytes, str]=..., byte_length: int=...) -> DataFormatT: ...
def from_binary(self: DataFormatT, delimiter: Union[bytes, str]=..., byte_length: int=...) -> DataFormatT: ...
def from_binary(self: DataFormatT, delimiter: Union[str, None]=None, byte_length: int=...) -> DataFormatT: ...
def to_octal(self: DataFormatT, join_by: str=...) -> DataFormatT: ...
def from_octal(self: DataFormatT, delimiter: str=..., join_by: str=...) -> DataFormatT: ...
def to_html_entity(self: DataFormatT) -> DataFormatT: ...
Expand All @@ -68,7 +68,7 @@ class DataFormat(ChepyCore):
def from_braille(self: DataFormatT) -> DataFormatT: ...
def trim(self: DataFormatT) -> DataFormatT: ...
def to_nato(self: DataFormatT, join_by:str=...) -> DataFormatT: ...
def from_nato(self: DataFormatT, delimiter: str=..., join_by: str=...) -> DataFormatT: ...
def from_nato(self: DataFormatT, delimiter: Union[str, None]=None, join_by: str=...) -> DataFormatT: ...
def swap_strings(self: DataFormatT, by:int) -> DataFormatT: ...
def to_string(self: DataFormatT) -> DataFormatT: ...
def stringify(self: DataFormatT, compact:bool=...) -> DataFormatT: ...
Expand Down
48 changes: 46 additions & 2 deletions chepy/modules/encryptionencoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
derive_key as _derive_key,
)
from .internal.constants import Ciphers, Rabbit
from .internal.helpers import detect_delimiter

import lazy_import

Expand All @@ -34,6 +35,7 @@
Blowfish = lazy_import.lazy_module("Crypto.Cipher.Blowfish")
Padding = lazy_import.lazy_module("Crypto.Util.Padding")
pycipher = lazy_import.lazy_module("pycipher")
Fernet = lazy_import.lazy_callable("cryptography.fernet.Fernet")

from ..core import ChepyCore, ChepyDecorators
from ..extras.combinatons import hex_chars
Expand Down Expand Up @@ -1499,7 +1501,7 @@ def to_letter_number_code(

@ChepyDecorators.call_stack
def from_letter_number_code(
self, delimiter: Union[str, bytes] = " ", join_by: Union[str, bytes] = ""
self, delimiter: Union[str, bytes] = None, join_by: Union[str, bytes] = ""
) -> EncryptionEncodingT:
"""Decode A1Z26
Expand All @@ -1510,7 +1512,9 @@ def from_letter_number_code(
Returns:
Chepy: The Chepy object.
"""
data = self._convert_to_str().split(delimiter)
data = self._convert_to_str()
delimiter = detect_delimiter(data)
data = data.split(delimiter)
hold = ["Β§" for _ in range(len(data))]
for d in data:
try:
Expand Down Expand Up @@ -1771,3 +1775,43 @@ def rabbit(self, key: str, iv: Union[None, str] = None) -> EncryptionEncodingT:
"""
self.state = Rabbit(key, iv).encrypt(self._convert_to_str())
return self

@ChepyDecorators.call_stack
def fernet_encrypt(
self, key: Union[bytes, str], encode_key: bool = False
) -> EncryptionEncodingT:
"""Fernet encrypt
Args:
key (Union[bytes, str]): Key to encrypt with. This should be 32 bytes long
encode_key (bool, optional): If key should be base64 encoded. Defaults to False.
Returns:
Chepy: The Chepy object.
"""
key = self._str_to_bytes(key)
if encode_key:
key = base64.b64encode(key)
out = Fernet(key).encrypt(self._convert_to_bytes())
self.state = out
return self

@ChepyDecorators.call_stack
def fernet_decrypt(
self, key: Union[bytes, str], encode_key: bool = False
) -> EncryptionEncodingT:
"""Fernet decrypt
Args:
key (Union[bytes, str]): Key to encrypt with. This should be 32 bytes long
encode_key (bool, optional): If key should be base64 encoded. Defaults to False.
Returns:
Chepy: The Chepy object.
"""
key = self._str_to_bytes(key)
if encode_key:
key = base64.b64encode(key)
out = Fernet(key).decrypt(self._convert_to_bytes())
self.state = out
return self
4 changes: 3 additions & 1 deletion chepy/modules/encryptionencoding.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class EncryptionEncoding(ChepyCore):
def rsa_public_key_from_jwk(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def monoalphabetic_substitution(self: EncryptionEncodingT, mapping: Dict[str, str]=...): ...
def to_letter_number_code(self: EncryptionEncodingT, join_by: Union[str, bytes]=...) -> EncryptionEncodingT: ...
def from_letter_number_code(self: EncryptionEncodingT, delimiter: Union[str, bytes]=..., join_by: Union[str, bytes]=...) -> EncryptionEncodingT: ...
def from_letter_number_code(self: EncryptionEncodingT, delimiter: Union[str, bytes, None]=None, join_by: Union[str, bytes]=...) -> EncryptionEncodingT: ...
def ls47_encrypt(self: EncryptionEncodingT, password: str, padding: int=..., signature: str=...) -> EncryptionEncodingT: ...
def ls47_decrypt(self: EncryptionEncodingT, password: str, padding: int=...) -> EncryptionEncodingT: ...
def bifid_encode(self: EncryptionEncodingT, key: Union[bytes, str]='') -> EncryptionEncodingT: ...
Expand All @@ -65,3 +65,5 @@ class EncryptionEncoding(ChepyCore):
def cetacean_encode(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def cetacean_decode(self: EncryptionEncodingT) -> EncryptionEncodingT: ...
def rabbit(self: EncryptionEncodingT, key: str, iv: Union[None, str]=...) -> EncryptionEncodingT: ...
def fernet_encrypt(self: EncryptionEncodingT, key:Union[bytes, str], encode_key: bool=False) -> EncryptionEncodingT: ...
def fernet_decrypt(self: EncryptionEncodingT, key:Union[bytes, str], encode_key: bool=False) -> EncryptionEncodingT: ...
44 changes: 44 additions & 0 deletions chepy/modules/internal/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import List, Union


def detect_delimiter(
data: Union[str, bytes],
delimiters: List[Union[str, bytes]] = [
" ",
";",
".",
"-",
"\\",
":",
"/",
",",
"\n",
"\\x",
"\\0x",
],
default_delimiter: str = " ",
) -> Union[str, bytes, None]:
"""Detect delimiter
Args:
data (Union[str, bytes]): Data
delimiters (List[Union[str, bytes]], optional): Array of delimiters. Defaults to [" ", ";", ".", "-", "\"].
default_delimiter (str): The default delimiter
Returns:
Union[str, bytes, None]: Delimiter or None if one is not found
"""
is_bytes = False
if isinstance(data, bytes): # pragma: no cover
delimiters = [d.encode() for d in delimiters]
is_bytes = True

for delimiter in delimiters:
parts = data.split(delimiter)
if len(parts) > 1 and all(part.strip() for part in parts):
return delimiter

if default_delimiter: # pragma: no cover
return default_delimiter.encode() if is_bytes else default_delimiter
else:
return None
3 changes: 2 additions & 1 deletion chepy/modules/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ def split_by_char(self, delimiter: str = " ") -> UtilsT:
Returns:
UtilsT: The Chepy object.
"""
self.state = self._convert_to_str().split(delimiter)
delimiter = self._str_to_bytes(delimiter)
self.state = self._convert_to_bytes().split(delimiter)
return self

@ChepyDecorators.call_stack
Expand Down
11 changes: 10 additions & 1 deletion tests/test_dataformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ def test_to_charcode():


def test_from_charcode():
assert Chepy("314e 61 20 41").from_charcode().o == b"\xe3\x85\x8ea A"
assert Chepy("314e-61-20-41").from_charcode(base=16).o == b"\xe3\x85\x8ea A"
assert Chepy("314e 61 20 41").from_charcode(base=16).o == b"\xe3\x85\x8ea A"
assert Chepy("97 98 99").from_charcode().o == b"abc"


def test_to_decimal():
Expand All @@ -275,6 +277,7 @@ def test_to_decimal():

def test_from_decimal():
assert Chepy(12622).from_decimal().o == b"\xe3\x85\x8e"
assert Chepy('97-98-99').from_decimal().o == b"abc"


def test_to_binary():
Expand Down Expand Up @@ -386,6 +389,12 @@ def test_nato_convert():
.o
== b"LAKEMICHIGAN"
)
assert (
Chepy("Lima-Alpha-Kilo-Echo-Mike-India-Charlie-Hotel-India-Golf-Alpha-November")
.from_nato()
.o
== b"LAKEMICHIGAN"
)
assert (
Chepy(
"Whiskey Hotel Four Tango Dash Alpha Romeo Three Dash Yankee Oscar Uniform Dash Sierra One November Kilo India November Golf Dash Four Bravo Zero Uniform Seven"
Expand Down
8 changes: 8 additions & 0 deletions tests/test_encryptionencoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,3 +828,11 @@ def test_cetacean():

def test_rabbit():
assert Chepy("hello").rabbit("pass", "iv").rabbit("pass", "iv").o == b"hello"


def test_fernet():
flag = "ucf{urum_noql}"
key = "\x41" * 32
c = Chepy(flag).fernet_encrypt(key, True)
assert c.o.startswith(b"gAAAAABk")
assert c.fernet_decrypt(key, True).o == flag.encode()

0 comments on commit 4b511a5

Please sign in to comment.