diff --git a/Makefile b/Makefile index b4665e6..46f216c 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ test: - python -m pytest -v --disable-pytest-warnings --cov-report=xml --cov=chepy --cov-config=.coveragerc tests/ + python -m pytest --noconftest -v --disable-pytest-warnings --cov-report=xml --cov=chepy --cov-config=.coveragerc tests/ test-all: test - python -m pytest -v --disable-pytest-warnings tests_plugins/ + python -m pytest --noconftest -v --disable-pytest-warnings tests_plugins/ # git log --format=%B 4.0.0..5.0.0 | sed '/^\s*$/d' | sort | uniq \ No newline at end of file diff --git a/TODO b/TODO index 0a542cb..124da24 100644 --- a/TODO +++ b/TODO @@ -26,9 +26,10 @@ New ideas: ☐ ✨ amf encode/decode ☐ ✨ aes cmac ☐ ✨ whitespace encoding https://www.dcode.fr/whitespace-language - beaufort + ☐ beaufort ☐ register support in callstack ☐ 🔥 update python_requires in setup.py on python version change + ☐ 🐙 update config to use envars also Bug: @@ -59,14 +60,5 @@ Misc: ☐ cyberchef recipe to chepy recipe converter Archive: - ✔ 🐙 diff show results only - ✔ 🐙 update ascii in xor function to documentation - ✔ 🐛 search with bytes is erroring - ✔ ✨ base62 - ✔ ✨ callback function that can take a python function and run it over state. handle recipes for this - ✔ ✨ automatic delimiter detect - ✔ ✨ rabbit encryption - ✔ ✨ cetacean encode/decode - ✔ ✨ huffman encode/decode - ✔ ✨ new plugin that can help detect encoding type trained on random data - ✔ ✨ bifd + ✔ ecb no padding in aes/des + ✔ update ml model with different spacing for hex, binary etc diff --git a/chepy/chepy_plugins b/chepy/chepy_plugins index 80d08b7..164f631 160000 --- a/chepy/chepy_plugins +++ b/chepy/chepy_plugins @@ -1 +1 @@ -Subproject commit 80d08b7a58c667c2997e9c5386772da505edd432 +Subproject commit 164f63115b79f974770b30884181aa764beb2757 diff --git a/chepy/config.py b/chepy/config.py index e3ce410..5214894 100644 --- a/chepy/config.py +++ b/chepy/config.py @@ -135,5 +135,5 @@ def load_plugins(self): # pragma: no cover loaded = getattr(plugin, klass) plugins.append(loaded) except: - logging.warning("Error loading {}".format(plugin.__name__)) + logging.warning(f"Error loading {plugin.__name__}") return plugins diff --git a/chepy/modules/dataformat.py b/chepy/modules/dataformat.py index 2849984..3d8f1cf 100644 --- a/chepy/modules/dataformat.py +++ b/chepy/modules/dataformat.py @@ -554,7 +554,7 @@ def to_hex(self, delimiter: str = "") -> DataFormatT: return self @ChepyDecorators.call_stack - def from_hex(self, delimiter: str = None, join_by: str = " ") -> DataFormatT: + def from_hex(self, delimiter: str = None, join_by: str = "") -> DataFormatT: """Convert a non delimited hex string to string Args: diff --git a/chepy/modules/dataformat.pyi b/chepy/modules/dataformat.pyi index 6d7bc4e..e1e68e0 100644 --- a/chepy/modules/dataformat.pyi +++ b/chepy/modules/dataformat.pyi @@ -32,7 +32,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: Union[str, None]=None) -> DataFormatT: ... + def from_hex(self: DataFormatT, delimiter: Union[str, None]=None, join_by: str='') -> DataFormatT: ... def hex_to_int(self: DataFormatT) -> DataFormatT: ... def hex_to_bytes(self: DataFormatT) -> DataFormatT: ... def hex_to_str(self: DataFormatT, ignore: bool=...) -> DataFormatT: ... diff --git a/chepy/modules/encryptionencoding.py b/chepy/modules/encryptionencoding.py index b33eda9..3985268 100644 --- a/chepy/modules/encryptionencoding.py +++ b/chepy/modules/encryptionencoding.py @@ -802,18 +802,24 @@ def triple_des_decrypt( b"some data" """ - self.__check_mode(mode) - key, iv = self._convert_key(key, iv, key_format, iv_format) if mode == "CBC": cipher = DES3.new(key, mode=DES3.MODE_CBC, iv=iv) self.state = Padding.unpad(cipher.decrypt(self._convert_to_bytes()), 8) return self + elif mode == "CBC/NoPadding": + cipher = DES3.new(key, mode=DES3.MODE_CBC, iv=iv) + self.state = cipher.decrypt(self._convert_to_bytes()) + return self elif mode == "ECB": cipher = DES3.new(key, mode=DES3.MODE_ECB) self.state = Padding.unpad(cipher.decrypt(self._convert_to_bytes()), 8) return self + elif mode == "ECB/NoPadding": + cipher = DES3.new(key, mode=DES3.MODE_ECB) + self.state = cipher.decrypt(self._convert_to_bytes()) + return self elif mode == "CTR": cipher = DES3.new(key, mode=DES3.MODE_CTR, nonce=b"") self.state = cipher.decrypt(self._convert_to_bytes()) @@ -822,6 +828,8 @@ def triple_des_decrypt( cipher = DES3.new(key, mode=DES3.MODE_OFB, iv=iv) self.state = cipher.decrypt(self._convert_to_bytes()) return self + else: # pragma: no cover + raise ValueError('Invalid mode') @ChepyDecorators.call_stack def aes_encrypt( @@ -894,7 +902,7 @@ def aes_decrypt( key_format: str = "hex", iv_format: str = "hex", ) -> EncryptionEncodingT: - """Decrypt raw state encrypted with DES. + """Decrypt raw state encrypted with AES. CFB mode reflects Cyberchef and not native python behaviour. Args: @@ -916,15 +924,17 @@ def aes_decrypt( b"some data" """ - assert mode in ["CBC", "CFB", "OFB", "CTR", "ECB", "GCM"], "Not a valid mode." - key, iv = self._convert_key(key, iv, key_format, iv_format) if mode == "CBC": cipher = AES.new(key, mode=AES.MODE_CBC, iv=iv) self.state = Padding.unpad(cipher.decrypt(self._convert_to_bytes()), 16) return self - if mode == "CFB": + elif mode == "CBC/NoPadding": + cipher = AES.new(key, mode=AES.MODE_CBC, iv=iv) + self.state = cipher.decrypt(self._convert_to_bytes()) + return self + elif mode == "CFB": cipher = AES.new(key, mode=AES.MODE_CFB, iv=iv, segment_size=128) self.state = cipher.decrypt(self._convert_to_bytes()) return self @@ -932,6 +942,10 @@ def aes_decrypt( cipher = AES.new(key, mode=AES.MODE_ECB) self.state = Padding.unpad(cipher.decrypt(self._convert_to_bytes()), 16) return self + elif mode == "ECB/NoPadding": + cipher = AES.new(key, mode=AES.MODE_ECB) + self.state = cipher.decrypt(self._convert_to_bytes()) + return self elif mode == "CTR": counter = Counter.new(128, initial_value=int.from_bytes(iv, "big")) cipher = AES.new(key, mode=AES.MODE_CTR, counter=counter) @@ -949,6 +963,8 @@ def aes_decrypt( cipher = AES.new(key, mode=AES.MODE_OFB, iv=iv) self.state = cipher.decrypt(self._convert_to_bytes()) return self + else: # pragma: no cover + raise ValueError('Invalid AES mode') @ChepyDecorators.call_stack def blowfish_encrypt( @@ -1108,6 +1124,7 @@ def vigenere_decode(self, key: str) -> EncryptionEncodingT: alphabet = "abcdefghijklmnopqrstuvwxyz" output = "" fail = 0 + key = key.lower() if not key: raise ValueError("No key entered") # pragma: no cover diff --git a/chepy/modules/encryptionencoding.pyi b/chepy/modules/encryptionencoding.pyi index 7d1a540..4600d5d 100644 --- a/chepy/modules/encryptionencoding.pyi +++ b/chepy/modules/encryptionencoding.pyi @@ -29,14 +29,14 @@ class EncryptionEncoding(ChepyCore): def jwt_token_generate_embedded_jwk(self: EncryptionEncodingT, private_key_pem: str, private_key_passphrase: str = ..., headers: dict = ..., alg: str = Union["RS256", "RS512"]) -> EncryptionEncodingT: ... def rc4_encrypt(self: EncryptionEncodingT, key: str, key_format: RC4_FORMAT=...) -> EncryptionEncodingT: ... def rc4_decrypt(self: EncryptionEncodingT, key: str, key_format: RC4_FORMAT=...) -> EncryptionEncodingT: ... - def des_encrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... - def des_decrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... + def des_encrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... + def des_decrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... def chacha_encrypt(self: EncryptionEncodingT, key: str, nonce: str=..., key_format: FORMAT=..., nonce_format: FORMAT=...) -> EncryptionEncodingT: ... def chacha_decrypt(self: EncryptionEncodingT, key: str, nonce: str=..., key_format: FORMAT=..., nonce_format: FORMAT=...) -> EncryptionEncodingT: ... - def triple_des_encrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... - def triple_des_decrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... - def aes_encrypt(self: EncryptionEncodingT, key: Union[bytes, str], iv: str=..., mode: Literal["CBC", "CFB", "OFB", "CTR", "ECB", "GCM"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... - def aes_decrypt(self: EncryptionEncodingT, key: Union[bytes, str], iv: str=..., mode: Literal["CBC", "CFB", "OFB", "CTR", "ECB", "GCM"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... + def triple_des_encrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... + def triple_des_decrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB", "ECB/NoPadding", "CBC/NoPadding"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... + def aes_encrypt(self: EncryptionEncodingT, key: Union[bytes, str], iv: str=..., mode: Literal["CBC", "CFB", "OFB", "CTR", "ECB", "GCM"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... + def aes_decrypt(self: EncryptionEncodingT, key: Union[bytes, str], iv: str=..., mode: Literal["CBC", "CFB", "OFB", "CTR", "ECB", "GCM", "ECB/NoPadding", "CBC/NoPadding"]="CBC", key_format: FORMAT="hex", iv_format: FORMAT="hex") -> EncryptionEncodingT: ... def blowfish_encrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... def blowfish_decrypt(self: EncryptionEncodingT, key: str, iv: str=..., mode: Literal["CBC", "OFB", "CTR", "ECB"]=..., key_format: FORMAT=..., iv_format: FORMAT=...) -> EncryptionEncodingT: ... def vigenere_encode(self: EncryptionEncodingT, key: str) -> EncryptionEncodingT: ... diff --git a/setup.cfg b/setup.cfg index b88034e..dc16a72 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,5 @@ [metadata] description-file = README.md + +[tool:pytest] +testpaths = tests tests_plugins \ No newline at end of file diff --git a/tests/test_core.py b/tests/test_core.py index c8af4d4..f6ccf93 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -149,7 +149,7 @@ def test_load_file_binary(): def test_show_recipe(): assert Chepy("4142").from_hex().recipe == [ - {"function": "from_hex", "args": {"delimiter": None, "join_by": " "}} + {"function": "from_hex", "args": {"delimiter": None, "join_by": ""}} ] diff --git a/tests/test_encryptionencoding.py b/tests/test_encryptionencoding.py index d9fc20e..911ead9 100644 --- a/tests/test_encryptionencoding.py +++ b/tests/test_encryptionencoding.py @@ -464,6 +464,22 @@ def test_aes_decrypt(): .o == b"some data" ) + assert ( + Chepy("6bcd22d5c24a59a818f39ba64b7f2d21") + .from_hex() + .aes_decrypt("b88e5c5597eb6e5e9d1ce47ab2eb57d0fcbd44a3c3a648116cbf6b09073f836b", iv='404cce974703e46da08c3fb65c469109', mode='ECB/NoPadding') + .to_hex() + .o + == b"68656c6c6f0b0b0b0b0b0b0b0b0b0b0b" + ) + assert ( + Chepy("dda597db9a1b3627f64fb3397502c6f4") + .from_hex() + .aes_decrypt("b88e5c5597eb6e5e9d1ce47ab2eb57d0fcbd44a3c3a648116cbf6b09073f836b", iv='404cce974703e46da08c3fb65c469109', mode='CBC/NoPadding') + .to_hex() + .o + == b"68656c6c6f0b0b0b0b0b0b0b0b0b0b0b" + ) def test_des_decrypt(): @@ -540,6 +556,8 @@ def test_triple_des_decrypt(): .o == b"some data" ) + assert Chepy('23bba626dce4683a').from_hex().triple_des_decrypt('df5770dec9f7d1843d72f195656b374c894b435da94a830d', '8219e29f40416b93', mode='ECB/NoPadding').to_hex().o == b'68656c6c6f030303' + assert Chepy('804b7fd84fa2d823').from_hex().triple_des_decrypt('df5770dec9f7d1843d72f195656b374c894b435da94a830d', '8219e29f40416b93', mode='CBC/NoPadding').to_hex().o == b'68656c6c6f030303' def test_blowfish_encrypt(): @@ -622,7 +640,7 @@ def test_vigener_encode(): def test_vigenere_decode(): assert ( - Chepy("npcdhzaon{a4Rmp!_K1N5q0p_4vQfKkT1uA3R}").vigenere_decode("victory").o + Chepy("npcdhzaon{a4Rmp!_K1N5q0p_4vQfKkT1uA3R}").vigenere_decode("vicTOry").o == b"shaktictf{y4Yyy!_M1S5i0n_4cCoMpL1sH3D}" ) assert Chepy("kieiim").vigenere_decode("secret").o == b"secret"