Merge pull request #661 from Ciphey/bee-xor
Implement xortool in Ciphey and better testing
This commit is contained in:
commit
5b4244fbae
|
@ -19,28 +19,29 @@ class What(Checker[str]):
|
|||
|
||||
def check(self, ctext: T) -> Optional[str]:
|
||||
logging.debug("Trying PyWhat checker")
|
||||
returned_regexes = self.id.identify(ctext, api=True)
|
||||
if len(returned_regexes["Regexes"]) > 0:
|
||||
|
||||
matched_regex = returned_regexes["Regexes"][0]["Regex Pattern"]
|
||||
returned_regexes = self.id.identify(ctext)
|
||||
if returned_regexes["Regexes"]:
|
||||
matched_regex = returned_regexes["Regexes"]['text'][0]["Regex Pattern"]
|
||||
|
||||
ret = f'The plaintext is a [yellow]{matched_regex["Name"]}[/yellow]'
|
||||
human = f'\nI think the plaintext is a [yellow]{matched_regex["Name"]}[/yellow]'
|
||||
human = (
|
||||
f'\nI think the plaintext is a [yellow]{matched_regex["Name"]}[/yellow]'
|
||||
)
|
||||
|
||||
if "Description" in matched_regex and matched_regex["Description"]:
|
||||
s = matched_regex['Description']
|
||||
s = matched_regex["Description"]
|
||||
# lowercases first letter so it doesn't look weird
|
||||
s = f", which is {s[0].lower() + s[1:]}\n"
|
||||
ret += s
|
||||
human += s
|
||||
|
||||
|
||||
# if URL is attached, include that too.
|
||||
if "URL" in matched_regex:
|
||||
link = matched_regex['URL'] + ctext.replace(' ', '')
|
||||
if "URL" in matched_regex and matched_regex["URL"]:
|
||||
link = matched_regex["URL"] + ctext.replace(" ", "")
|
||||
ret += f"\nClick here to view in browser [#CAE4F1][link={link}]{link}[/link][/#CAE4F1]\n"
|
||||
|
||||
|
||||
# If greppable mode is on, don't print this
|
||||
if self.config.verbosity > 0:
|
||||
if self.config.verbosity >= 0:
|
||||
# Print with full stop
|
||||
console.print(human)
|
||||
return ret
|
||||
|
|
|
@ -6,6 +6,5 @@ from . import (
|
|||
rot47,
|
||||
soundex,
|
||||
vigenere,
|
||||
xor_single,
|
||||
xorcrypt,
|
||||
xortool,
|
||||
)
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
"""
|
||||
██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗
|
||||
██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
"""
|
||||
import base64
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import cipheycore
|
||||
import logging
|
||||
from rich.logging import RichHandler
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class XorCrypt(Cracker[bytes]):
|
||||
def getInfo(self, ctext: bytes) -> CrackInfo:
|
||||
if self.keysize is not None:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
f"xorcrypt::{self.keysize}",
|
||||
lambda: cipheycore.analyse_string(ctext, self.keysize, self.group),
|
||||
)
|
||||
|
||||
return CrackInfo(
|
||||
success_likelihood=cipheycore.xorcrypt_detect(analysis, self.expected),
|
||||
# TODO: actually calculate runtimes
|
||||
success_runtime=1e-4,
|
||||
failure_runtime=1e-4,
|
||||
)
|
||||
|
||||
keysize = self.cache.get_or_update(
|
||||
ctext,
|
||||
"xorcrypt::likely_lens",
|
||||
lambda: cipheycore.xorcrypt_guess_len(ctext),
|
||||
)
|
||||
|
||||
if keysize == 1:
|
||||
return CrackInfo(
|
||||
success_likelihood=0,
|
||||
# TODO: actually calculate runtimes
|
||||
success_runtime=2e-3,
|
||||
failure_runtime=2e-2,
|
||||
)
|
||||
|
||||
return CrackInfo(
|
||||
success_likelihood=0.9, # Dunno, but it's quite likely
|
||||
# TODO: actually calculate runtimes
|
||||
success_runtime=2e-3,
|
||||
failure_runtime=2e-2,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "xorcrypt"
|
||||
|
||||
def crackOne(
|
||||
self, ctext: bytes, analysis: cipheycore.windowed_analysis_res
|
||||
) -> List[CrackResult]:
|
||||
possible_keys = cipheycore.xorcrypt_crack(analysis, self.expected, self.p_value)
|
||||
|
||||
logging.debug(
|
||||
f"xorcrypt crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}"
|
||||
)
|
||||
return [
|
||||
CrackResult(
|
||||
value=cipheycore.xorcrypt_decrypt(ctext, candidate.key),
|
||||
key_info="0x" + "".join(["{:02x}".format(i) for i in candidate.key]),
|
||||
)
|
||||
for candidate in possible_keys[: min(len(possible_keys), 10)]
|
||||
]
|
||||
|
||||
def attemptCrack(self, ctext: bytes) -> List[CrackResult]:
|
||||
logging.info(f"Trying xorcrypt cipher on {base64.b64encode(ctext)}")
|
||||
|
||||
# Analysis must be done here, where we know the case for the cache
|
||||
if self.keysize is not None:
|
||||
return self.crackOne(
|
||||
ctext,
|
||||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"xorcrypt::{self.keysize}",
|
||||
lambda: cipheycore.analyse_bytes(ctext, self.keysize),
|
||||
),
|
||||
)
|
||||
|
||||
len = self.cache.get_or_update(
|
||||
ctext,
|
||||
"xorcrypt::likely_lens",
|
||||
lambda: cipheycore.xorcrypt_guess_len(ctext),
|
||||
)
|
||||
|
||||
logging.debug(f"Got possible length {len}")
|
||||
|
||||
if len < 2:
|
||||
return []
|
||||
|
||||
ret = []
|
||||
# Fuzz around
|
||||
for i in range(min(len - 2, 2), len + 2):
|
||||
ret += self.crackOne(
|
||||
ctext,
|
||||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"xorcrypt::{len}",
|
||||
lambda: cipheycore.analyse_bytes(ctext, len),
|
||||
),
|
||||
)
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"keysize": ParamSpec(
|
||||
desc="A key size that should be used. If not given, will attempt to work it out",
|
||||
req=False,
|
||||
),
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for windowed frequency analysis",
|
||||
req=False,
|
||||
default=0.001,
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.cache = config.cache
|
||||
self.keysize = self._params().get("keysize")
|
||||
if self.keysize is not None:
|
||||
self.keysize = int(self.keysize)
|
||||
self.p_value = self._params()["p_value"]
|
||||
self.max_key_length = 16
|
|
@ -5,68 +5,50 @@
|
|||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
Github: bee-san
|
||||
"""
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import cipheycore
|
||||
import logging
|
||||
from rich.logging import RichHandler
|
||||
|
||||
from xortool_ciphey import tool_main
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class XorSingle(Cracker[bytes]):
|
||||
class XorTool(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
"cipheycore::simple_analysis",
|
||||
lambda: cipheycore.analyse_bytes(ctext),
|
||||
)
|
||||
|
||||
return CrackInfo(
|
||||
success_likelihood=cipheycore.xor_single_detect(analysis, self.expected),
|
||||
success_likelihood=0.1,
|
||||
# TODO: actually calculate runtimes
|
||||
success_runtime=1e-5,
|
||||
failure_runtime=1e-5,
|
||||
success_runtime=1e-8,
|
||||
failure_runtime=1e-8,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "xor_single"
|
||||
return "xortool"
|
||||
|
||||
def attemptCrack(self, ctext: bytes) -> List[CrackResult]:
|
||||
logging.info("Trying xor single cipher")
|
||||
# TODO: handle different alphabets
|
||||
def attemptCrack(self, ctext: str) -> List[CrackResult]:
|
||||
logging.debug("Trying xortool cipher")
|
||||
# TODO handle different charsets
|
||||
# TODO allow more config over xortool
|
||||
|
||||
logging.debug("Beginning cipheycore simple analysis")
|
||||
logging.debug(f"{ctext}")
|
||||
|
||||
# Hand it off to the core
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
"cipheycore::simple_analysis",
|
||||
lambda: cipheycore.analyse_bytes(ctext),
|
||||
)
|
||||
logging.debug("Beginning cipheycore::xor_single")
|
||||
possible_keys = cipheycore.xor_single_crack(
|
||||
analysis, self.expected, self.p_value
|
||||
)
|
||||
# https://github.com/Ciphey/xortool/discussions/4
|
||||
# for docs on this function
|
||||
try:
|
||||
result = tool_main.api(str.encode(ctext))
|
||||
except:
|
||||
logging.debug("Xor failed.")
|
||||
return
|
||||
|
||||
n_candidates = len(possible_keys)
|
||||
logging.info(f"XOR single returned {n_candidates} candidates")
|
||||
result = CrackResult(value=result[1]["Dexored"], key_info=result[0]["keys"])
|
||||
|
||||
candidates = []
|
||||
|
||||
for candidate in possible_keys:
|
||||
translated = cipheycore.xor_single_decrypt(ctext, candidate.key)
|
||||
logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}")
|
||||
candidates.append(CrackResult(value=translated, key_info=candidate.key))
|
||||
|
||||
logging.debug(f"{candidates}")
|
||||
|
||||
return candidates
|
||||
return [result]
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
|
@ -80,8 +62,7 @@ class XorSingle(Cracker[bytes]):
|
|||
desc="The p-value to use for standard frequency analysis",
|
||||
req=False,
|
||||
default=0.01,
|
||||
)
|
||||
# TODO: add "filter" param
|
||||
),
|
||||
}
|
||||
|
||||
@staticmethod
|
|
@ -273,7 +273,9 @@ class AuSearch(Searcher):
|
|||
# TODO Cyclic uses some tricky C++ here
|
||||
# I know because it's sorted the one at the back (the anti-weight)
|
||||
# is the most likely
|
||||
|
||||
edge: Edge = chunk.pop(-1)
|
||||
|
||||
# Expand the node
|
||||
res = edge.route(edge.source.level.result.value)
|
||||
if res is None:
|
||||
|
|
|
@ -309,6 +309,7 @@ class Searcher(ConfigurableModule):
|
|||
|
||||
|
||||
def pretty_search_results(res: SearchResult, display_intermediate: bool = False) -> str:
|
||||
# TODO what is display_intermediate
|
||||
ret: str = ""
|
||||
table = Table(show_header=False, box=box.ROUNDED, safe_box=False)
|
||||
# Only print the checker if we need to. Normal people don't know what
|
||||
|
@ -340,12 +341,14 @@ def pretty_search_results(res: SearchResult, display_intermediate: bool = False)
|
|||
already_broken = True
|
||||
if not already_broken:
|
||||
out += "\n"
|
||||
return out
|
||||
return out, already_broken
|
||||
|
||||
# Skip the 'input' and print in order
|
||||
already_broken = False
|
||||
out = ""
|
||||
for i in res.path[1:]:
|
||||
out += add_one()
|
||||
output, already_broken = add_one()
|
||||
out += output
|
||||
|
||||
if out:
|
||||
if len(out.split("\n")) > 1:
|
||||
|
@ -358,8 +361,11 @@ def pretty_search_results(res: SearchResult, display_intermediate: bool = False)
|
|||
ret = ret[:-1]
|
||||
|
||||
# If we didn't show intermediate steps, then print the final result
|
||||
if not display_intermediate:
|
||||
if already_broken:
|
||||
ret += f"""\nPlaintext: [bold green]"{escape(res.path[-1].result.value)}"[bold green]"""
|
||||
else:
|
||||
ret += f"""Plaintext: [bold green]"{escape(res.path[-1].result.value)}"[bold green]"""
|
||||
|
||||
table.add_row(ret)
|
||||
return table
|
||||
|
||||
|
|
|
@ -136,7 +136,9 @@ class mathsHelper:
|
|||
highest_key = key
|
||||
logging.debug(f"Highest key is {highest_key}")
|
||||
# removes the highest key from the prob table
|
||||
logging.debug(f"Prob table is {prob_table} and highest key is {highest_key}")
|
||||
logging.debug(
|
||||
f"Prob table is {prob_table} and highest key is {highest_key}"
|
||||
)
|
||||
logging.debug(f"Removing {prob_table[highest_key]}")
|
||||
del prob_table[highest_key]
|
||||
logging.debug(f"Prob table after deletion is {prob_table}")
|
||||
|
|
|
@ -23,7 +23,8 @@ base91 = "^1.0.1"
|
|||
pybase62 = "^0.4.3"
|
||||
click = ">=7.1.2,<9.0.0"
|
||||
mock = "^4.0.3"
|
||||
pywhat = ">=0.2.5,<1.3.0"
|
||||
pywhat = "3.0.0"
|
||||
xortool-ciphey = "^0.1.16"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest-cov = "^2.10.1"
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import pytest
|
||||
from click.testing import CliRunner
|
||||
import mock
|
||||
import re
|
||||
|
||||
from ciphey import decrypt
|
||||
from ciphey.iface import Config
|
||||
from ciphey.ciphey import main
|
||||
from ciphey.basemods.Checkers import human
|
||||
|
||||
def test_xor():
|
||||
res = decrypt(Config().library_default().complete_config(),"Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/")
|
||||
assert re.findall("This is a test for XOR", res)
|
||||
|
||||
@pytest.mark.skip("Skipping because it matches on Discover card, this is a PyWhat bug that's being fixed.")
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "")
|
||||
def test_xor_tui_multi_byte(mock_click):
|
||||
# https://github.com/Ciphey/Ciphey/issues/655
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ['-vvv', '-t', '360w0x11450x114504421611100x0y0545000x06171y1511070145150x110z45081709110y45071y1100423w2z3045120z0x060z450x1145080w170042060z0u1509071w45160w040x45160y0y020v0045001x1107453w2w374y422x0y1111000301450w03450w0y091y4510110x0y05450442160x0x02090745071y110042030z104504420v001y45120z0x060z450x11450003161x42110z42071717110042030z10060042041642110w071700420x16420z0y0v1x4550505342150z11160x000x090y11001149450u1009160x45001x1107450v071x1642060z170901420w04140045160w0z170416030y0111450z0445150w16160y070x0v0x110716450u040v0y0y02420x11420w04100145160z450017101600030w1706074y453z2z37160z0z0v450x1145041500160w08004207000104101100450y114501040y42061703060v42070z160w45110x0y05090042071x160045030y014208100v110x42071x1600453z2z3742000y01171x121100064511071w114x452z0x060042260x120w001y450w0316453z2z37160z0z0v450x0x1100051704160001420x0y160z450y1149420x1142120x0v0945000045111015071745030804180x0y0545040x0145150x090v451012021703010042260x120w001y45110w450707450400090042110z42061703060v42060z0u1509071w453z2z3742000y01171x121100064511071w114x45320z1x450y1645160w0x114511071w1142160z42090z0x025z4227000104101100453z2z37160z0z0v45060w1009060y4216450610040609450x1645120z000y422x450u040107450x1645160z0z171600174x455u4z'])
|
||||
assert result.exit_code == 0
|
||||
assert re.findall("This is a string encrypted with multi", str(result.output))
|
||||
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "")
|
||||
def test_xor_tui(mock_click):
|
||||
# https://github.com/Ciphey/Ciphey/issues/655
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ['-t', 'Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/'])
|
||||
assert result.exit_code == 0
|
||||
assert re.findall("This is a test for XOR", str(result.output))
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "")
|
||||
def test_xor_tui_verbose_mode_doesnt_break(mock_click):
|
||||
# We had a bug where verbose mode broke xor
|
||||
# https://discord.com/channels/754001738184392704/814565556027654214/853183178104373310
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ['-v', '-t', 'Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/'])
|
||||
assert result.exit_code == 0
|
||||
assert re.findall("This is a test for XOR", str(result.output))
|
||||
|
||||
def test_xor_atbash():
|
||||
# Frsi!si!{!fwif!tmh!BMH-!sf!si!hw{nnc!nmlu!fm!o{qw!ighw!fr{f!BMHfmmn!y{l!uwf!sf/!Ysjrwc!*!BMHfmmn.si!ymmn/
|
||||
# This is a test for XOR, it is really long to make sure that XORtool can get it. Ciphey + XORtool/is cool.
|
||||
# Previously xor only worked on level 1, this test ensures it always works on levels > 1
|
||||
res = decrypt(Config().library_default().complete_config(),"Frsi!si!{!fwif!tmh!BMH-!sf!si!hw{nnc!nmlu!fm!o{qw!ighw!fr{f!BMHfmmn!y{l!uwf!sf/!Ysjrwc!*!BMHfmmn.si!ymmn/")
|
||||
assert re.findall("This is a test for XOR", res)
|
|
@ -1,14 +1,28 @@
|
|||
from click.testing import CliRunner
|
||||
from ciphey.ciphey import main
|
||||
from ciphey.basemods.Checkers import human
|
||||
import mock
|
||||
|
||||
|
||||
def test_hello_world():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ['-g', '-t', 'hello'])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == 'hello\n'
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["-g", "-t", "hello"])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == "hello\n"
|
||||
|
||||
|
||||
def test_ip_address():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ['-g', '-t', 'MTkyLjE2OC4wLjE='])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == '192.168.0.1\n'
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["-g", "-t", "MTkyLjE2OC4wLjE="])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == "192.168.0.1\n"
|
||||
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="")
|
||||
def test_quick_visual_output(mock_click):
|
||||
# https://github.com/Ciphey/Ciphey/issues/655
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="])
|
||||
assert result.exit_code == 0
|
||||
assert "base32" in result.output
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
from click.testing import CliRunner
|
||||
from ciphey.ciphey import main
|
||||
from ciphey.basemods.Checkers import human
|
||||
import mock
|
||||
import mock
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "")
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="")
|
||||
def test_fix_for_655(mock_click):
|
||||
# https://github.com/Ciphey/Ciphey/issues/655
|
||||
runner = CliRunner()
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ['-t', 'NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==='])
|
||||
result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="])
|
||||
assert result.exit_code == 0
|
||||
assert "base32" in result.output
|
||||
|
||||
|
||||
|
||||
# assert "base32" in result.output
|
||||
"""
|
||||
TODO Mock
|
||||
360d0c11450c114504421611100c0b0545000c06171b1511070145150c110a45081709110b45071b1100423d2a3045120a0c060a450c1145080d170042060a0f1509071d45160d040c45160b0b020e0045001c1107453d2d374b422c0b1111000301450d03450d0b091b4510110c0b05450442160c0c02090745071b110042030a104504420e001b45120a0c060a450c11450003161c42110a42071717110042030a10060042041642110d071700420c16420a0b0e1c4550505342150a11160c000c090b11001149450f1009160c45001c1107450e071c1642060a170901420d04140045160d0a170416030b0111450a0445150d16160b070c0e0c110716450f040e0b0b02420c11420d04100145160a450017101600030d1706074b453a2a37160a0a0e450c1145041500160d08004207000104101100450b114501040b42061703060e42070a160d45110c0b05090042071c160045030b014208100e110c42071c1600453a2a3742000b01171c121100064511071d114c452a0c060042260c120d001b450d0316453a2a37160a0a0e450c0c1100051704160001420c0b160a450b1149420c1142120c0e0945000045111015071745030804180c0b0545040c0145150c090e451012021703010042260c120d001b45110d450707450400090042110a42061703060e42060a0f1509071d453a2a3742000b01171c121100064511071d114c45320a1c450b1645160d0c114511071d1142160a42090a0c025a4227000104101100453a2a37160a0a0e45060d1009060b4216450610040609450c1645120a000b422c450f040107450c1645160a0a171600174c455f4a
|
||||
|
||||
As it passes as a discover card
|
||||
"""
|
||||
|
|
|
@ -112,7 +112,9 @@ def test_binary():
|
|||
assert res == answer_str
|
||||
|
||||
|
||||
@pytest.mark.skip("Can't decode base64 + caesar https://github.com/Ciphey/Ciphey/issues/606")
|
||||
@pytest.mark.skip(
|
||||
"Can't decode base64 + caesar https://github.com/Ciphey/Ciphey/issues/606"
|
||||
)
|
||||
def test_binary_base64_caesar():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import pytest
|
||||
|
||||
from ciphey import decrypt
|
||||
from ciphey.iface import Config
|
||||
from click.testing import CliRunner
|
||||
from ciphey.ciphey import main
|
||||
from ciphey.basemods.Checkers import human
|
||||
import mock
|
||||
|
||||
answer_str = "Hello my name is bee and I like dog and apple and tree"
|
||||
|
||||
|
||||
def test_quick_base32():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"JBSWY3DPEBWXSIDOMFWWKIDJOMQGEZLFEBQW4ZBAJEQGY2LLMUQGI33HEBQW4ZBAMFYHA3DFEBQW4ZBAORZGKZI=",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_quick_base58_ripple():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"aqY64A1PhaM8hgyagyw4C1Mmp5cwxGEwag8EjVm9F6YHebyfPZmsvt65XxS7ffteQgTEGbHNT8",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_quick_greppable_works_with_ip_address():
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["-g", "-t", "MTkyLjE2OC4wLjE="])
|
||||
assert result.exit_code == 0
|
||||
assert result.output == "192.168.0.1\n"
|
||||
|
||||
|
||||
@mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="")
|
||||
def test_quick_visual_output(mock_click):
|
||||
# https://github.com/Ciphey/Ciphey/issues/655
|
||||
runner = CliRunner()
|
||||
mock_click.return_value = "y"
|
||||
result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="])
|
||||
assert result.exit_code == 0
|
||||
assert "base32" in result.output
|
|
@ -11,6 +11,7 @@ def test_regex_ip():
|
|||
)
|
||||
assert res == "192.160.0.1"
|
||||
|
||||
|
||||
def test_regex_domain():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
|
@ -18,9 +19,10 @@ def test_regex_domain():
|
|||
)
|
||||
assert res == "https://google.com"
|
||||
|
||||
|
||||
def test_regex_bitcoin():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"M0ZaYmdpMjljcGpxMkdqZHdWOGV5SHVKSm5rTHRrdFpjNQ==",
|
||||
)
|
||||
assert res == "3FZbgi29cpjq2GjdwV8eyHuJJnkLtktZc5"
|
||||
assert res == "3FZbgi29cpjq2GjdwV8eyHuJJnkLtktZc5"
|
||||
|
|
Loading…
Reference in New Issue