Code cleanup (#510)
* Code cleanup * Rename base58.py to base58_bitcoin.py * Bump CipheyCore and CipheyDists * Update __init__.py * Fix import error * Fix error * Fix decoder error * Fix import error * Fix type error * Fix bytes error * Fix attribute error * Fix XandY cracker * Fix brandon test * Fix leetspeak test * Update and rename leet.py to leetspeak.py * Update and rename morse.py to morse_code.py * Update __init__.py
This commit is contained in:
parent
3721f91ce0
commit
5544e945c5
|
@ -1,7 +1,2 @@
|
|||
from . import common
|
||||
|
||||
from . import iface
|
||||
|
||||
from . import basemods
|
||||
|
||||
from . import basemods, common, iface
|
||||
from .ciphey import decrypt
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
from . import quorum, regex, brandon, format, human, any
|
||||
|
||||
from . import ezcheck
|
||||
from . import any, brandon, ezcheck, format, human, quorum, regex
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import Optional, Dict
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import registry, PolymorphicChecker, Config, ParamSpec
|
||||
from ciphey.iface import Config, ParamSpec, PolymorphicChecker, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
"""
|
||||
██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗
|
||||
██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
|
||||
Class to determine whether somethine is English or not.
|
||||
Class to determine whether something is English or not.
|
||||
1. Calculate the Chi Squared score of a sentence
|
||||
2. If the score is significantly lower than the average score, it _might_ be English
|
||||
2.1. If the score _might_ be English, then take the text and compare it to the sorted dictionary
|
||||
|
@ -15,7 +15,7 @@ Class to determine whether somethine is English or not.
|
|||
It creates a percentage of "How much of this text is in the dictionary?"
|
||||
The dictionary contains:
|
||||
* 20,000 most common US words
|
||||
* 10,000 most common UK words (there's no repition between the two)
|
||||
* 10,000 most common UK words (there's no repetition between the two)
|
||||
* The top 10,000 passwords
|
||||
If the word "Looks like" English (chi-squared) and if it contains English words, we can conclude it is
|
||||
very likely English. The alternative is doing the dictionary thing but with an entire 479k word dictionary (slower)
|
||||
|
@ -31,7 +31,7 @@ How to add a language:
|
|||
* Download your desired dictionary. Try to make it the most popular words, for example. Place this file into this
|
||||
folder with languagename.txt
|
||||
As an example, this comes built in with english.txt
|
||||
Find the statistical frequency of each letter in that language.
|
||||
Find the statistical frequency of each letter in that language.
|
||||
For English, we have:
|
||||
self.languages = {
|
||||
"English":
|
||||
|
@ -45,23 +45,17 @@ self.languages = {
|
|||
[0.0855, 0.0160, 0.0316, 0.0387, 0.1210,0.0218, 0.0209, 0.0496, 0.0733, 0.0022,0.0081, 0.0421, 0.0253, 0.0717,
|
||||
0.0747,0.0207, 0.0010, 0.0633, 0.0673, 0.0894,0.0268, 0.0106, 0.0183, 0.0019, 0.0172,0.0011]
|
||||
"German": [0.0973]
|
||||
}
|
||||
}
|
||||
In alphabetical order
|
||||
And you're.... Done! Make sure the name of the two match up
|
||||
"""
|
||||
from typing import Dict, Set, Optional, Any
|
||||
import ciphey
|
||||
from string import punctuation
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import string
|
||||
import os
|
||||
import sys
|
||||
from loguru import logger
|
||||
from math import ceil
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import T, registry
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
sys.path.append("..")
|
||||
try:
|
||||
|
@ -71,7 +65,7 @@ except ModuleNotFoundError:
|
|||
|
||||
|
||||
@registry.register
|
||||
class Brandon(ciphey.iface.Checker[str]):
|
||||
class Brandon(Checker[str]):
|
||||
"""
|
||||
Class designed to confirm whether something is **language** based on how many words of **language** appears
|
||||
Call confirmLanguage(text, language)
|
||||
|
@ -104,7 +98,7 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
"""
|
||||
# makes the text unique words and readable
|
||||
text = text.lower()
|
||||
text = self.mh.strip_puncuation(text)
|
||||
text = self.mh.strip_punctuation(text)
|
||||
text = text.split(" ")
|
||||
text = filter(lambda x: len(x) > 2, text)
|
||||
text = set(text)
|
||||
|
@ -112,11 +106,11 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
|
||||
x = []
|
||||
for word in text:
|
||||
# poor mans lemisation
|
||||
# poor mans lemmatisation
|
||||
# removes 's from the dict'
|
||||
if word.endswith("'s"):
|
||||
x.append(word[0:-2])
|
||||
text = self.mh.strip_puncuation(x)
|
||||
text = self.mh.strip_punctuation(x)
|
||||
# turns it all into lowercase and as a set
|
||||
complete = set([word.lower() for word in x])
|
||||
|
||||
|
@ -125,20 +119,20 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
def checker(self, text: str, threshold: float, text_length: int, var: set) -> bool:
|
||||
"""Given text determine if it passes checker
|
||||
|
||||
The checker uses the vairable passed to it. I.E. Stopwords list, 1k words, dictionary
|
||||
The checker uses the variable passed to it. I.E. Stopwords list, 1k words, dictionary
|
||||
|
||||
Args:
|
||||
text -> The text to check
|
||||
threshold -> at what point do we return True? The percentage of text that is in var before we return True
|
||||
text_length -> the length of the text
|
||||
var -> the variable we are checking against. Stopwords list, 1k words list, dictionray list.
|
||||
var -> the variable we are checking against. Stopwords list, 1k words list, dictionary list.
|
||||
Returns:
|
||||
boolean -> True for it passes the test, False for it fails the test."""
|
||||
if text is None:
|
||||
logger.trace(f"Checker's text is None, so returning False")
|
||||
logger.trace("Checker's text is None, so returning False")
|
||||
return False
|
||||
if var is None:
|
||||
logger.trace(f"Checker's input var is None, so returning False")
|
||||
logger.trace("Checker's input var is None, so returning False")
|
||||
return False
|
||||
|
||||
percent = ceil(text_length * threshold)
|
||||
|
@ -179,7 +173,7 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
)
|
||||
return False
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
# Suppresses warning
|
||||
super().__init__(config)
|
||||
self.mh = mh.mathsHelper()
|
||||
|
@ -216,7 +210,6 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
|
||||
length_text = len(text)
|
||||
|
||||
|
||||
what_to_use = {}
|
||||
|
||||
# this code decides what checker / threshold to use
|
||||
|
@ -262,7 +255,7 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
If the length of the text is over the maximum sentence length, use the last checker / threshold
|
||||
Otherwise, traverse the keys backwards until we find a key range that does not fit.
|
||||
So we traverse backwards and see if the sentence length is between current - 1 and current
|
||||
In this way, we find the absolute lowest checker / percentage threshold.
|
||||
In this way, we find the absolute lowest checker / percentage threshold.
|
||||
We traverse backwards because if the text is longer than the max sentence length, we already know.
|
||||
In total, the keys are only 5 items long or so. It is not expensive to move backwards, nor is it expensive to move forwards.
|
||||
|
||||
|
@ -285,29 +278,29 @@ class Brandon(ciphey.iface.Checker[str]):
|
|||
return what_to_use
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ciphey.iface.ParamSpec]]:
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"top1000": ciphey.iface.ParamSpec(
|
||||
"top1000": ParamSpec(
|
||||
desc="A wordlist of the top 1000 words",
|
||||
req=False,
|
||||
default="cipheydists::list::english1000",
|
||||
),
|
||||
"wordlist": ciphey.iface.ParamSpec(
|
||||
"wordlist": ParamSpec(
|
||||
desc="A wordlist of all the words",
|
||||
req=False,
|
||||
default="cipheydists::list::english",
|
||||
),
|
||||
"stopwords": ciphey.iface.ParamSpec(
|
||||
"stopwords": ParamSpec(
|
||||
desc="A wordlist of StopWords",
|
||||
req=False,
|
||||
default="cipheydists::list::englishStopWords",
|
||||
),
|
||||
"threshold": ciphey.iface.ParamSpec(
|
||||
"threshold": ParamSpec(
|
||||
desc="The minimum proportion (between 0 and 1) that must be in the dictionary",
|
||||
req=False,
|
||||
default=0.45,
|
||||
),
|
||||
"phases": ciphey.iface.ParamSpec(
|
||||
"phases": ParamSpec(
|
||||
desc="Language-specific phase thresholds",
|
||||
req=False,
|
||||
default="cipheydists::brandon::english",
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from . import brandon
|
||||
from ciphey.iface import registry, Checker, ParamSpec, T, Config
|
||||
|
||||
import json
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Enttropy(Checker[str]):
|
||||
class Entropy(Checker[str]):
|
||||
|
||||
"""
|
||||
Uses entropy to determine plaintext
|
||||
Uses entropy to determine plaintext
|
||||
"""
|
||||
|
||||
def check(self, text: T) -> Optional[str]:
|
||||
logger.trace(f"Trying entropy checker")
|
||||
logger.trace("Trying entropy checker")
|
||||
pass
|
||||
|
||||
def getExpectedRuntime(self, text: T) -> float:
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
from typing import Optional, Dict, List
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from . import brandon
|
||||
from ciphey.iface import registry, Checker, ParamSpec, T, Config
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
from .regex import RegexList
|
||||
from .brandon import Brandon
|
||||
from .format import JsonChecker
|
||||
from .human import HumanChecker
|
||||
from .regex import RegexList
|
||||
|
||||
|
||||
@registry.register
|
||||
class EzCheck(Checker[str]):
|
||||
"""
|
||||
This object is effectively a prebuilt quorum (with requirement 1) of common patterns, followed by a human check
|
||||
This object is effectively a prebuilt quorum (with requirement 1) of common patterns, followed by a human check
|
||||
"""
|
||||
|
||||
def check(self, text: str) -> Optional[str]:
|
||||
for checker in self.checkers:
|
||||
res = checker.check(text)
|
||||
if res is not None and (self.decider is None or self.decider.check(text)) is not None:
|
||||
if (
|
||||
res is not None
|
||||
and (self.decider is None or self.decider.check(text)) is not None
|
||||
):
|
||||
return res
|
||||
return None
|
||||
|
||||
def getExpectedRuntime(self, text: T) -> float:
|
||||
return sum(i.getExpectedRuntime(text) for i in self.checkers) + self.decider.getExpectedRuntime(text)
|
||||
return sum(
|
||||
i.getExpectedRuntime(text) for i in self.checkers
|
||||
) + self.decider.getExpectedRuntime(text)
|
||||
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
from typing import Optional, Dict, List
|
||||
import json
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from . import brandon
|
||||
from ciphey.iface import registry, Checker, ParamSpec, T, Config
|
||||
|
||||
import json
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class JsonChecker(Checker[str]):
|
||||
|
||||
"""
|
||||
This object is effectively a prebuilt quroum (with requirement 1) of common patterns
|
||||
This object is effectively a prebuilt quorum (with requirement 1) of common patterns
|
||||
"""
|
||||
|
||||
def check(self, text: T) -> Optional[str]:
|
||||
logger.trace(f"Trying json checker")
|
||||
logger.trace("Trying json checker")
|
||||
|
||||
# https://github.com/Ciphey/Ciphey/issues/389
|
||||
if text.isdigit():
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from . import brandon
|
||||
from ciphey.iface import registry, Checker, ParamSpec, T, Config
|
||||
|
||||
import json
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
|
@ -16,7 +13,7 @@ class GTestChecker(Checker[str]):
|
|||
"""
|
||||
|
||||
def check(self, text: T) -> Optional[str]:
|
||||
logger.trace(f"Trying entropy checker")
|
||||
logger.trace("Trying entropy checker")
|
||||
pass
|
||||
|
||||
def getExpectedRuntime(self, text: T) -> float:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import Optional, Dict
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import registry, Checker, Config, ParamSpec
|
||||
from ciphey.iface import Checker, Config, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
|
@ -11,10 +11,10 @@ class HumanChecker(Checker[str]):
|
|||
|
||||
def check(self, text: str) -> Optional[str]:
|
||||
with self._config().pause_spinner_handle():
|
||||
response = input(f'Result {text.__repr__()} (y/N): ').lower()
|
||||
response = input(f"Result {text.__repr__()} (y/N): ").lower()
|
||||
if response == "y":
|
||||
return ""
|
||||
elif response == "n" or response == "":
|
||||
elif response in ("n", ""):
|
||||
return None
|
||||
else:
|
||||
return self.check(text)
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
from math import ceil
|
||||
from typing import Optional, Dict, Generic
|
||||
from typing import Dict, Generic, Optional
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import ParamSpec, Config, T
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, _registry
|
||||
|
||||
|
||||
class Quorum(Generic[T], ciphey.iface.Checker[T]):
|
||||
class Quorum(Generic[T], Checker[T]):
|
||||
def check(self, text: T) -> Optional[str]:
|
||||
left = self._params().k
|
||||
results = []
|
||||
|
@ -32,9 +30,7 @@ class Quorum(Generic[T], ciphey.iface.Checker[T]):
|
|||
self.checkers = []
|
||||
for i in self._params()["checker"]:
|
||||
# This enforces type consistency
|
||||
self.checkers.append(
|
||||
ciphey.iface._registry.get_named(i, ciphey.iface.Checker[T])
|
||||
)
|
||||
self.checkers.append(_registry.get_named(i, Checker[T]))
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict
|
||||
|
||||
import ciphey
|
||||
import re
|
||||
from ciphey.iface import ParamSpec, T, Config, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Checker, Config, ParamSpec, T, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Regex(ciphey.iface.Checker[str]):
|
||||
class Regex(Checker[str]):
|
||||
def getExpectedRuntime(self, text: T) -> float:
|
||||
return 1e-5 # TODO: actually calculate this
|
||||
|
||||
|
@ -37,7 +36,7 @@ class Regex(ciphey.iface.Checker[str]):
|
|||
|
||||
|
||||
@registry.register
|
||||
class RegexList(ciphey.iface.Checker[str]):
|
||||
class RegexList(Checker[str]):
|
||||
def getExpectedRuntime(self, text: T) -> float:
|
||||
return 1e-5 # TODO: actually calculate this
|
||||
|
||||
|
@ -60,6 +59,8 @@ class RegexList(ciphey.iface.Checker[str]):
|
|||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"resource": ParamSpec(
|
||||
req=True, desc="A list of regexes that could be matched", list=True,
|
||||
req=True,
|
||||
desc="A list of regexes that could be matched",
|
||||
list=True,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,114 +0,0 @@
|
|||
# community
|
||||
# by https://github.com/lukasgabriel
|
||||
|
||||
import re
|
||||
from distutils import util
|
||||
from typing import Optional, Dict, Union, Set, List
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import ParamSpec, Cracker, CrackResult, CrackInfo, T, registry, Config
|
||||
|
||||
|
||||
@registry.register
|
||||
class XandY(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
return CrackInfo(
|
||||
success_likelihood=0.1, success_runtime=1e-5, failure_runtime=1e-5,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def binary_to_ascii(variant):
|
||||
# Convert the binary string to an integer with base 2
|
||||
binary_int = int(variant, 2)
|
||||
byte_number = binary_int.bit_length() + 7 // 8
|
||||
|
||||
# Convert the resulting int to a bytearray and then decode it to ascii text
|
||||
binary_array = binary_int.to_bytes(byte_number, "big")
|
||||
try:
|
||||
ascii_text = binary_array.decode()
|
||||
logger.trace(f"Found possible solution: {ascii_text[:32]}...")
|
||||
return ascii_text
|
||||
except UnicodeDecodeError as e:
|
||||
logger.trace(f"X-Y Cracker ecountered UnicodeDecodeError when trying to crack ctext: {e}")
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "XandY"
|
||||
|
||||
def attemptCrack(self, ctext: str) -> List[CrackResult]:
|
||||
"""
|
||||
Checks an input if it only consists of two or three different letters.
|
||||
If this is the case, it attempts to regard those letters as
|
||||
0 and 1 (with the third characters as an optional delimiter) and then
|
||||
converts it to ascii text.
|
||||
"""
|
||||
logger.trace("Attempting X-Y replacement.")
|
||||
variants = []
|
||||
candidates = []
|
||||
result = []
|
||||
|
||||
# Convert the ctext to all-lowercase and regex-match & replace all whitespace
|
||||
ctext = ctext.lower()
|
||||
ctext = re.sub(r"\s+", "", ctext, flags=re.UNICODE)
|
||||
|
||||
# cset contains every unique value in the ctext
|
||||
cset = list(set(list(ctext)))
|
||||
cset_len = len(cset)
|
||||
|
||||
if not 1 < cset_len < 4:
|
||||
# We only consider inputs with two or three unique values
|
||||
logger.trace("String does not contain two or three unique values. Skipping X-Y...")
|
||||
return None
|
||||
|
||||
else:
|
||||
logger.trace(f"String contains {cset_len} unique values: {cset}")
|
||||
|
||||
# In case of three unique values, we regard the least frequent character as the delimiter
|
||||
if cset_len == 3:
|
||||
# Count each unique character in the set to determine the least frequent one
|
||||
counting_list = []
|
||||
for char in cset:
|
||||
counting_list.append(ctext.count(char))
|
||||
val, index = min(
|
||||
(val, index) for (index, val) in enumerate(counting_list)
|
||||
)
|
||||
delimiter = cset[index]
|
||||
logger.trace(
|
||||
f"{delimiter} occurs {val} times and is least frequent character & probable delimiter."
|
||||
)
|
||||
# Remove the delimiter from the ctext and compute new cset
|
||||
ctext = ctext.replace(delimiter, "")
|
||||
cset = list(set(list(ctext)))
|
||||
|
||||
# Form both variants of the substitution
|
||||
for i in range(2):
|
||||
if i:
|
||||
variants.append(ctext.replace(cset[0], "1").replace(cset[1], "0"))
|
||||
else:
|
||||
variants.append(ctext.replace(cset[0], "0").replace(cset[1], "1"))
|
||||
|
||||
# Apply function to both variants and strip stray NULL characters
|
||||
for variant in variants:
|
||||
candidates.append(self.binary_to_ascii(variant).strip("\x00"))
|
||||
for i, candidate in enumerate(candidates):
|
||||
if candidate != "":
|
||||
keyinfo = f"{cset[0]} -> {i} & {cset[1]} -> {str(int(not i))}"
|
||||
result.append(CrackResult(value=candidate, key_info=keyinfo))
|
||||
logger.trace(f"X-Y cracker - Returning results: {result}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.cache = config.cache
|
|
@ -1,5 +1,5 @@
|
|||
from . import (
|
||||
XandY,
|
||||
xandy,
|
||||
affine,
|
||||
ascii_shift,
|
||||
caesar,
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import ciphey
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.common import fix_case
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
from ciphey.mathsHelper import mathsHelper
|
||||
from loguru import logger
|
||||
|
||||
|
||||
@registry.register
|
||||
|
@ -44,24 +44,24 @@ class Affine(Cracker[str]):
|
|||
# a and b are coprime if gcd(a,b) is 1.
|
||||
possible_a = [
|
||||
a
|
||||
for a in range(1, self.ALPHABET_LENGTH)
|
||||
if mathsHelper.gcd(a, self.ALPHABET_LENGTH) == 1
|
||||
for a in range(1, self.alphabet_length)
|
||||
if mathsHelper.gcd(a, self.alphabet_length) == 1
|
||||
]
|
||||
logger.debug(
|
||||
f"Trying Affine Cracker with {len(possible_a)} a-values and {self.ALPHABET_LENGTH} b-values"
|
||||
f"Trying Affine Cracker with {len(possible_a)} a-values and {self.alphabet_length} b-values"
|
||||
)
|
||||
|
||||
for a in possible_a:
|
||||
a_inv = mathsHelper.mod_inv(a, self.ALPHABET_LENGTH)
|
||||
a_inv = mathsHelper.mod_inv(a, self.alphabet_length)
|
||||
# If there is no inverse, we cannot decrypt the text
|
||||
if a_inv is None:
|
||||
continue
|
||||
for b in range(self.ALPHABET_LENGTH):
|
||||
for b in range(self.alphabet_length):
|
||||
# Pass in lowered text. This means that we expect alphabets to not contain both 'a' and 'A'.
|
||||
translated = self.decrypt(ctext.lower(), a_inv, b, self.ALPHABET_LENGTH)
|
||||
translated = self.decrypt(ctext.lower(), a_inv, b, self.alphabet_length)
|
||||
|
||||
candidate_probability = self.plaintext_probability(translated)
|
||||
if candidate_probability > self.PLAINTEXT_PROB_THRESHOLD:
|
||||
if candidate_probability > self.plaintext_prob_threshold:
|
||||
candidates.append(
|
||||
CrackResult(
|
||||
value=fix_case(translated, ctext), key_info=f"a={a}, b={b}"
|
||||
|
@ -108,7 +108,7 @@ class Affine(Cracker[str]):
|
|||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"group": ciphey.iface.ParamSpec(
|
||||
"group": ParamSpec(
|
||||
desc="An ordered sequence of chars that make up the alphabet",
|
||||
req=False,
|
||||
default="abcdefghijklmnopqrstuvwxyz",
|
||||
|
@ -119,6 +119,6 @@ class Affine(Cracker[str]):
|
|||
super().__init__(config)
|
||||
self.group = list(self._params()["group"])
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.ALPHABET_LENGTH = len(self.group)
|
||||
self.alphabet_length = len(self.group)
|
||||
self.cache = config.cache
|
||||
self.PLAINTEXT_PROB_THRESHOLD = 0.01
|
||||
self.plaintext_prob_threshold = 0.01
|
||||
|
|
|
@ -8,19 +8,16 @@
|
|||
Github: brandonskerritt
|
||||
"""
|
||||
|
||||
from typing import Optional, Dict, Union, Set, List, Tuple
|
||||
|
||||
from ciphey.iface import ParamSpec, CrackResult, T, CrackInfo, registry
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Ascii_shift(ciphey.iface.Cracker[str]):
|
||||
class Ascii_shift(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
|
@ -77,17 +74,17 @@ class Ascii_shift(ciphey.iface.Cracker[str]):
|
|||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"group": ciphey.iface.ParamSpec(
|
||||
"group": ParamSpec(
|
||||
desc="An ordered sequence of chars that make up the ASCII shift cipher alphabet",
|
||||
req=False,
|
||||
default="""\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f""",
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for standard frequency analysis",
|
||||
req=False,
|
||||
default=0.01,
|
||||
|
@ -95,7 +92,7 @@ class Ascii_shift(ciphey.iface.Cracker[str]):
|
|||
# TODO: add "filter" param
|
||||
}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.group = list(self._params()["group"])
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
|
|
|
@ -7,20 +7,18 @@
|
|||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
"""
|
||||
import sys
|
||||
from distutils import util
|
||||
from typing import Optional, Dict, Union, Set, List, Tuple
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
from loguru import logger
|
||||
import ciphey
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import ParamSpec, CrackResult, T, CrackInfo, registry
|
||||
from ciphey.common import fix_case
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Caesar(ciphey.iface.Cracker[str]):
|
||||
class Caesar(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
|
@ -66,7 +64,7 @@ class Caesar(ciphey.iface.Cracker[str]):
|
|||
logger.debug(f"Caesar returned {n_candidates} candidates")
|
||||
|
||||
if n_candidates == 0:
|
||||
logger.trace(f"Filtering for better results")
|
||||
logger.trace("Filtering for better results")
|
||||
analysis = cipheycore.analyse_string(ctext, self.group)
|
||||
possible_keys = cipheycore.caesar_crack(
|
||||
analysis, self.expected, self.group, self.p_value
|
||||
|
@ -77,29 +75,31 @@ class Caesar(ciphey.iface.Cracker[str]):
|
|||
for candidate in possible_keys:
|
||||
logger.trace(f"Candidate {candidate.key} has prob {candidate.p_value}")
|
||||
translated = cipheycore.caesar_decrypt(message, candidate.key, self.group)
|
||||
candidates.append(CrackResult(value=fix_case(translated, ctext), key_info=candidate.key))
|
||||
candidates.append(
|
||||
CrackResult(value=fix_case(translated, ctext), key_info=candidate.key)
|
||||
)
|
||||
|
||||
return candidates
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"group": ciphey.iface.ParamSpec(
|
||||
"group": ParamSpec(
|
||||
desc="An ordered sequence of chars that make up the caesar cipher alphabet",
|
||||
req=False,
|
||||
default="abcdefghijklmnopqrstuvwxyz",
|
||||
),
|
||||
"lower": ciphey.iface.ParamSpec(
|
||||
"lower": ParamSpec(
|
||||
desc="Whether or not the ciphertext should be converted to lowercase first",
|
||||
req=False,
|
||||
default=True,
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for standard frequency analysis",
|
||||
req=False,
|
||||
default=0.01,
|
||||
|
@ -107,10 +107,10 @@ class Caesar(ciphey.iface.Cracker[str]):
|
|||
# TODO: add "filter" param
|
||||
}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.lower: Union[str, bool] = self._params()["lower"]
|
||||
if type(self.lower) != bool:
|
||||
if not isinstance(self.lower, bool):
|
||||
self.lower = util.strtobool(self.lower)
|
||||
self.group = list(self._params()["group"])
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
"""
|
||||
his is Hashbuster but slightly modified to work with Ciphey
|
||||
why reivent the wheel?
|
||||
This is Hashbuster but slightly modified to work with Ciphey.
|
||||
Why reinvent the wheel?
|
||||
Changes (that I can remember)
|
||||
* timeout set, as hashbuster took AGES before timeout was set.
|
||||
https://github.com/s0md3v/Hash-Buster
|
||||
"""
|
||||
|
||||
|
||||
import re
|
||||
import os
|
||||
import argparse
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import requests
|
||||
import concurrent.futures
|
||||
|
||||
from loguru import logger
|
||||
from typing import Optional, Dict, Union, Set, List, Any
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import ParamSpec, CrackResult, T, CrackInfo, registry
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, T, registry
|
||||
|
||||
thread_count = 4
|
||||
|
||||
|
@ -38,8 +31,7 @@ def beta(ctext, hashtype):
|
|||
match = re.search(r'/generate-hash/?text=.*?"', response)
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def gamma(ctext, hashtype):
|
||||
|
@ -85,7 +77,7 @@ result = {}
|
|||
|
||||
|
||||
def crack(ctext):
|
||||
raise ("Error Crack is called")
|
||||
raise "Error Crack is called"
|
||||
|
||||
|
||||
def threaded(ctext):
|
||||
|
@ -96,14 +88,14 @@ def threaded(ctext):
|
|||
|
||||
|
||||
@registry.register
|
||||
class HashBuster(ciphey.iface.Cracker[str]):
|
||||
class HashBuster(Cracker[str]):
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "hash"
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, Dict[str, Any]]]:
|
||||
pass
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def priority() -> float:
|
||||
|
@ -111,10 +103,14 @@ class HashBuster(ciphey.iface.Cracker[str]):
|
|||
|
||||
def getInfo(self, ctext: T) -> CrackInfo:
|
||||
# TODO calculate these properly
|
||||
return CrackInfo(success_likelihood=0.5, success_runtime=5, failure_runtime=5,)
|
||||
return CrackInfo(
|
||||
success_likelihood=0.5,
|
||||
success_runtime=5,
|
||||
failure_runtime=5,
|
||||
)
|
||||
|
||||
def attemptCrack(self, ctext: T) -> List[CrackResult]:
|
||||
logger.debug(f"Starting to crack hashes")
|
||||
logger.debug("Starting to crack hashes")
|
||||
result = False
|
||||
|
||||
candidates = []
|
||||
|
@ -154,5 +150,5 @@ class HashBuster(ciphey.iface.Cracker[str]):
|
|||
# TODO add to 5.1 make this return multiple possible candidates
|
||||
return [CrackResult(value=candidates[0][0], misc_info=candidates[1][1])]
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
|
|
@ -8,19 +8,16 @@
|
|||
Github: brandonskerritt
|
||||
"""
|
||||
|
||||
from typing import Optional, Dict, Union, Set, List, Tuple
|
||||
|
||||
from ciphey.iface import ParamSpec, CrackResult, T, CrackInfo, registry
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Rot47(ciphey.iface.Cracker[str]):
|
||||
class Rot47(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
|
@ -77,17 +74,17 @@ class Rot47(ciphey.iface.Cracker[str]):
|
|||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"group": ciphey.iface.ParamSpec(
|
||||
"group": ParamSpec(
|
||||
desc="An ordered sequence of chars that make up the ROT47 cipher alphabet",
|
||||
req=False,
|
||||
default="""!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""",
|
||||
default="""!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~""",
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for standard frequency analysis",
|
||||
req=False,
|
||||
default=0.01,
|
||||
|
@ -95,7 +92,7 @@ class Rot47(ciphey.iface.Cracker[str]):
|
|||
# TODO: add "filter" param
|
||||
}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.group = list(self._params()["group"])
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
|
|
|
@ -7,28 +7,26 @@
|
|||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
"""
|
||||
from copy import copy
|
||||
from distutils import util
|
||||
from typing import Optional, Dict, Union, Set, List
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
import re
|
||||
|
||||
from loguru import logger
|
||||
import ciphey
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import ParamSpec, Cracker, CrackResult, T, CrackInfo, registry
|
||||
from ciphey.common import fix_case
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Vigenere(ciphey.iface.Cracker[str]):
|
||||
class Vigenere(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
if self.keysize is not None:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::{self.keysize}",
|
||||
lambda: cipheycore.analyse_string(ctext.lower(), self.keysize, self.group),
|
||||
lambda: cipheycore.analyse_string(
|
||||
ctext.lower(), self.keysize, self.group
|
||||
),
|
||||
)
|
||||
|
||||
val = cipheycore.vigenere_detect(analysis, self.expected)
|
||||
|
@ -44,13 +42,14 @@ class Vigenere(ciphey.iface.Cracker[str]):
|
|||
|
||||
likely_lens = self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::likely_lens",
|
||||
lambda: cipheycore.vigenere_likely_key_lens(ctext.lower(), self.expected, self.group, self.detect_p_value),
|
||||
"vigenere::likely_lens",
|
||||
lambda: cipheycore.vigenere_likely_key_lens(
|
||||
ctext.lower(), self.expected, self.group, self.detect_p_value
|
||||
),
|
||||
)
|
||||
|
||||
likely_lens_cpy = likely_lens
|
||||
# Filter out the lens that make no sense
|
||||
likely_lens = [i for i in likely_lens if i.len <= self.MAX_KEY_LENGTH]
|
||||
likely_lens = [i for i in likely_lens if i.len <= self.max_key_length]
|
||||
|
||||
for keysize in likely_lens:
|
||||
# Store the analysis
|
||||
|
@ -65,7 +64,9 @@ class Vigenere(ciphey.iface.Cracker[str]):
|
|||
failure_runtime=2e-2,
|
||||
)
|
||||
|
||||
logger.debug(f"Vigenere has likelihood {likely_lens[0].p_value} with lens {[i.len for i in likely_lens]}")
|
||||
logger.debug(
|
||||
f"Vigenere has likelihood {likely_lens[0].p_value} with lens {[i.len for i in likely_lens]}"
|
||||
)
|
||||
|
||||
return CrackInfo(
|
||||
success_likelihood=likely_lens[0].p_value,
|
||||
|
@ -85,15 +86,18 @@ class Vigenere(ciphey.iface.Cracker[str]):
|
|||
analysis, self.expected, self.group, self.p_value
|
||||
)
|
||||
if len(possible_keys) > self.clamp:
|
||||
possible_keys = possible_keys[:self.clamp]
|
||||
possible_keys = possible_keys[: self.clamp]
|
||||
logger.trace(
|
||||
f"Vigenere crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}"
|
||||
)
|
||||
return [
|
||||
CrackResult(
|
||||
value=fix_case(cipheycore.vigenere_decrypt(ctext, candidate.key, self.group), real_ctext),
|
||||
value=fix_case(
|
||||
cipheycore.vigenere_decrypt(ctext, candidate.key, self.group),
|
||||
real_ctext,
|
||||
),
|
||||
key_info="".join([self.group[i] for i in candidate.key]),
|
||||
misc_info=f"p-value was {candidate.p_value}"
|
||||
misc_info=f"p-value was {candidate.p_value}",
|
||||
)
|
||||
for candidate in possible_keys[: min(len(possible_keys), 10)]
|
||||
]
|
||||
|
@ -113,80 +117,84 @@ class Vigenere(ciphey.iface.Cracker[str]):
|
|||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::{self.keysize}",
|
||||
lambda: cipheycore.analyse_string(message, self.keysize, self.group),
|
||||
lambda: cipheycore.analyse_string(
|
||||
message, self.keysize, self.group
|
||||
),
|
||||
),
|
||||
ctext
|
||||
)
|
||||
else:
|
||||
arrs = []
|
||||
likely_lens = self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::likely_lens",
|
||||
lambda: cipheycore.vigenere_likely_key_lens(message, self.expected, self.group),
|
||||
)
|
||||
possible_lens = [i for i in likely_lens]
|
||||
possible_lens.sort(key=lambda i: i.p_value)
|
||||
logger.trace(f"Got possible lengths {[i.len for i in likely_lens]}")
|
||||
# TODO: work out length
|
||||
for i in possible_lens:
|
||||
arrs.extend(
|
||||
self.crackOne(
|
||||
message,
|
||||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::{i.len}",
|
||||
lambda: cipheycore.analyse_string(message, i.len, self.group),
|
||||
),
|
||||
ctext
|
||||
)
|
||||
)
|
||||
|
||||
logger.debug(f"Vigenere returned {len(arrs)} candidates")
|
||||
return arrs
|
||||
arrs = []
|
||||
likely_lens = self.cache.get_or_update(
|
||||
ctext,
|
||||
"vigenere::likely_lens",
|
||||
lambda: cipheycore.vigenere_likely_key_lens(
|
||||
message, self.expected, self.group
|
||||
),
|
||||
)
|
||||
possible_lens = [i for i in likely_lens]
|
||||
possible_lens.sort(key=lambda i: i.p_value)
|
||||
logger.trace(f"Got possible lengths {[i.len for i in likely_lens]}")
|
||||
# TODO: work out length
|
||||
for i in possible_lens:
|
||||
arrs.extend(
|
||||
self.crackOne(
|
||||
message,
|
||||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"vigenere::{i.len}",
|
||||
lambda: cipheycore.analyse_string(message, i.len, self.group),
|
||||
),
|
||||
ctext,
|
||||
)
|
||||
)
|
||||
|
||||
logger.debug(f"Vigenere returned {len(arrs)} candidates")
|
||||
return arrs
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"group": ciphey.iface.ParamSpec(
|
||||
"group": ParamSpec(
|
||||
desc="An ordered sequence of chars that make up the caesar cipher alphabet",
|
||||
req=False,
|
||||
default="abcdefghijklmnopqrstuvwxyz",
|
||||
),
|
||||
"lower": ciphey.iface.ParamSpec(
|
||||
"lower": ParamSpec(
|
||||
desc="Whether or not the ciphertext should be converted to lowercase first",
|
||||
req=False,
|
||||
default=True,
|
||||
),
|
||||
"keysize": ciphey.iface.ParamSpec(
|
||||
"keysize": ParamSpec(
|
||||
desc="A key size that should be used. If not given, will attempt to work it out",
|
||||
req=False,
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for windowed frequency analysis",
|
||||
req=False,
|
||||
default=0.5,
|
||||
),
|
||||
"detect_p_value": ciphey.iface.ParamSpec(
|
||||
"detect_p_value": ParamSpec(
|
||||
desc="The p-value to use for the detection of Vigenere length",
|
||||
req=False,
|
||||
default=0.01,
|
||||
),
|
||||
"clamp": ciphey.iface.ParamSpec(
|
||||
"clamp": ParamSpec(
|
||||
desc="The maximum number of candidates that can be returned per key len",
|
||||
req=False,
|
||||
default=10,
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.lower: Union[str, bool] = self._params()["lower"]
|
||||
if type(self.lower) != bool:
|
||||
if not isinstance(self.lower, bool):
|
||||
self.lower = util.strtobool(self.lower)
|
||||
self.group = list(self._params()["group"])
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
|
@ -197,4 +205,4 @@ class Vigenere(ciphey.iface.Cracker[str]):
|
|||
self.p_value = float(self._params()["p_value"])
|
||||
self.detect_p_value = float(self._params()["detect_p_value"])
|
||||
self.clamp = int(self._params()["clamp"])
|
||||
self.MAX_KEY_LENGTH = 16
|
||||
self.max_key_length = 16
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import re
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Xandy(Cracker[str]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
return CrackInfo(
|
||||
success_likelihood=0.1,
|
||||
success_runtime=1e-5,
|
||||
failure_runtime=1e-5,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def binary_to_ascii(variant):
|
||||
# Convert the binary string to an integer with base 2
|
||||
binary_int = int(variant, 2)
|
||||
byte_number = binary_int.bit_length() + 7 // 8
|
||||
|
||||
# Convert the resulting int to a bytearray and then decode it to ASCII text
|
||||
binary_array = binary_int.to_bytes(byte_number, "big")
|
||||
try:
|
||||
ascii_text = binary_array.decode()
|
||||
logger.trace(f"Found possible solution: {ascii_text[:32]}")
|
||||
return ascii_text
|
||||
except UnicodeDecodeError as e:
|
||||
logger.trace(f"Failed to crack X-Y due to a UnicodeDecodeError: {e}")
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "xandy"
|
||||
|
||||
def attemptCrack(self, ctext: str) -> List[CrackResult]:
|
||||
"""
|
||||
Checks an input if it only consists of two or three different letters.
|
||||
If this is the case, it attempts to regard those letters as
|
||||
0 and 1 (with the third characters as an optional delimiter) and then
|
||||
converts it to ASCII text.
|
||||
"""
|
||||
logger.trace("Attempting X-Y replacement")
|
||||
variants = []
|
||||
candidates = []
|
||||
result = []
|
||||
|
||||
# Convert the ctext to all-lowercase and regex-match & replace all whitespace
|
||||
ctext = re.sub(r"\s+", "", ctext.lower(), flags=re.UNICODE)
|
||||
|
||||
# cset contains every unique value in the ctext
|
||||
cset = list(set(list(ctext)))
|
||||
cset_len = len(cset)
|
||||
|
||||
if not 1 < cset_len < 4:
|
||||
# We only consider inputs with two or three unique values
|
||||
logger.trace(
|
||||
"Failed to crack X-Y due to not containing two or three unique values"
|
||||
)
|
||||
return None
|
||||
|
||||
logger.trace(f"String contains {cset_len} unique values: {cset}")
|
||||
|
||||
# In case of three unique values, we regard the least frequent character as the delimiter
|
||||
if cset_len == 3:
|
||||
# Count each unique character in the set to determine the least frequent one
|
||||
counting_list = []
|
||||
for char in cset:
|
||||
counting_list.append(ctext.count(char))
|
||||
val, index = min((val, index) for (index, val) in enumerate(counting_list))
|
||||
delimiter = cset[index]
|
||||
logger.trace(
|
||||
f"{delimiter} occurs {val} times and is the probable delimiter"
|
||||
)
|
||||
# Remove the delimiter from the ctext and compute new cset
|
||||
ctext = ctext.replace(delimiter, "")
|
||||
cset = list(set(list(ctext)))
|
||||
|
||||
# Form both variants of the substitution
|
||||
for i in range(2):
|
||||
if i:
|
||||
variants.append(ctext.replace(cset[0], "1").replace(cset[1], "0"))
|
||||
else:
|
||||
variants.append(ctext.replace(cset[0], "0").replace(cset[1], "1"))
|
||||
|
||||
# Apply function to both variants and strip stray NULL characters
|
||||
for variant in variants:
|
||||
candidates.append(self.binary_to_ascii(variant).strip("\x00"))
|
||||
for i, candidate in enumerate(candidates):
|
||||
if candidate != "":
|
||||
keyinfo = f"{cset[0]} -> {i} & {cset[1]} -> {str(int(not i))}"
|
||||
result.append(CrackResult(value=candidate, key_info=keyinfo))
|
||||
logger.trace(f"X-Y cracker - Returning results: {result}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.cache = config.cache
|
|
@ -7,18 +7,16 @@
|
|||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
"""
|
||||
import sys
|
||||
from distutils import util
|
||||
from typing import Optional, Dict, Union, Set, List, Tuple
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
import ciphey
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
from ciphey.iface import ParamSpec, CrackResult, T, CrackInfo, registry
|
||||
|
||||
@registry.register
|
||||
class XorSingle(ciphey.iface.Cracker[bytes]):
|
||||
class XorSingle(Cracker[bytes]):
|
||||
def getInfo(self, ctext: str) -> CrackInfo:
|
||||
analysis = self.cache.get_or_update(
|
||||
ctext,
|
||||
|
@ -72,12 +70,12 @@ class XorSingle(ciphey.iface.Cracker[bytes]):
|
|||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for standard frequency analysis",
|
||||
req=False,
|
||||
default=0.01,
|
||||
|
@ -86,10 +84,10 @@ class XorSingle(ciphey.iface.Cracker[bytes]):
|
|||
}
|
||||
|
||||
@staticmethod
|
||||
def scoreUtility() -> float:
|
||||
def score_utility() -> float:
|
||||
return 1.5
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.cache = config.cache
|
||||
|
|
|
@ -7,22 +7,17 @@
|
|||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
"""
|
||||
from copy import copy
|
||||
from distutils import util
|
||||
from typing import Optional, Dict, Union, Set, List
|
||||
|
||||
import re
|
||||
import base64
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
import ciphey
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import ParamSpec, Cracker, CrackResult, T, CrackInfo, registry
|
||||
from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class XorCrypt(ciphey.iface.Cracker[bytes]):
|
||||
class XorCrypt(Cracker[bytes]):
|
||||
def getInfo(self, ctext: bytes) -> CrackInfo:
|
||||
if self.keysize is not None:
|
||||
analysis = self.cache.get_or_update(
|
||||
|
@ -40,7 +35,7 @@ class XorCrypt(ciphey.iface.Cracker[bytes]):
|
|||
|
||||
keysize = self.cache.get_or_update(
|
||||
ctext,
|
||||
f"xorcrypt::likely_lens",
|
||||
"xorcrypt::likely_lens",
|
||||
lambda: cipheycore.xorcrypt_guess_len(ctext),
|
||||
)
|
||||
|
||||
|
@ -53,7 +48,7 @@ class XorCrypt(ciphey.iface.Cracker[bytes]):
|
|||
)
|
||||
|
||||
return CrackInfo(
|
||||
success_likelihood=0.9, # Dunno, but it's quite likely
|
||||
success_likelihood=0.9, # Dunno, but it's quite likely
|
||||
# TODO: actually calculate runtimes
|
||||
success_runtime=2e-3,
|
||||
failure_runtime=2e-2,
|
||||
|
@ -66,17 +61,17 @@ class XorCrypt(ciphey.iface.Cracker[bytes]):
|
|||
def crackOne(
|
||||
self, ctext: bytes, analysis: cipheycore.windowed_analysis_res
|
||||
) -> List[CrackResult]:
|
||||
possible_keys = cipheycore.xorcrypt_crack(
|
||||
analysis, self.expected, self.p_value
|
||||
)
|
||||
possible_keys = cipheycore.xorcrypt_crack(analysis, self.expected, self.p_value)
|
||||
|
||||
logger.trace(f"xorcrypt crack got keys: {[[i for i in candidate.key] for candidate in possible_keys]}")
|
||||
logger.trace(
|
||||
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)]
|
||||
for candidate in possible_keys[: min(len(possible_keys), 10)]
|
||||
]
|
||||
|
||||
def attemptCrack(self, ctext: bytes) -> List[CrackResult]:
|
||||
|
@ -92,52 +87,52 @@ class XorCrypt(ciphey.iface.Cracker[bytes]):
|
|||
lambda: cipheycore.analyse_bytes(ctext, self.keysize),
|
||||
),
|
||||
)
|
||||
else:
|
||||
len = self.cache.get_or_update(
|
||||
|
||||
len = self.cache.get_or_update(
|
||||
ctext,
|
||||
"xorcrypt::likely_lens",
|
||||
lambda: cipheycore.xorcrypt_guess_len(ctext),
|
||||
)
|
||||
|
||||
logger.trace(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,
|
||||
f"xorcrypt::likely_lens",
|
||||
lambda: cipheycore.xorcrypt_guess_len(ctext),
|
||||
self.cache.get_or_update(
|
||||
ctext,
|
||||
f"xorcrypt::{len}",
|
||||
lambda: cipheycore.analyse_bytes(ctext, len),
|
||||
),
|
||||
)
|
||||
|
||||
logger.trace(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
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"expected": ciphey.iface.ParamSpec(
|
||||
"expected": ParamSpec(
|
||||
desc="The expected distribution of the plaintext",
|
||||
req=False,
|
||||
config_ref=["default_dist"],
|
||||
),
|
||||
"keysize": ciphey.iface.ParamSpec(
|
||||
"keysize": ParamSpec(
|
||||
desc="A key size that should be used. If not given, will attempt to work it out",
|
||||
req=False,
|
||||
),
|
||||
"p_value": ciphey.iface.ParamSpec(
|
||||
"p_value": ParamSpec(
|
||||
desc="The p-value to use for windowed frequency analysis",
|
||||
req=False,
|
||||
default=0.001,
|
||||
),
|
||||
}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.expected = config.get_resource(self._params()["expected"])
|
||||
self.cache = config.cache
|
||||
|
@ -145,4 +140,4 @@ class XorCrypt(ciphey.iface.Cracker[bytes]):
|
|||
if self.keysize is not None:
|
||||
self.keysize = int(self.keysize)
|
||||
self.p_value = self._params()["p_value"]
|
||||
self.MAX_KEY_LENGTH = 16
|
||||
self.max_key_length = 16
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
from . import (
|
||||
morse,
|
||||
bases,
|
||||
unicode,
|
||||
reverse,
|
||||
octal,
|
||||
binary,
|
||||
hexadecimal,
|
||||
atbash,
|
||||
galactic,
|
||||
base62,
|
||||
base58,
|
||||
base58_bitcoin,
|
||||
base58_ripple,
|
||||
base91,
|
||||
leet,
|
||||
decimal,
|
||||
base62,
|
||||
base69,
|
||||
base91,
|
||||
bases,
|
||||
baudot,
|
||||
multi_tap,
|
||||
url,
|
||||
tap_code,
|
||||
binary,
|
||||
brainfuck,
|
||||
decimal,
|
||||
galactic,
|
||||
hexadecimal,
|
||||
leetspeak,
|
||||
morse_code,
|
||||
multi_tap,
|
||||
octal,
|
||||
reverse,
|
||||
tap_code,
|
||||
unicode,
|
||||
url,
|
||||
uuencode,
|
||||
)
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
import re
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import re
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class A1z26(Decoder[str, str]):
|
||||
class A1z26(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs A1Z26 decoding
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
# community
|
||||
# by https://github.com/lukasgabriel
|
||||
from typing import Dict, Optional
|
||||
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, WordList
|
||||
from ciphey.common import fix_case
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Atbash(Decoder[str, str]):
|
||||
class Atbash(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Takes an encoded string and attempts to decode it according to the Atbash cipher.
|
||||
|
||||
The Atbash cipher is a very simple substitution cipher without a key.
|
||||
It operates by replacing every letter in the input by its 'counterpoint'
|
||||
in the alphabet. Example: A -> Z, B -> Y, ... , M -> N and vice versa.
|
||||
The Atbash cipher is a very simple substitution cipher without a key.
|
||||
It operates by replacing every letter in the input by its 'counterpoint'
|
||||
in the alphabet. Example: A -> Z, B -> Y, ... , M -> N and vice versa.
|
||||
"""
|
||||
|
||||
result = ""
|
||||
|
@ -27,7 +24,7 @@ class Atbash(Decoder[str, str]):
|
|||
result += atbash_dict[letter]
|
||||
else:
|
||||
# If the current character is not in the defined alphabet,
|
||||
# just accept it as-is (useful for numbers, punctuation,...)
|
||||
# just accept it as-is (useful for numbers, punctuation, etc.)
|
||||
result += letter
|
||||
return fix_case(result, ctext)
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base58
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base58(Decoder[str, str]):
|
||||
class Base58_bitcoin(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base62 decoding
|
||||
Performs Base58 (Bitcoin) decoding
|
||||
"""
|
||||
try:
|
||||
return base58.b58decode(ctext).decode("utf-8")
|
||||
|
@ -30,4 +30,4 @@ class Base58(Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "base58"
|
||||
return "base58_bitcoin"
|
|
@ -1,12 +1,12 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base58
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base58_flickr(Decoder[str, str]):
|
||||
class Base58_flickr(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base58 (Flickr) decoding
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base58
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base58_ripple(Decoder[str, str]):
|
||||
class Base58_ripple(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base62 decoding
|
||||
Performs Base58 (Ripple) decoding
|
||||
"""
|
||||
try:
|
||||
return base58.b58decode(ctext, alphabet=base58.RIPPLE_ALPHABET).decode(
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base62
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base62(Decoder[str, str]):
|
||||
class Base62(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base62 decoding
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
|
||||
import base64
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base64_url(Decoder[str, str]):
|
||||
class Base64_url(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base64 URL decoding
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base65536
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base65536(Decoder[str, str]):
|
||||
class Base65536(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base65536 decoding
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
# by https://github.com/lukasgabriel
|
||||
# translated to Python and adapted for Ciphey from the JS original at https://github.com/pshihn/base69
|
||||
# Translated to Python and adapted for Ciphey from the JS original at https://github.com/pshihn/base69
|
||||
|
||||
|
||||
import re
|
||||
from math import ceil
|
||||
from typing import Dict, Optional
|
||||
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, WordList
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base69(Decoder[str, str]):
|
||||
class Base69(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base69 decoding
|
||||
|
@ -39,7 +37,7 @@ class Base69(Decoder[str, str]):
|
|||
for n, elem in enumerate(insert):
|
||||
result[n + i * 7] = elem % 256
|
||||
return bytearray(result).decode().strip("\x00")
|
||||
except:
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def decode_chunk(self, s: str):
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
import base91
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Base91(Decoder[str, str]):
|
||||
class Base91(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Base91 decoding
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import base64
|
||||
import types
|
||||
|
||||
import ciphey
|
||||
from typing import Callable, Optional, Any, Dict
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.common import id_lambda
|
||||
from ciphey.iface import Decoder, registry
|
||||
|
||||
|
||||
def _dispatch(self: Any, ctext: str, func: Callable[[str], bytes]) -> Optional[bytes]:
|
||||
logger.trace(f"Attempting {self.getTarget()}")
|
||||
|
@ -29,19 +30,19 @@ _bases = {
|
|||
|
||||
|
||||
def gen_class(name, decoder, priority, ns):
|
||||
ns["_get_func"] = ciphey.common.id_lambda(decoder)
|
||||
ns["_get_func"] = id_lambda(decoder)
|
||||
ns["decode"] = lambda self, ctext: _dispatch(self, ctext, self._get_func())
|
||||
ns["getParams"] = ciphey.common.id_lambda(None)
|
||||
ns["getTarget"] = ciphey.common.id_lambda(name)
|
||||
ns["priority"] = ciphey.common.id_lambda(priority)
|
||||
ns["getParams"] = id_lambda(None)
|
||||
ns["getTarget"] = id_lambda(name)
|
||||
ns["priority"] = id_lambda(priority)
|
||||
ns["__init__"] = lambda self, config: super(type(self), self).__init__(config)
|
||||
|
||||
|
||||
for name, (decoder, priority) in _bases.items():
|
||||
t = types.new_class(
|
||||
name,
|
||||
(ciphey.iface.Decoder[str, bytes],),
|
||||
(Decoder[str],),
|
||||
exec_body=lambda x: gen_class(name, decoder, priority, x),
|
||||
)
|
||||
|
||||
ciphey.iface.registry.register(t)
|
||||
registry.register(t)
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import re
|
||||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import ParamSpec, Config, T, U, Decoder, registry, Translation
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
@registry.register_multi((str, str), (bytes, bytes))
|
||||
class Baudot(Decoder[str, str]):
|
||||
|
||||
@registry.register
|
||||
class Baudot(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
ret = ""
|
||||
result = ""
|
||||
switch_to_digit_map = 0
|
||||
if type(ctext) == str:
|
||||
if re.search("^[01]{5}$", ctext.split()[0]):
|
||||
for i in ctext.split():
|
||||
if i == "11011":
|
||||
switch_to_digit_map = 1
|
||||
if i == "11111":
|
||||
switch_to_digit_map = 0
|
||||
if switch_to_digit_map == 1:
|
||||
ret += self.BAUDOT_DICT["+" + i]
|
||||
if switch_to_digit_map == 0:
|
||||
ret += self.BAUDOT_DICT[i]
|
||||
return ret
|
||||
if re.search("^[01]{5}$", ctext.split()[0]):
|
||||
for i in ctext.split():
|
||||
if i == "11011":
|
||||
switch_to_digit_map = 1
|
||||
if i == "11111":
|
||||
switch_to_digit_map = 0
|
||||
if switch_to_digit_map == 1:
|
||||
result += self.BAUDOT_DICT["+" + i]
|
||||
if switch_to_digit_map == 0:
|
||||
result += self.BAUDOT_DICT[i]
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
from typing import Optional, Dict, Any, List
|
||||
import re
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import registry
|
||||
|
||||
import re
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Binary(ciphey.iface.Decoder[str, bytes]):
|
||||
def decode(self, text: str) -> Optional[bytes]:
|
||||
class Binary(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
try:
|
||||
text = re.sub(r"[^\S \n]", " ", text, flags=re.UNICODE)
|
||||
text = text.replace("\n", " ")
|
||||
ctext = re.sub(r"[^\S \n]", " ", ctext, flags=re.UNICODE)
|
||||
ctext = ctext.replace("\n", " ")
|
||||
|
||||
existing_split = self.try_split(text.split(" "))
|
||||
existing_split = self.try_split(ctext.split(" "))
|
||||
if existing_split is not None:
|
||||
return existing_split
|
||||
|
||||
# Now we try our own grouping
|
||||
|
||||
# Remove final bit of whitespace
|
||||
text = text.replace(" ", "")
|
||||
ctext = ctext.replace(" ", "")
|
||||
# Split into bytes, and test
|
||||
return self.try_split([text[i : i + 8] for i in range(0, len(text), 8)])
|
||||
return self.try_split([ctext[i : i + 8] for i in range(0, len(ctext), 8)])
|
||||
# Catch bad octal chars
|
||||
except ValueError:
|
||||
return None
|
||||
|
@ -49,12 +47,12 @@ class Binary(ciphey.iface.Decoder[str, bytes]):
|
|||
def priority() -> float:
|
||||
return 0.3
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, Dict[str, Any]]]:
|
||||
pass
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
from typing import Optional, Dict, List, Tuple
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, WordList
|
||||
import re
|
||||
import time
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import re
|
||||
|
||||
import time
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Brainfuck(Decoder[str, str]):
|
||||
class Brainfuck(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Takes a ciphertext and treats it as a Brainfuck program,
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
import re
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import re
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Decimal(Decoder[str, str]):
|
||||
class Decimal(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Decimal decoding
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, Translation
|
||||
import re
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import re
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Dna(Decoder[str, str]):
|
||||
class Dna(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs DNA decoding
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, Translation
|
||||
import re
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import re
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Dtmf(Decoder[str, str]):
|
||||
class Dtmf(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs DTMF decoding
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
# community
|
||||
# by https://github.com/lukasgabriel
|
||||
from typing import Dict, Optional
|
||||
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, Translation
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Galactic(Decoder[str, str]):
|
||||
class Galactic(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Takes a string written in the 'Standard Galactic Alphabet'
|
||||
Takes a string written in the 'Standard Galactic Alphabet'
|
||||
(aka Minecraft Enchanting Table Symbols) and translates it to ASCII text.
|
||||
"""
|
||||
logger.trace("Attempting Standard Galactic Alphabet Decoder")
|
||||
logger.trace("Attempting Standard Galactic Alphabet decoder")
|
||||
|
||||
# To avoid complications, only move forward with the decoding if we can
|
||||
# reasonably assume that the input string is written in the galactic alphabet
|
||||
|
@ -28,7 +26,7 @@ class Galactic(Decoder[str, str]):
|
|||
continue
|
||||
if galactic_matches == 0:
|
||||
logger.trace(
|
||||
"No matching galactic alphabet letters found. Skipping galactic decoder..."
|
||||
"No matching galactic alphabet letters found. Skipping galactic decoder"
|
||||
)
|
||||
return None
|
||||
logger.trace(f"{galactic_matches} galactic alphabet letters found. ")
|
||||
|
@ -50,7 +48,7 @@ class Galactic(Decoder[str, str]):
|
|||
result += self.GALACTIC_DICT[letter]
|
||||
else:
|
||||
# If the current character is not in the defined alphabet,
|
||||
# just accept it as-is (useful for numbers, punctuation,...)
|
||||
# just accept it as-is (useful for numbers, punctuation, etc.)
|
||||
result += letter
|
||||
# Remove the trailing space (appearing as a leading space)
|
||||
# from the x that results from the diacritic replacement
|
||||
|
|
|
@ -1,34 +1,32 @@
|
|||
from typing import Optional, Dict, Any
|
||||
from typing import Dict, Optional
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import registry
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Hex(ciphey.iface.Decoder[str, bytes]):
|
||||
def decode(self, text: str) -> Optional[bytes]:
|
||||
class Hexadecimal(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
It takes an octal string and return a string
|
||||
:octal_str: octal str like "110 145 154"
|
||||
Performs Hexadecimal decoding
|
||||
"""
|
||||
ctext_decoded = ""
|
||||
try:
|
||||
str_converted = bytearray.fromhex(text).decode()
|
||||
return str_converted
|
||||
# Catch bad octal chars
|
||||
except ValueError:
|
||||
ctext_decoded = bytearray.fromhex(ctext).decode("utf-8")
|
||||
return ctext_decoded
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def priority() -> float:
|
||||
return 0.015
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, Dict[str, Any]]]:
|
||||
pass
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "hex"
|
||||
return "hexadecimal"
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
from typing import Optional, Dict, Any
|
||||
from typing import Dict, Optional
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import registry, Translation, ParamSpec
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Leet(ciphey.iface.Decoder[str, str]):
|
||||
def decode(self, text: str) -> Optional[str]:
|
||||
class Leetspeak(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
for src, dst in self.translate.items():
|
||||
text = text.replace(src, dst)
|
||||
return text
|
||||
ctext = ctext.replace(src, dst)
|
||||
return ctext
|
||||
|
||||
@staticmethod
|
||||
def priority() -> float:
|
||||
return 0.05
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.translate = config.get_resource(self._params()["dict"], Translation)
|
||||
|
||||
|
@ -31,4 +30,4 @@ class Leet(ciphey.iface.Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "leet"
|
||||
return "leetspeak"
|
|
@ -1,11 +1,12 @@
|
|||
from typing import Optional, Dict, Any, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
import ciphey
|
||||
from ciphey.iface import registry
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class MorseCode(ciphey.iface.Decoder[str, str]):
|
||||
class Morse_code(Decoder[str]):
|
||||
# A priority list for char/word boundaries
|
||||
BOUNDARIES = {" ": 1, "/": 2, "\n": 3}
|
||||
PURGE = {ord(c): None for c in BOUNDARIES.keys()}
|
||||
|
@ -14,19 +15,19 @@ class MorseCode(ciphey.iface.Decoder[str, str]):
|
|||
MORSE_CODE_DICT: Dict[str, str]
|
||||
MORSE_CODE_DICT_INV: Dict[str, str]
|
||||
|
||||
def decode(self, text: str) -> Optional[str]:
|
||||
logger.trace("Attempting morse code")
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
logger.trace("Attempting Morse code decoder")
|
||||
|
||||
char_boundary = word_boundary = None
|
||||
|
||||
char_boundary = word_boundary = None
|
||||
char_priority = word_priority = 0
|
||||
# Custom loop allows early break
|
||||
for i in text:
|
||||
for i in ctext:
|
||||
i_priority = self.BOUNDARIES.get(i)
|
||||
if i_priority is None:
|
||||
if i in self.ALLOWED:
|
||||
continue
|
||||
continue
|
||||
logger.trace(f"Non-morse char '{i}' found")
|
||||
return None
|
||||
|
||||
|
@ -50,12 +51,12 @@ class MorseCode(ciphey.iface.Decoder[str, str]):
|
|||
|
||||
result = ""
|
||||
|
||||
for word in text.split(word_boundary) if word_boundary else [text]:
|
||||
for word in ctext.split(word_boundary) if word_boundary else [ctext]:
|
||||
logger.trace(f"Attempting to decode word {word}")
|
||||
for char in word.split(char_boundary):
|
||||
char = char.translate(self.PURGE)
|
||||
if len(char) == 0:
|
||||
continue
|
||||
continue
|
||||
try:
|
||||
m = self.MORSE_CODE_DICT_INV[char]
|
||||
except KeyError:
|
||||
|
@ -65,7 +66,7 @@ class MorseCode(ciphey.iface.Decoder[str, str]):
|
|||
# after every word add a space
|
||||
result = result + " "
|
||||
if len(result) == 0:
|
||||
logger.trace(f"Morse code failed to match")
|
||||
logger.trace("Morse code failed to match")
|
||||
return None
|
||||
# Remove trailing space
|
||||
result = result[:-1]
|
||||
|
@ -76,17 +77,15 @@ class MorseCode(ciphey.iface.Decoder[str, str]):
|
|||
def priority() -> float:
|
||||
return 0.05
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self.MORSE_CODE_DICT = config.get_resource(
|
||||
self._params()["dict"], ciphey.iface.Translation
|
||||
)
|
||||
self.MORSE_CODE_DICT = config.get_resource(self._params()["dict"], Translation)
|
||||
self.MORSE_CODE_DICT_INV = {v: k for k, v in self.MORSE_CODE_DICT.items()}
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ciphey.iface.ParamSpec]]:
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"dict": ciphey.iface.ParamSpec(
|
||||
"dict": ParamSpec(
|
||||
desc="The morse code dictionary to use",
|
||||
req=False,
|
||||
default="cipheydists::translate::morse",
|
||||
|
@ -95,4 +94,4 @@ class MorseCode(ciphey.iface.Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "morse"
|
||||
return "morse_code"
|
|
@ -1,21 +1,21 @@
|
|||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import ParamSpec, Config, T, U, Decoder, registry
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class multiTap(Decoder[str, str]):
|
||||
def decode(self, ctext: str) -> Optional[str]:
|
||||
decode_text = ""
|
||||
class Multi_tap(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
result = ""
|
||||
for x in ctext.split():
|
||||
if x == self.SPACE_DIGIT: # check if it space
|
||||
decode_text += " "
|
||||
elif not multiTap.valid_code_part(x):
|
||||
if x == self.SPACE_DIGIT: # Check if it's a space
|
||||
result += " "
|
||||
elif not Multi_tap.valid_code_part(x):
|
||||
return None
|
||||
else:
|
||||
decode_text += self.decode_num_to_char(x)
|
||||
result += self.decode_num_to_char(x)
|
||||
|
||||
return decode_text
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def valid_code_part(code: str) -> bool:
|
||||
|
@ -23,7 +23,7 @@ class multiTap(Decoder[str, str]):
|
|||
return False
|
||||
|
||||
# if not all the digits are the same
|
||||
if not multiTap.is_all_dup(code):
|
||||
if not Multi_tap.is_all_dup(code):
|
||||
return False
|
||||
|
||||
if int(code[0]) not in range(2, 10):
|
||||
|
@ -36,8 +36,8 @@ class multiTap(Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def decode_num_to_char(number: str) -> str:
|
||||
index = multiTap.calculate_index(number)
|
||||
return multiTap.number_index_to_char(index)
|
||||
index = Multi_tap.calculate_index(number)
|
||||
return Multi_tap.number_index_to_char(index)
|
||||
|
||||
@staticmethod
|
||||
def is_all_dup(code):
|
||||
|
@ -47,9 +47,9 @@ class multiTap(Decoder[str, str]):
|
|||
def calculate_index(number: str) -> int:
|
||||
first_number_as_int = int(number[0])
|
||||
|
||||
number_index = multiTap.get_index_from_first_digit(first_number_as_int)
|
||||
number_index = Multi_tap.get_index_from_first_digit(first_number_as_int)
|
||||
|
||||
# add to index the number of the char : "22" -> index += 1
|
||||
# Add to index the number of the char : "22" -> index += 1
|
||||
num_rest_numbers = len(number) - 1
|
||||
number_index += num_rest_numbers
|
||||
|
||||
|
@ -82,8 +82,8 @@ class multiTap(Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
pass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "Multi-tap"
|
||||
return "multi_tap"
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
from typing import Optional, Dict, Any
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import registry
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Octal(ciphey.iface.Decoder[str, bytes]):
|
||||
def decode(self, text: str) -> Optional[bytes]:
|
||||
class Octal(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
It takes an octal string and return a string
|
||||
:octal_str: octal str like "110 145 154"
|
||||
Performs Octal decoding
|
||||
"""
|
||||
str_converted = []
|
||||
octal_seq = text.split(" ")
|
||||
octal_seq = ctext.split(" ")
|
||||
if len(octal_seq) == 1:
|
||||
# Concatted octal must be formed of octal triplets
|
||||
if len(text) % 3 != 0:
|
||||
if len(ctext) % 3 != 0:
|
||||
return None
|
||||
octal_seq = [text[i : i + 3] for i in range(0, len(text), 3)]
|
||||
octal_seq = [ctext[i : i + 3] for i in range(0, len(ctext), 3)]
|
||||
logger.trace(f"Trying chunked octal {octal_seq}")
|
||||
try:
|
||||
for octal_char in octal_seq:
|
||||
if len(octal_char) > 3:
|
||||
logger.trace(f"Octal subseq too long")
|
||||
logger.trace("Octal subseq too long")
|
||||
return None
|
||||
n = int(octal_char, 8)
|
||||
if (
|
||||
|
@ -43,14 +41,13 @@ class Octal(ciphey.iface.Decoder[str, bytes]):
|
|||
def priority() -> float:
|
||||
return 0.025
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, Dict[str, Any]]]:
|
||||
pass
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
return "octal"
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import ParamSpec, Config, T, U, Decoder, registry
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register_multi((str, str), (bytes, bytes))
|
||||
class Reverse(Decoder):
|
||||
@registry.register
|
||||
class Reverse(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
return ctext[::-1]
|
||||
|
||||
|
@ -17,7 +17,7 @@ class Reverse(Decoder):
|
|||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
pass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
# by https://github.com/RustyDucky and https://github.com/lukasgabriel
|
||||
|
||||
from typing import Optional, Dict, List
|
||||
from typing import Dict, Optional
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry, Translation
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class tap_code(Decoder[str, str]):
|
||||
class Tap_code(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Tap code decoding
|
||||
"""
|
||||
try:
|
||||
output = ""
|
||||
result = ""
|
||||
combinations = ctext.split(" ")
|
||||
for fragment in combinations:
|
||||
output += self.TABLE.get(fragment)
|
||||
return output
|
||||
|
||||
except Exception as e:
|
||||
result += self.TABLE.get(fragment)
|
||||
return result
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
|
|
@ -1,33 +1,38 @@
|
|||
from typing import Optional, Dict, Any
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import registry
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Utf8(ciphey.iface.Decoder[bytes, str]):
|
||||
def decode(self, text: bytes) -> Optional[str]:
|
||||
logger.trace("Attempting utf-8 decode")
|
||||
class Utf8(Decoder[bytes]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs UTF-8 decoding
|
||||
"""
|
||||
logger.trace("Attempting UTF-8 decoder")
|
||||
result = ""
|
||||
try:
|
||||
res = text.decode("utf8")
|
||||
logger.debug(f"utf-8 decode gave '{res}'")
|
||||
return res if len(res) != 0 else None
|
||||
except UnicodeDecodeError:
|
||||
logger.trace("utf-8 decode failed")
|
||||
result = ctext.decode("utf-8")
|
||||
if result != ctext:
|
||||
logger.debug(f"UTF-8 successful, returning '{result}'")
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def priority() -> float:
|
||||
return 0.9
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, Dict[str, Any]]]:
|
||||
pass
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
|
||||
from typing import Dict, Optional
|
||||
from urllib.parse import unquote_plus
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Url(Decoder[str, str]):
|
||||
class Url(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs URL decoding
|
||||
"""
|
||||
logger.trace("Attempting URL")
|
||||
result = ""
|
||||
try:
|
||||
result = unquote_plus(ctext, errors="strict")
|
||||
if result != ctext:
|
||||
logger.debug(f"URL successful, returning '{result}'")
|
||||
return result
|
||||
else:
|
||||
return None
|
||||
except Exception:
|
||||
logger.trace("Failed to decode URL")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
@ -29,7 +34,7 @@ class Url(Decoder[str, str]):
|
|||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
pass
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getTarget() -> str:
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
from typing import Optional, Dict
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from binascii import a2b_uu
|
||||
from codecs import decode
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from codecs import decode
|
||||
|
||||
from binascii import a2b_uu
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Uuencode(Decoder[str, str]):
|
||||
class Uuencode(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
UUEncode (Unix to Unix Encoding) is a symmetric encryption
|
||||
|
@ -31,8 +29,8 @@ class Uuencode(Decoder[str, str]):
|
|||
# If there isn't a "being" prefix and "end" suffix, we use the binascii module instead
|
||||
# It is possible that the ctext has multiple lines, so convert each line and append
|
||||
ctext_split = list(filter(None, ctext.splitlines()))
|
||||
for i in range(0, len(ctext_split)):
|
||||
result += a2b_uu(ctext_split[i]).decode("utf-8")
|
||||
for _, value in enumerate(ctext_split):
|
||||
result += a2b_uu(value).decode("utf-8")
|
||||
logger.debug(f"UUencode successful, returning '{result}'")
|
||||
return result
|
||||
except Exception:
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
from typing import Optional, Dict, List
|
||||
|
||||
from ciphey.iface import Config, ParamSpec, T, U, Decoder, registry
|
||||
from typing import Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from zmq.utils import z85
|
||||
|
||||
from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry
|
||||
|
||||
|
||||
@registry.register
|
||||
class Z85(Decoder[str, str]):
|
||||
class Z85(Decoder[str]):
|
||||
def decode(self, ctext: T) -> Optional[U]:
|
||||
"""
|
||||
Performs Z85 decoding
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
from typing import Optional, Dict, Any, Set
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import Any, Dict, Optional, Set
|
||||
|
||||
import cipheydists
|
||||
import loguru
|
||||
|
||||
import ciphey
|
||||
import cipheydists
|
||||
from ciphey.iface import ParamSpec, Config, registry, WordList, Distribution, Translation
|
||||
from ciphey.iface import (
|
||||
Config,
|
||||
Distribution,
|
||||
ParamSpec,
|
||||
ResourceLoader,
|
||||
Translation,
|
||||
WordList,
|
||||
registry,
|
||||
)
|
||||
|
||||
|
||||
@registry.register_multi(WordList, Distribution, Translation)
|
||||
class CipheyDists(ciphey.iface.ResourceLoader):
|
||||
class CipheyDists(ResourceLoader):
|
||||
# _wordlists: Set[str] = frozenset({"english", "english1000", "englishStopWords"})
|
||||
# _brandons: Set[str] = frozenset({"english"})
|
||||
# _dists: Set[str] = frozenset({"twist"})
|
||||
|
@ -36,4 +42,4 @@ class CipheyDists(ciphey.iface.ResourceLoader):
|
|||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
pass
|
||||
return None
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
from abc import abstractmethod
|
||||
from typing import Optional, Dict, Any, Set, Generic, Type
|
||||
|
||||
from functools import lru_cache
|
||||
|
||||
import ciphey
|
||||
from ciphey.iface import T, ParamSpec, Config, get_args, registry
|
||||
|
||||
import json
|
||||
import csv
|
||||
import json
|
||||
from functools import lru_cache
|
||||
from typing import Dict, Generic, Optional, Set
|
||||
|
||||
from ciphey.iface import (
|
||||
Config,
|
||||
Distribution,
|
||||
ParamSpec,
|
||||
ResourceLoader,
|
||||
T,
|
||||
WordList,
|
||||
registry,
|
||||
)
|
||||
|
||||
|
||||
# We can use a generic resource loader here, as we can instantiate it later
|
||||
@registry.register_multi(ciphey.iface.WordList, ciphey.iface.Distribution)
|
||||
class Json(ciphey.iface.ResourceLoader):
|
||||
@registry.register_multi(WordList, Distribution)
|
||||
class Json(ResourceLoader):
|
||||
def whatResources(self) -> T:
|
||||
return self._names
|
||||
|
||||
|
@ -28,18 +32,18 @@ class Json(ciphey.iface.ResourceLoader):
|
|||
return "json"
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ciphey.iface.ParamSpec]]:
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {"path": ParamSpec(req=True, desc="The path to a JSON file", list=True)}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self._paths = self._params()["path"]
|
||||
self._names = set(range(1, len(self._paths)))
|
||||
|
||||
|
||||
# We can use a generic resource loader here, as we can instantiate it later
|
||||
@registry.register_multi(ciphey.iface.WordList, ciphey.iface.Distribution)
|
||||
class Csv(Generic[T], ciphey.iface.ResourceLoader[T]):
|
||||
@registry.register_multi(WordList, Distribution)
|
||||
class Csv(Generic[T], ResourceLoader[T]):
|
||||
def whatResources(self) -> Set[str]:
|
||||
return self._names
|
||||
|
||||
|
@ -56,10 +60,10 @@ class Csv(Generic[T], ciphey.iface.ResourceLoader[T]):
|
|||
return "csv"
|
||||
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ciphey.iface.ParamSpec]]:
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {"path": ParamSpec(req=True, desc="The path to a CSV file", list=True)}
|
||||
|
||||
def __init__(self, config: ciphey.iface.Config):
|
||||
def __init__(self, config: Config):
|
||||
super().__init__(config)
|
||||
self._paths = self._params()["path"]
|
||||
self._names = set(range(1, len(self._paths)))
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
from collections import deque
|
||||
import cipheycore
|
||||
|
||||
|
||||
class Node:
|
||||
"""
|
||||
A node has a value assiocated with it
|
||||
A node has a value associated with it
|
||||
Calculated from the heuristic
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, config, h: float = None, edges: (any, float) = None, ctext: str = None,
|
||||
self,
|
||||
config,
|
||||
h: float = None,
|
||||
edges: (any, float) = None,
|
||||
ctext: str = None,
|
||||
):
|
||||
self.weight = h
|
||||
# Edges is a list of other nodes it can connect to
|
||||
|
@ -90,18 +93,18 @@ class Graph:
|
|||
for v in open_list:
|
||||
# TODO if v == decoder, run the decoder
|
||||
print(f"The for loop node v is {v}")
|
||||
if n == None or g[v] + self.h(v) < g[n] + self.h(n):
|
||||
if n is None or g[v] + self.h(v) < g[n] + self.h(n):
|
||||
n = v
|
||||
print(f"The value of n is {n}")
|
||||
|
||||
if n == None:
|
||||
if n is None:
|
||||
print("Path does not exist!")
|
||||
return None
|
||||
|
||||
# if the current node is the stop_node
|
||||
# then we begin reconstructin the path from it to the start_node
|
||||
# NOTE Uncomment this for an exit condition
|
||||
# TODO Make it exit if decryptor returns True
|
||||
# TODO Make it exit if decrypter returns True
|
||||
# TODO We need to append the decryption methods to each node
|
||||
# So when we reconstruct the path we can reconstruct the decryptions
|
||||
# used
|
||||
|
@ -179,5 +182,5 @@ graph1 = Graph(adjacency_list)
|
|||
graph1.a_star_algorithm(A, D)
|
||||
|
||||
"""
|
||||
Maybe after it
|
||||
Maybe after it
|
||||
"""
|
||||
|
|
|
@ -1,39 +1,32 @@
|
|||
import bisect
|
||||
import distutils
|
||||
import math
|
||||
import bisect
|
||||
from copy import copy
|
||||
from functools import lru_cache
|
||||
from typing import (
|
||||
Generic,
|
||||
List,
|
||||
Optional,
|
||||
Dict,
|
||||
Any,
|
||||
Union,
|
||||
TypeVar,
|
||||
)
|
||||
from ciphey.iface import (
|
||||
T,
|
||||
Cracker,
|
||||
Config,
|
||||
Searcher,
|
||||
ParamSpec,
|
||||
CrackInfo,
|
||||
SearchLevel,
|
||||
CrackResult,
|
||||
SearchResult,
|
||||
Decoder,
|
||||
registry,
|
||||
Checker,
|
||||
)
|
||||
from loguru import logger
|
||||
import cipheycore
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
from typing import Any, Dict, Generic, List, Optional, TypeVar, Union
|
||||
|
||||
import cipheycore
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.iface import (
|
||||
Checker,
|
||||
Config,
|
||||
Cracker,
|
||||
CrackInfo,
|
||||
CrackResult,
|
||||
Decoder,
|
||||
ParamSpec,
|
||||
Searcher,
|
||||
SearchLevel,
|
||||
SearchResult,
|
||||
T,
|
||||
registry,
|
||||
)
|
||||
|
||||
"""
|
||||
We are using a tree structure here, because that makes searching and tracing back easier
|
||||
|
||||
As such, when we encounter another possible parent, we remove that edge
|
||||
We are using a tree structure here, because that makes searching and tracing back easier
|
||||
As such, when we encounter another possible parent, we remove that edge
|
||||
"""
|
||||
|
||||
|
||||
|
@ -131,9 +124,7 @@ class PriorityWorkQueue(Generic[PriorityType, T]):
|
|||
_queues: Dict[Any, List[T]]
|
||||
|
||||
def add_work(self, priority: PriorityType, work: List[T]) -> None:
|
||||
logger.trace(
|
||||
f"""Adding work at depth {priority}"""
|
||||
)
|
||||
logger.trace(f"""Adding work at depth {priority}""")
|
||||
|
||||
idx = bisect.bisect_left(self._sorted_priorities, priority)
|
||||
if (
|
||||
|
@ -177,7 +168,7 @@ class AuSearch(Searcher):
|
|||
|
||||
@lru_cache() # To save extra sorting
|
||||
def get_decoders_for(self, t: type):
|
||||
ret = [j for i in registry[Decoder][t].values() for j in i]
|
||||
ret = registry[Decoder[t]]
|
||||
ret.sort(key=lambda x: x.priority(), reverse=True)
|
||||
return ret
|
||||
|
||||
|
@ -194,7 +185,9 @@ class AuSearch(Searcher):
|
|||
|
||||
for i in self.get_crackers_for(type(res)):
|
||||
inst = self._config()(i)
|
||||
additional_work.append(Edge(source=node, route=inst, info=convert_edge_info(inst.getInfo(res))))
|
||||
additional_work.append(
|
||||
Edge(source=node, route=inst, info=convert_edge_info(inst.getInfo(res)))
|
||||
)
|
||||
priority = min(node.depth, self.priority_cap)
|
||||
if self.invert_priority:
|
||||
priority = -priority
|
||||
|
@ -216,7 +209,7 @@ class AuSearch(Searcher):
|
|||
except DuplicateNode:
|
||||
continue
|
||||
|
||||
logger.trace(f"Nesting encodings")
|
||||
logger.trace("Nesting encodings")
|
||||
self.recursive_expand(new_node, False)
|
||||
|
||||
def recursive_expand(self, node: Node, nested: bool = True) -> None:
|
||||
|
@ -299,9 +292,13 @@ class AuSearch(Searcher):
|
|||
super().__init__(config)
|
||||
self._checker: Checker = config.objs["checker"]
|
||||
self.work = PriorityWorkQueue() # Has to be defined here because of sharing
|
||||
self.invert_priority = bool(distutils.util.strtobool(self._params()["invert_priority"]))
|
||||
self.invert_priority = bool(
|
||||
distutils.util.strtobool(self._params()["invert_priority"])
|
||||
)
|
||||
self.priority_cap = int(self._params()["priority_cap"])
|
||||
self.enable_nested = bool(distutils.util.strtobool(self._params()["enable_nested"]))
|
||||
self.enable_nested = bool(
|
||||
distutils.util.strtobool(self._params()["enable_nested"])
|
||||
)
|
||||
self.max_cipher_depth = int(self._params()["max_cipher_depth"])
|
||||
if self.max_cipher_depth == 0:
|
||||
self.max_cipher_depth = math.inf
|
||||
|
@ -312,24 +309,32 @@ class AuSearch(Searcher):
|
|||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
return {
|
||||
"enable_nested": ParamSpec(req=False,
|
||||
desc="Enables nested ciphers. "
|
||||
"Incredibly slow, and not guaranteed to terminate",
|
||||
default="False"),
|
||||
|
||||
"invert_priority": ParamSpec(req=False,
|
||||
desc="Causes more complex encodings to be looked at first. "
|
||||
"Good for deeply buried encodings.",
|
||||
default="False"),
|
||||
"max_cipher_depth": ParamSpec(req=False,
|
||||
desc="The depth at which we stop trying to crack ciphers. "
|
||||
"Set to 0 to disable",
|
||||
default="0"),
|
||||
"max_depth": ParamSpec(req=False,
|
||||
desc="The depth at which we give up. "
|
||||
"Set to 0 to disable",
|
||||
default="0"),
|
||||
"priority_cap": ParamSpec(req=False,
|
||||
desc="Sets the maximum depth before we give up ordering items.",
|
||||
default="2"),
|
||||
"enable_nested": ParamSpec(
|
||||
req=False,
|
||||
desc="Enables nested ciphers. "
|
||||
"Incredibly slow, and not guaranteed to terminate",
|
||||
default="False",
|
||||
),
|
||||
"invert_priority": ParamSpec(
|
||||
req=False,
|
||||
desc="Causes more complex encodings to be looked at first. "
|
||||
"Good for deeply buried encodings.",
|
||||
default="False",
|
||||
),
|
||||
"max_cipher_depth": ParamSpec(
|
||||
req=False,
|
||||
desc="The depth at which we stop trying to crack ciphers. "
|
||||
"Set to 0 to disable",
|
||||
default="0",
|
||||
),
|
||||
"max_depth": ParamSpec(
|
||||
req=False,
|
||||
desc="The depth at which we give up. " "Set to 0 to disable",
|
||||
default="0",
|
||||
),
|
||||
"priority_cap": ParamSpec(
|
||||
req=False,
|
||||
desc="Sets the maximum depth before we give up ordering items.",
|
||||
default="2",
|
||||
),
|
||||
}
|
||||
|
|
|
@ -9,33 +9,33 @@ class Imperfection:
|
|||
|
||||
To calculate current, we push the entire graph to A*
|
||||
|
||||
And it calculates the next node to choose, as well as increasing the size
|
||||
And it calculates the next node to choose, as well as increasing the size
|
||||
of the graph with values
|
||||
|
||||
We're using a heap, meaing the element at [0] is always the smallest element
|
||||
We're using a heap, meaning the element at [0] is always the smallest element
|
||||
|
||||
So we choose that and return it.
|
||||
|
||||
|
||||
The current A* implemnentation has an end, we simply do not let it end as LC will make it
|
||||
end far before itreaches Searcher again.
|
||||
The current A* implementation has an end, we simply do not let it end as LC will make it
|
||||
end far before it reaches Searcher again.
|
||||
|
||||
Current is the start position, so if we say we always start at the start of the graph it'll
|
||||
go through the entire graph
|
||||
|
||||
graph = {
|
||||
Node: [
|
||||
{Node :
|
||||
{Node :
|
||||
{
|
||||
node
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
For encodings we just do them straight out
|
||||
|
||||
The last value of parents from abstract
|
||||
The last value of parents from abstract
|
||||
"""
|
||||
|
||||
"""
|
||||
|
@ -50,7 +50,7 @@ class Imperfection:
|
|||
def __init__(self):
|
||||
None
|
||||
|
||||
def findBestNode(nodes):
|
||||
def findBestNode(self, nodes):
|
||||
"""Finds the best decryption module"""
|
||||
return next(iter(nodes))
|
||||
|
||||
|
@ -66,9 +66,9 @@ class Imperfection:
|
|||
# Current appears to be the list of all new tiles we can reach from current location
|
||||
|
||||
# End is the end node, that won't actually run bc LC will make it return before it hits aSTar function
|
||||
# so tbh I'll just make it infinitite unless something else forces a return
|
||||
# so tbh I'll just make it infinite unless something else forces a return
|
||||
|
||||
# The graph is the actual data structure used. According to StackOvervlow, it looks like this:
|
||||
# The graph is the actual data structure used. According to StackOverflow, it looks like this:
|
||||
|
||||
# graph = {'A': ['B', 'C'],
|
||||
# 'B': ['C', 'D'],
|
||||
|
@ -196,7 +196,7 @@ class Imperfection:
|
|||
|
||||
class Node:
|
||||
"""
|
||||
A node has a value assiocated with it
|
||||
A node has a value associated with it
|
||||
Calculated from the heuristic
|
||||
"""
|
||||
|
||||
|
|
|
@ -1,28 +1,15 @@
|
|||
from abc import abstractmethod
|
||||
from typing import Set, Any, Union, List, Optional, Dict, Tuple
|
||||
from typing import Dict, Optional, Set
|
||||
|
||||
from loguru import logger
|
||||
from ciphey.iface import Config, ParamSpec, registry
|
||||
|
||||
from .ausearch import Node, AuSearch
|
||||
from ciphey.iface import (
|
||||
SearchLevel,
|
||||
Config,
|
||||
registry,
|
||||
CrackResult,
|
||||
Searcher,
|
||||
ParamSpec,
|
||||
Decoder,
|
||||
DecoderComparer,
|
||||
)
|
||||
|
||||
import bisect
|
||||
from .ausearch import AuSearch, Node
|
||||
|
||||
|
||||
@registry.register
|
||||
class Perfection(AuSearch):
|
||||
@staticmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
pass
|
||||
return None
|
||||
|
||||
def findBestNode(self, nodes: Set[Node]) -> Node:
|
||||
return next(iter(nodes))
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"""
|
||||
██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗
|
||||
██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
https://github.com/ciphey
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
https://github.com/Ciphey
|
||||
https://github.com/Ciphey/Ciphey/wiki
|
||||
|
||||
The cycle goes:
|
||||
|
@ -13,24 +13,16 @@ one_level_of_decryption -> decrypt_normal
|
|||
"""
|
||||
import os
|
||||
import warnings
|
||||
import argparse
|
||||
import sys
|
||||
from typing import Optional, Dict, Any, List, Union
|
||||
import bisect
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from ciphey.iface import SearchLevel, registry
|
||||
from . import iface
|
||||
|
||||
from rich import print
|
||||
from loguru import logger
|
||||
import click
|
||||
import click_spinner
|
||||
from appdirs import AppDirs
|
||||
import yaspin
|
||||
from appdirs import AppDirs
|
||||
from loguru import logger
|
||||
from rich import print
|
||||
from yaspin.spinners import Spinners
|
||||
from yaspin import yaspin
|
||||
|
||||
import time
|
||||
from . import iface
|
||||
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
@ -64,7 +56,10 @@ def print_help(ctx):
|
|||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"-t", "--text", help="The ciphertext you want to decrypt.", type=str,
|
||||
"-t",
|
||||
"--text",
|
||||
help="The ciphertext you want to decrypt.",
|
||||
type=str,
|
||||
)
|
||||
@click.option(
|
||||
"-q", "--quiet", help="Decrease verbosity", type=int, count=True, default=None
|
||||
|
@ -86,13 +81,20 @@ def print_help(ctx):
|
|||
)
|
||||
@click.option("-w", "--wordlist", help="Uses the given wordlist")
|
||||
@click.option(
|
||||
"-p", "--param", help="Passes a parameter to the language checker", multiple=True,
|
||||
"-p",
|
||||
"--param",
|
||||
help="Passes a parameter to the language checker",
|
||||
multiple=True,
|
||||
)
|
||||
@click.option(
|
||||
"-l", "--list-params", help="List the parameters of the selected module", type=bool,
|
||||
"-l",
|
||||
"--list-params",
|
||||
help="List the parameters of the selected module",
|
||||
type=bool,
|
||||
)
|
||||
@click.option(
|
||||
"--searcher", help="Select the searching algorithm to use",
|
||||
"--searcher",
|
||||
help="Select the searching algorithm to use",
|
||||
)
|
||||
# HARLAN TODO XXX
|
||||
# I switched this to a boolean flag system
|
||||
|
@ -129,19 +131,19 @@ def print_help(ctx):
|
|||
@click.argument("text_stdin", callback=get_name, required=False)
|
||||
def main(**kwargs):
|
||||
"""Ciphey - Automated Decryption Tool
|
||||
|
||||
Documentation:
|
||||
|
||||
Documentation:
|
||||
https://github.com/Ciphey/Ciphey/wiki\n
|
||||
Discord (support here, we're online most of the day):
|
||||
https://discord.ciphey.online/\n
|
||||
GitHub:
|
||||
GitHub:
|
||||
https://github.com/ciphey/ciphey\n
|
||||
|
||||
Ciphey is an automated decryption tool using smart artificial intelligence and natural language processing. Input encrypted text, get the decrypted text back.
|
||||
|
||||
Examples:\n
|
||||
Basic Usage: ciphey -t "aGVsbG8gbXkgbmFtZSBpcyBiZWU="
|
||||
|
||||
Basic Usage: ciphey -t "aGVsbG8gbXkgbmFtZSBpcyBiZWU="
|
||||
|
||||
"""
|
||||
|
||||
"""Function to deal with arguments. Either calls with args or not. Makes Pytest work.
|
||||
|
@ -152,7 +154,6 @@ def main(**kwargs):
|
|||
we then update locals() with the new command line args and remove "withArgs"
|
||||
This function then calls call_encryption(**result) which passes our dict of args
|
||||
to the function as its own arguments using dict unpacking.
|
||||
|
||||
Returns:
|
||||
The output of the decryption.
|
||||
"""
|
||||
|
@ -243,9 +244,9 @@ def main(**kwargs):
|
|||
|
||||
if issubclass(config.objs["format"], type(kwargs["text"])):
|
||||
pass
|
||||
elif config.objs["format"] == str and type(kwargs["text"]) is bytes:
|
||||
elif config.objs["format"] == str and isinstance(kwargs["text"], bytes):
|
||||
kwargs["text"] = kwargs["text"].decode("utf-8")
|
||||
elif config.objs["format"] == bytes and type(kwargs["text"]) is str:
|
||||
elif config.objs["format"] == bytes and isinstance(kwargs["text"], str):
|
||||
kwargs["text"] = kwargs["text"].encode("utf-8")
|
||||
else:
|
||||
raise TypeError(f"Cannot load type {config.format} from {type(kwargs['text'])}")
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
"""Some useful adapters"""
|
||||
from typing import Any, List
|
||||
import inspect
|
||||
|
||||
import cipheycore
|
||||
from typing import Any
|
||||
|
||||
|
||||
def id_lambda(value: Any):
|
||||
"""
|
||||
A function used in dynamic class generation that abstracts away a constant return value (like in getName)
|
||||
A function used in dynamic class generation that abstracts away a constant return value (like in getName)
|
||||
"""
|
||||
return lambda *args: value
|
||||
|
||||
|
||||
def fix_case(target: str, base: str) -> str:
|
||||
"""Returns the lower-case string target with the case of base"""
|
||||
ret = ''.join([target[i].upper() if base[i].isupper() else target[i] for i in range(len(target))])
|
||||
return ''.join([target[i].upper() if base[i].isupper() else target[i] for i in range(len(target))])
|
||||
ret = "".join(
|
||||
[
|
||||
target[i].upper() if base[i].isupper() else target[i]
|
||||
for i in range(len(target))
|
||||
]
|
||||
)
|
||||
return "".join(
|
||||
[
|
||||
target[i].upper() if base[i].isupper() else target[i]
|
||||
for i in range(len(target))
|
||||
]
|
||||
)
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
from ._config import Config
|
||||
|
||||
from ._modules import (
|
||||
Checker,
|
||||
Cracker,
|
||||
CrackInfo,
|
||||
CrackResult,
|
||||
Decoder,
|
||||
DecoderComparer,
|
||||
Cracker,
|
||||
CrackResult,
|
||||
CrackInfo,
|
||||
Checker,
|
||||
Searcher,
|
||||
SearchResult,
|
||||
SearchLevel,
|
||||
ResourceLoader,
|
||||
ParamSpec,
|
||||
WordList,
|
||||
Distribution,
|
||||
Translation,
|
||||
ParamSpec,
|
||||
PolymorphicChecker,
|
||||
ResourceLoader,
|
||||
Searcher,
|
||||
SearchLevel,
|
||||
SearchResult,
|
||||
T,
|
||||
Translation,
|
||||
U,
|
||||
WordList,
|
||||
pretty_search_results,
|
||||
PolymorphicChecker
|
||||
)
|
||||
|
||||
from ._registry import get_args, get_origin
|
||||
|
||||
from ._fwd import registry
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
import datetime
|
||||
import os
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Optional,
|
||||
List,
|
||||
Type,
|
||||
Union,
|
||||
Callable,
|
||||
)
|
||||
import pydoc
|
||||
from typing import Any, Callable, Dict, List, Optional, Type, Union
|
||||
|
||||
import appdirs
|
||||
import yaml
|
||||
from loguru import logger
|
||||
|
||||
import datetime
|
||||
|
||||
import yaml
|
||||
import appdirs
|
||||
|
||||
from . import _fwd
|
||||
from ._modules import Checker, Searcher, ResourceLoader, PolymorphicChecker
|
||||
from ._modules import PolymorphicChecker, ResourceLoader, Searcher
|
||||
|
||||
|
||||
class Cache:
|
||||
|
@ -28,7 +18,7 @@ class Cache:
|
|||
self._cache: Dict[Any, Dict[str, Any]] = {}
|
||||
|
||||
def mark_ctext(self, ctext: Any) -> bool:
|
||||
if (type(ctext) == str or type(ctext) == bytes) and len(ctext) < 4:
|
||||
if (isinstance(ctext, str) or isinstance(ctext, bytes)) and len(ctext) < 4:
|
||||
logger.trace(f"Candidate {ctext.__repr__()} too short!")
|
||||
return False
|
||||
|
||||
|
@ -98,7 +88,7 @@ class Config:
|
|||
|
||||
def instantiate(self, t: type) -> Any:
|
||||
"""
|
||||
Used to enable caching of a instantiated type after the configuration has settled
|
||||
Used to enable caching of a instantiated type after the configuration has settled
|
||||
"""
|
||||
# We cannot use set default as that would construct it again, and throw away the result
|
||||
res = self._inst.get(t)
|
||||
|
@ -138,7 +128,9 @@ class Config:
|
|||
|
||||
# Checkers do not depend on any other config object
|
||||
logger.trace(f"Registry is {_fwd.registry._reg[PolymorphicChecker]}")
|
||||
self.objs["checker"] = self(_fwd.registry.get_named(self.checker, PolymorphicChecker))
|
||||
self.objs["checker"] = self(
|
||||
_fwd.registry.get_named(self.checker, PolymorphicChecker)
|
||||
)
|
||||
# Searchers only depend on checkers
|
||||
self.objs["searcher"] = self(_fwd.registry.get_named(self.searcher, Searcher))
|
||||
|
||||
|
@ -159,9 +151,10 @@ class Config:
|
|||
else:
|
||||
verbosity_name = quiet_list[min(len(quiet_list), -verbosity) - 1]
|
||||
|
||||
from loguru import logger
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
|
||||
logger.remove()
|
||||
if self.verbosity is None:
|
||||
return
|
||||
|
|
|
@ -1,22 +1,5 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Generic,
|
||||
Optional,
|
||||
List,
|
||||
NamedTuple,
|
||||
TypeVar,
|
||||
Type,
|
||||
Union,
|
||||
Set,
|
||||
)
|
||||
import pydoc
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import datetime
|
||||
from typing import Any, Dict, Generic, List, NamedTuple, Optional, Set, Type, TypeVar
|
||||
|
||||
from ._fwd import config as Config
|
||||
|
||||
|
@ -48,14 +31,14 @@ class ConfigurableModule(ABC):
|
|||
@abstractmethod
|
||||
def getParams() -> Optional[Dict[str, ParamSpec]]:
|
||||
"""
|
||||
Returns a dictionary of `argument name: argument specification`
|
||||
Returns a dictionary of `argument name: argument specification`
|
||||
"""
|
||||
pass
|
||||
|
||||
def _checkParams(self):
|
||||
"""
|
||||
Fills the given params dict with default values where arguments are not given,
|
||||
using None as the default value for default values
|
||||
Fills the given params dict with default values where arguments are not given,
|
||||
using None as the default value for default values
|
||||
"""
|
||||
|
||||
params = self._params()
|
||||
|
@ -179,7 +162,7 @@ class Checker(Generic[T], ConfigurableModule):
|
|||
# def __init__(self, config: Config): super().__init__(config)
|
||||
|
||||
|
||||
class Decoder(Generic[T, U], ConfigurableModule, Targeted):
|
||||
class Decoder(Generic[T], ConfigurableModule, Targeted):
|
||||
"""Represents the undoing of some encoding into a different (or the same) type"""
|
||||
|
||||
@abstractmethod
|
||||
|
@ -243,7 +226,7 @@ class Cracker(Generic[T], ConfigurableModule, Targeted):
|
|||
@abstractmethod
|
||||
def attemptCrack(self, ctext: T) -> List[CrackResult]:
|
||||
"""
|
||||
This should attempt to crack the cipher `target`, and return a list of candidate solutions
|
||||
This should attempt to crack the cipher `target`, and return a list of candidate solutions
|
||||
"""
|
||||
# FIXME: Actually CrackResult[T], but python complains
|
||||
pass
|
||||
|
@ -260,21 +243,21 @@ class ResourceLoader(Generic[T], ConfigurableModule):
|
|||
@abstractmethod
|
||||
def whatResources(self) -> Optional[Set[str]]:
|
||||
"""
|
||||
Return a set of the names of instances T you can provide.
|
||||
The names SHOULD be unique amongst ResourceLoaders of the same type
|
||||
Return a set of the names of instances T you can provide.
|
||||
The names SHOULD be unique amongst ResourceLoaders of the same type
|
||||
|
||||
These names will be exposed as f"{self.__name__}::{name}", use split_resource_name to recover this
|
||||
These names will be exposed as f"{self.__name__}::{name}", use split_resource_name to recover this
|
||||
|
||||
If you cannot reasonably determine what resources you provide, return None instead
|
||||
If you cannot reasonably determine what resources you provide, return None instead
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def getResource(self, name: str) -> T:
|
||||
"""
|
||||
Returns the requested distribution
|
||||
Returns the requested distribution
|
||||
|
||||
The behaviour is undefined if `name not in self.what_resources()`
|
||||
The behavior is undefined if `name not in self.what_resources()`
|
||||
"""
|
||||
pass
|
||||
|
||||
|
|
|
@ -1,30 +1,12 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from collections import defaultdict
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Generic,
|
||||
Optional,
|
||||
List,
|
||||
NamedTuple,
|
||||
TypeVar,
|
||||
Type,
|
||||
Union,
|
||||
Set,
|
||||
Tuple,
|
||||
)
|
||||
import pydoc
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union
|
||||
|
||||
try:
|
||||
from typing import get_origin, get_args
|
||||
from typing import get_args, get_origin
|
||||
except ImportError:
|
||||
from typing_inspect import get_origin, get_args
|
||||
|
||||
from loguru import logger
|
||||
from . import _fwd
|
||||
from ._modules import *
|
||||
import datetime
|
||||
|
||||
|
||||
class Registry:
|
||||
|
@ -91,9 +73,13 @@ class Registry:
|
|||
# Replace input type with polymorphic checker if required
|
||||
if issubclass(input_type, Checker):
|
||||
if len(args) == 0:
|
||||
arg = [get_args(i) for i in input_type.__orig_bases__ if get_origin(i) == Checker][0]
|
||||
arg = [
|
||||
get_args(i)
|
||||
for i in input_type.__orig_bases__
|
||||
if get_origin(i) == Checker
|
||||
][0]
|
||||
if len(arg) != 1:
|
||||
raise TypeError(f"No argument for Checker")
|
||||
raise TypeError("No argument for Checker")
|
||||
input_type = input_type.convert({arg[0]})
|
||||
else:
|
||||
input_type = input_type.convert(set(args))
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""
|
||||
██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗
|
||||
██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗
|
||||
██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
██║ ██║██████╔╝███████║█████╗ ╚████╔╝
|
||||
██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝
|
||||
╚██████╗██║██║ ██║ ██║███████╗ ██║
|
||||
© Brandon Skerritt
|
||||
Github: brandonskerritt
|
||||
|
||||
|
@ -14,9 +14,10 @@ Class to provide helper functions for mathematics
|
|||
|
||||
from collections import OrderedDict
|
||||
from string import punctuation
|
||||
from loguru import logger
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class mathsHelper:
|
||||
"""Class to provide helper functions for mathematics and other small things"""
|
||||
|
@ -189,17 +190,16 @@ class mathsHelper:
|
|||
return bool(lambda s: len(s) == len(s.encode()))
|
||||
|
||||
@staticmethod
|
||||
def strip_puncuation(text: str) -> str:
|
||||
def strip_punctuation(text: str) -> str:
|
||||
"""Strips punctuation from a given string.
|
||||
|
||||
Uses string.puncuation.
|
||||
Uses string.punctuation.
|
||||
|
||||
Args:
|
||||
text -> the text to strip puncuation from.
|
||||
text -> the text to strip punctuation from.
|
||||
|
||||
Returns:
|
||||
Returns string without puncuation.
|
||||
|
||||
Returns string without punctuation.
|
||||
"""
|
||||
text: str = (str(text).translate(str.maketrans("", "", punctuation))).strip(
|
||||
"\n"
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"""
|
||||
The file for Nox
|
||||
"""
|
||||
import nox
|
||||
from typing import Any
|
||||
|
||||
import nox
|
||||
from nox.sessions import Session
|
||||
import tempfile
|
||||
|
||||
locations = "ciphey/", "tests/", "docs/"
|
||||
nox.options.sessions = "safety", "tests"
|
||||
|
|
|
@ -14,8 +14,8 @@ rich = ">=4,<10"
|
|||
loguru = "^0.5.0"
|
||||
pylint = "^2.5.2"
|
||||
flake8 = "^3.8.2"
|
||||
cipheydists = "^0.3.31"
|
||||
cipheycore = "^0.3.1"
|
||||
cipheydists = "^0.3.33"
|
||||
cipheycore = "^0.3.2"
|
||||
appdirs = "^1.4.4"
|
||||
typing_inspect = { version = "^0.6.0", python = "~3.7" }
|
||||
base58 = "^2.0.1"
|
||||
|
|
|
@ -13,7 +13,7 @@ If you have more tests, let me know and I can factor them in.
|
|||
In your first reply:
|
||||
https://github.com/Ciphey/Ciphey/issues/90#issuecomment-645046918
|
||||
Point 3:
|
||||
> Be aware that the stuff passed to the checker will most likely be complete gibberish (with a similar freq dist) OR the correct result. A user will not care about an extra second spent on the final correct result, but really will care that every false candidate takes an extra second. The current suggestion seems to be pessimal for the gibberish inputs: maybe add some sanity checks (have I failed to match any word, have I failed to lemmatise any word, etc.)
|
||||
> Be aware that the stuff passed to the checker will most likely be complete gibberish (with a similar freq dist) OR the correct result. A user will not care about an extra second spent on the final correct result, but really will care that every false candidate takes an extra second. The current suggestion seems to be pessimal for the gibberish inputs: maybe add some sanity checks (have I failed to match any word, have I failed to lemmatize any word, etc.)
|
||||
|
||||
I decided to test how well `lem` worked as phase 1. To do this, I created this program:
|
||||
```python
|
||||
|
@ -36,7 +36,6 @@ import spacy
|
|||
import random
|
||||
import time
|
||||
from statistics import mean
|
||||
import ciphey
|
||||
import enciphey
|
||||
from alive_progress import alive_bar
|
||||
|
||||
|
@ -75,10 +74,10 @@ def perform():
|
|||
total = 0
|
||||
true_returns = 0
|
||||
|
||||
# calculate aveager time
|
||||
# calculate average time
|
||||
time_list = []
|
||||
|
||||
# average sentance size
|
||||
# average sentence size
|
||||
sent_size_list = []
|
||||
items = range(20000)
|
||||
with alive_bar(len(items)) as bar:
|
||||
|
@ -117,7 +116,7 @@ perform()
|
|||
```
|
||||
|
||||
The results were fascinating, to say the least.
|
||||
With a 50/50 chance of the text being gibberish (ciphertext from enCiphey) or sentences from Hansard.txt, we had these results for using lemmization as phase 1:
|
||||
With a 50/50 chance of the text being gibberish (ciphertext from enCiphey) or sentences from Hansard.txt, we had these results for using lemmatization as phase 1:
|
||||
|
||||
```
|
||||
The accuracy is 49.63%
|
||||
|
@ -138,7 +137,7 @@ I will create a table of my results:
|
|||
|
||||
| Name | Speed | Accuracy | String Size Average Chars | Epochs | Max Sentence Size |
|
||||
| -------------------------- | ---------------------------- | -------- | ------------------------- | ------ | ----------------- |
|
||||
| Lemmization (lem) | 0.02 seconds | 50% | 1580 | 20,000 | 50 |
|
||||
| Lemmatization (lem) | 0.02 seconds | 50% | 1580 | 20,000 | 50 |
|
||||
| Stop word removal | 3.05465052884756e-05 seconds | 96% | 1596 | 20,000 | 50 |
|
||||
| Check1000Words | 0.0005 seconds | 96% | 1597 | 20,000 | 50 |
|
||||
| Word endings | 0.0009 seconds | 95% | 1597 | 20,000 | 50 |
|
||||
|
@ -147,7 +146,7 @@ I will create a table of my results:
|
|||
|
||||
| Name | Speed | Accuracy | String Size Average Chars | Epochs | Max Sentence Size |
|
||||
| -------------------------- | ------------------------------ | -------- | ------------------------- | ------ | ----------------- |
|
||||
| Lemmization (lem) |
|
||||
| Lemmatization (lem) |
|
||||
| Stop word removal | 1.1574924453998391e-05 seconds | 93% | 569 | 20,000 | 5 |
|
||||
| Check1000Words | 0.0006 seconds | 95% | 586 | 20,000 | 5 |
|
||||
| Word endings | 0.0003 seconds | 92% | 482 | 20,000 | 5 |
|
||||
|
@ -155,14 +154,14 @@ I will create a table of my results:
|
|||
|
||||
| Name | Speed | Accuracy | Threshold | String Size Average Chars | Epochs | Max Sentence Size |
|
||||
| -------------------------- | ------------------------------- | -------- | ------ |------------------------- | ------ | ----------------- |
|
||||
| Lemmization (lem) |
|
||||
| Lemmatization (lem) |
|
||||
| Stop word removal | 1.2532061150591289e-05. seconds | 50% | 481 | 20,000 | 1 |
|
||||
| Check1000Words | 0.0006 seconds | 95% | 586 | 20,000 | 5 |
|
||||
| Word endings | 0.0002 seconds | 86% | 15| 482 | 20,000 | 1 |
|
||||
|
||||
|
||||
## Confusion Matrices & Notes
|
||||
### Lemization
|
||||
### Lemmatization
|
||||
|
||||
```
|
||||
Positive Negative
|
||||
|
@ -297,7 +296,7 @@ However, the accuracy for smaller sentence sizes tanked.
|
|||
|
||||
The highest accuracy we had was with the original one. Words <= 2 chars and no limit on threshold.
|
||||
|
||||
If possible, we want to combine the high accuracy on smaller texts while maintaining the generalisation found in the latter checker results.
|
||||
If possible, we want to combine the high accuracy on smaller texts while maintaining the generalization found in the latter checker results.
|
||||
|
||||
The reason we want a smaller threshold is that due to the chunking procedure, it will be much faster on larger texts. The lower the sentence length the higher the threshold is allowed to be.
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import unittest
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.basemods.Checkers.brandon import Brandon
|
||||
|
||||
config = dict()
|
||||
lc = config["checker"](config)
|
||||
import unittest
|
||||
from loguru import logger
|
||||
|
||||
logger.remove()
|
||||
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
import random
|
||||
import nltk
|
||||
from nltk.tokenize.treebank import TreebankWordDetokenizer
|
||||
import random
|
||||
import base64
|
||||
import binascii
|
||||
import cipheydists
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import cipheycore
|
||||
import cipheydists
|
||||
|
||||
import base58
|
||||
import base62
|
||||
import re
|
||||
|
||||
import lukas
|
||||
import cipheycore
|
||||
import cipheydists
|
||||
import nltk
|
||||
from nltk.tokenize.treebank import TreebankWordDetokenizer
|
||||
|
||||
|
||||
class encipher:
|
||||
|
@ -48,11 +45,11 @@ class encipher_crypto: # pragma: no cover
|
|||
"""Holds the encryption functions
|
||||
can randomly select an encryption function use on text
|
||||
returns:
|
||||
{"text": t, "plaintext": c, "cipher": p, "suceeds": False}
|
||||
{"text": t, "plaintext": c, "cipher": p, "succeeds": False}
|
||||
|
||||
where suceeds is whether or not the text is really encrypted or falsely decrypted
|
||||
where succeeds is whether or not the text is really encrypted or falsely decrypted
|
||||
|
||||
Uses Cyclic3's module generate psuedo random text"""
|
||||
Uses Cyclic3's module generate pseudo random text"""
|
||||
|
||||
def __init__(self): # pragma: no cover
|
||||
self.methods = [
|
||||
|
@ -93,13 +90,13 @@ class encipher_crypto: # pragma: no cover
|
|||
return {"PlainText": text, "EncryptedText": encryptedText, "CipherUsed": name}
|
||||
|
||||
def Base64(self, text: str) -> str: # pragma: no cover
|
||||
"""Turns text in base64 using Python libray
|
||||
"""Turns text into Base64 using Python library
|
||||
|
||||
args:
|
||||
text -> text convert
|
||||
args:
|
||||
text -> text convert
|
||||
|
||||
returns:
|
||||
text -> as base 64"""
|
||||
returns:
|
||||
text -> as Base64"""
|
||||
return base64.b64encode(bytes(text, "utf-8")).decode("utf-8")
|
||||
|
||||
def Caesar(self, s, k): # pragma: no cover
|
||||
|
@ -118,23 +115,23 @@ class encipher_crypto: # pragma: no cover
|
|||
return c
|
||||
|
||||
def Base32(self, text: str) -> str: # pragma: no cover
|
||||
"""Turns text in base64 using Python libray
|
||||
"""Turns text in Base32 using Python library
|
||||
|
||||
args:
|
||||
text -> text convert
|
||||
args:
|
||||
text -> text convert
|
||||
|
||||
returns:
|
||||
text -> as base 64"""
|
||||
returns:
|
||||
text -> as Base32"""
|
||||
return base64.b32encode(bytes(text, "utf-8")).decode("utf-8")
|
||||
|
||||
def Base16(self, text: str) -> str: # pragma: no cover
|
||||
"""Turns text in base64 using Python libray
|
||||
"""Turns text in Base16 using Python library
|
||||
|
||||
args:
|
||||
text -> text convert
|
||||
args:
|
||||
text -> text convert
|
||||
|
||||
returns:
|
||||
text -> as base 64"""
|
||||
returns:
|
||||
text -> as Base16"""
|
||||
return base64.b16encode(bytes(text, "utf-8")).decode("utf-8")
|
||||
|
||||
def Binary(self, text: str) -> str: # pragma: no cover
|
||||
|
@ -152,7 +149,7 @@ class encipher_crypto: # pragma: no cover
|
|||
morse = []
|
||||
for i in text:
|
||||
m = self.morse_dict.get(i.upper())
|
||||
if m == None:
|
||||
if m is None:
|
||||
m = ""
|
||||
morse.append(m)
|
||||
|
||||
|
@ -189,5 +186,3 @@ class encipher_crypto: # pragma: no cover
|
|||
|
||||
def b62(self, text: str):
|
||||
return base62.decode(str(re.sub(r"[^A-Za-z1-9]+", "", text)))
|
||||
|
||||
|
||||
|
|
|
@ -18,17 +18,17 @@ for i in range(1, 20000):
|
|||
grabCipher = grabCipher()
|
||||
# this returns a random cipher, encrypted text and plaintext combo
|
||||
toAppend ='''
|
||||
def test_{cipher}_{suceeds}_{plaintext[0:10]}(textToTest):
|
||||
def test_{cipher}_{succeeds}_{plaintext[0:10]}(textToTest):
|
||||
cipheyObj = ciphey(text)
|
||||
output = cipheyObj.decrypt()
|
||||
assert(output, {plaintext})
|
||||
'''
|
||||
file.append()
|
||||
"""
|
||||
import uuid
|
||||
import enciphey
|
||||
import string
|
||||
import random
|
||||
import string
|
||||
|
||||
import enciphey
|
||||
from rich.progress import track
|
||||
|
||||
|
||||
|
@ -69,7 +69,7 @@ def test_{cipher['Encrypted Texts']['CipherUsed']}_{id}():
|
|||
cfg["debug"] = "TRACE"
|
||||
result = main(cfg)
|
||||
|
||||
assert result["IsPlaintext?"] == True
|
||||
assert result["IsPlaintext?"] == True
|
||||
"""
|
||||
|
||||
def randomString(self, stringLength):
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
from ciphey.LanguageChecker import LanguageChecker
|
||||
import unittest
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from ciphey.LanguageChecker import LanguageChecker
|
||||
|
||||
logger.remove()
|
||||
|
||||
|
||||
|
@ -24,7 +26,7 @@ class testIntegration(unittest.TestCase):
|
|||
|
||||
def test_basics_quickbrownfox(self):
|
||||
"""
|
||||
This returns true becaue by default chi squared returns true so long as it's less than 10 items it's processed
|
||||
This returns true because by default chi squared returns true so long as it's less than 10 items it's processed
|
||||
"""
|
||||
lc = LanguageChecker.Checker()
|
||||
result = lc.check("The quick brown fox jumped over the lazy dog")
|
||||
|
@ -32,7 +34,7 @@ class testIntegration(unittest.TestCase):
|
|||
|
||||
def test_basics_quickbrownfox(self):
|
||||
"""
|
||||
This returns true becaue by default chi squared returns true so long as it's less than 10 items it's processed
|
||||
This returns true because by default chi squared returns true so long as it's less than 10 items it's processed
|
||||
"""
|
||||
lc = LanguageChecker.Checker()
|
||||
result = lc.check("The quick brown fox jumped over the lazy dog")
|
||||
|
@ -109,7 +111,7 @@ class testIntegration(unittest.TestCase):
|
|||
|
||||
def test_integration_addition(self):
|
||||
"""
|
||||
Makes sure you can add 2 lanuggae objecs together
|
||||
Makes sure you can add 2 language objects together
|
||||
"""
|
||||
lc = LanguageChecker.Checker()
|
||||
result = lc.check("hello my darling")
|
||||
|
@ -128,7 +130,7 @@ class testIntegration(unittest.TestCase):
|
|||
"""
|
||||
I had a bug with this exact string
|
||||
Bug is that chi squared does not score this as True
|
||||
"""
|
||||
"""
|
||||
text = """Charles Babbage, FRS (26 December 1791 - 18 October 1871) was an English mathematician, philosopher, inventor and mechanical engineer who originated the concept of a programmable computer. Considered a "father of the computer", Babbage is credited with inventing the first mechanical computer that eventually led to more complex designs. Parts of his uncompleted mechanisms are on display in the London Science Museum. In 1991, a perfectly functioning difference engine was constructed from Babbage's original plans. Built to tolerances achievable in the 19th century, the success of the finished engine indicated that Babbage's machine would have worked. Nine years later, the Science Museum completed the printer Babbage had designed for the difference engine."""
|
||||
lc = LanguageChecker.Checker()
|
||||
result = lc.check(text)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import cipheydists
|
||||
import random
|
||||
|
||||
import cipheydists
|
||||
|
||||
|
||||
class galactic_encode:
|
||||
"""
|
||||
|
@ -50,7 +51,7 @@ class XY_encrypt:
|
|||
"""
|
||||
Encrypts an input string using binary substitution (called XandY in Ciphey) in which
|
||||
first, the input string is converted to its binary representation and then the 0s and 1s
|
||||
of the binary string are replaced with any two characters.
|
||||
of the binary string are replaced with any two characters.
|
||||
- flip: Which of the two possible rotations of the substitute characters is used?
|
||||
- randomize: If True, random spaces are inserted into the cstring, which Ciphey can handle.
|
||||
- key: Which two characters are used to represent the 0s and 1s?
|
||||
|
@ -91,6 +92,6 @@ class XY_encrypt:
|
|||
self.ctext = self.ctext.replace(str(int(self.flip)), one).replace(
|
||||
str(int(not self.flip)), two
|
||||
)
|
||||
self.ctext = self.randomizer() if self.randomize == True else self.ctext
|
||||
self.ctext = self.randomizer() if self.randomize is True else self.ctext
|
||||
|
||||
return self.ctext
|
||||
|
|
|
@ -1,81 +1,25 @@
|
|||
import pytest
|
||||
|
||||
from ciphey import decrypt
|
||||
from ciphey.iface import Config
|
||||
import pytest
|
||||
|
||||
answer_str = "Hello my name is bee and I like dog and apple and tree"
|
||||
|
||||
|
||||
def test_plaintext():
|
||||
res = decrypt(Config.library_default().complete_config(), answer_str)
|
||||
|
||||
print(res)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_base64():
|
||||
def test_affine():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"SGVsbG8gbXkgbmFtZSBpcyBiZWUgYW5kIEkgbGlrZSBkb2cgYW5kIGFwcGxlIGFuZCB0cmVl",
|
||||
"Ihsst bf kxbh rd ghh xky R srjh ytz xky xccsh xky muhh",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_caesar():
|
||||
def test_ascii_shift():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"Uryyb zl anzr vf orr naq V yvxr qbt naq nccyr naq gerr",
|
||||
'"?FFIzGSzH;G?zCMz<??z;H>z#zFCE?z>IAz;H>z;JJF?z;H>zNL??',
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_binary_base64_caesar():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"01010110 01011000 01001010 00110101 01100101 01010111 01001001 01100111 01100101 01101101 01110111 "
|
||||
"01100111 01011001 01010111 00110101 00110110 01100011 01101001 01000010 00110010 01011010 01101001 "
|
||||
"01000010 01110110 01100011 01101110 01001001 01100111 01100010 01101101 01000110 01111000 01001001 "
|
||||
"01000110 01011001 01100111 01100101 01011000 01011010 00110100 01100011 01101001 01000010 01111000 "
|
||||
"01011001 01101110 01010001 01100111 01100010 01101101 01000110 01111000 01001001 01000111 00110101 "
|
||||
"01101010 01011001 00110011 01101100 01111001 01001001 01000111 00110101 01101000 01100011 01010011 "
|
||||
"01000010 01101110 01011010 01011000 01001010 01111001 00001010",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_vigenere():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"Rijvs ki rywi gc fco eln M jsoc nse krb ktnvi yxh rbic",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_binary():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"01001000 01100101 01101100 01101100 01101111 00100000 01101101 01111001 00100000 01101110 01100001 "
|
||||
"01101101 01100101 00100000 01101001 01110011 00100000 01100010 01100101 01100101 00100000 01100001 "
|
||||
"01101110 01100100 00100000 01001001 00100000 01101100 01101001 01101011 01100101 00100000 01100100 "
|
||||
"01101111 01100111 00100000 01100001 01101110 01100100 00100000 01100001 01110000 01110000 01101100 "
|
||||
"01100101 00100000 01100001 01101110 01100100 00100000 01110100 01110010 01100101 01100101",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_hex():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"48656c6c6f206d79206e616d652069732062656520616e642049206c696b6520646f6720616e64206170706c6520616e6420"
|
||||
"74726565",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_atbash():
|
||||
|
@ -86,55 +30,15 @@ def test_atbash():
|
|||
assert res == answer_str
|
||||
|
||||
|
||||
def test_galactic():
|
||||
def test_base32():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"⍑ᒷꖎꖎ𝙹 ᒲ|| リᔑᒲᒷ ╎ᓭ ʖᒷᒷ ᔑリ↸ i ꖎ╎ꖌᒷ ↸𝙹⊣ ᔑリ↸ ᔑ!¡!¡ꖎᒷ ᔑリ↸ ℸ ̣ ∷ᒷᒷ",
|
||||
"JBSWY3DPEBWXSIDOMFWWKIDJOMQGEZLFEBQW4ZBAJEQGY2LLMUQGI33HEBQW4ZBAMFYHA3DFEBQW4ZBAORZGKZI=",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_galactic_Xproblem():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"⍑ᔑꖎ╎⎓ᔑ ̇/, ̇/||ꖎ𝙹!¡⍑𝙹リᒷ, ᔑ ̇/ ᔑꖎ𝙹リᒷ ᔑリ↸ ̇/ᒷ∷𝙹 ̇/ ⎓∷𝙹ᒲ 𝙹 ̇/⎓𝙹∷↸"
|
||||
)
|
||||
assert res.lower() == "halifax, xylophone, a x alone and xerox from oxford"
|
||||
|
||||
|
||||
def test_XandY():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"xDDxDxxx xDDxxDxD xDDxDDxx xDDxDDxx xDDxDDDD xxDxxxxx xDDxDDxD xDDDDxxD xxDxxxxx xDDxDDDx xDDxxxxD xDDxDDxD xDDxxDxD xxDxxxxx xDDxDxxD xDDDxxDD xxDxxxxx xDDxxxDx xDDxxDxD xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDxxDxxD xxDxxxxx xDDxDDxx xDDxDxxD xDDxDxDD xDDxxDxD xxDxxxxx xDDxxDxx xDDxDDDD xDDxxDDD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDxxxxD xDDDxxxx xDDDxxxx xDDxDDxx xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDDxDxx xDDDxxDx xDDxxDxD xDDxxDxD",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def leet():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"|-|3770 my nam3 is 833 and 1 lIke D06 AND 4|>|>13 4 7R33",
|
||||
)
|
||||
assert res.lower() == answer_str
|
||||
|
||||
|
||||
def test_new_line_strip_and_return():
|
||||
# Language Checker should return True by stripping new line
|
||||
# but the new line should be returned to the user as new lines are important
|
||||
res = decrypt(Config().library_default().complete_config(), "pass\n")
|
||||
|
||||
assert res.lower() == "pass\n"
|
||||
|
||||
|
||||
def test_new_line_at_start_returns():
|
||||
# Language Checker should return True by stripping new line
|
||||
# but the new line should be returned to the user as new lines are important
|
||||
res = decrypt(Config().library_default().complete_config(), "\npass\n")
|
||||
|
||||
assert res.lower() == "\npass\n"
|
||||
|
||||
|
||||
def test_base58_normal():
|
||||
def test_base58_bitcoin():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"6qYhNwsP46Mn4gy6gyANfsMm2icAxGFA6gnFjVm9phYHeby7PZm3vthiXxSU77teQgTFGbHETn",
|
||||
|
@ -158,20 +62,13 @@ def test_base62():
|
|||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_base91():
|
||||
def test_base64():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
">OwJh>=/fV@$x88j9ZNKB*ge$yV%lE%ZKi,<d,TX2$0t,,cjPD@JY<UCHRWznuWoQPD",
|
||||
"SGVsbG8gbXkgbmFtZSBpcyBiZWUgYW5kIEkgbGlrZSBkb2cgYW5kIGFwcGxlIGFuZCB0cmVl",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_decimal():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"72 101 108 108 111 32 109 121 32 110 97 109 101 32 105 115 32 98 101 101 32 97 110 100 32 73 32 108 105 107 101 32 100 111 103 32 97 110 100 32 97 112 112 108 101 32 97 110 100 32 116 114 101 101",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_base69():
|
||||
|
@ -182,7 +79,107 @@ def test_base69():
|
|||
assert res == answer_str
|
||||
|
||||
|
||||
def test_base69():
|
||||
def test_base85():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"87cURD]inB+DtV)AKY].+C\\nn+CT.u+A!\\lBkq9&A8c*'@;]Tu@;p1%AKYE!A0>u7ARt",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_base91():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
">OwJh>=/fV@$x88j9ZNKB*ge$yV%lE%ZKi,<d,TX2$0t,,cjPD@JY<UCHRWznuWoQPD",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_baudot():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"10100 00001 10010 10010 11000 00100 11100 10101 00100 01100 00011 11100 00001 00100 00110 00101 00100 11001 00001 00001 00100 00011 01100 01001 00100 00110 00100 10010 00110 01111 00001 00100 01001 11000 11010 00100 00011 01100 01001 00100 00011 10110 10110 10010 00001 00100 00011 01100 01001 00100 10000 01010 00001 00001",
|
||||
)
|
||||
assert res == answer_str.upper()
|
||||
|
||||
|
||||
def test_binary():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"01001000 01100101 01101100 01101100 01101111 00100000 01101101 01111001 00100000 01101110 01100001 01101101 01100101 00100000 01101001 01110011 00100000 01100010 01100101 01100101 00100000 01100001 01101110 01100100 00100000 01001001 00100000 01101100 01101001 01101011 01100101 00100000 01100100 01101111 01100111 00100000 01100001 01101110 01100100 00100000 01100001 01110000 01110000 01101100 01100101 00100000 01100001 01101110 01100100 00100000 01110100 01110010 01100101 01100101",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_binary_base64_caesar():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"01010110 01011000 01001010 00110101 01100101 01010111 01001001 01100111 01100101 01101101 01110111 01100111 01011001 01010111 00110101 00110110 01100011 01101001 01000010 00110010 01011010 01101001 01000010 01110110 01100011 01101110 01001001 01100111 01100010 01101101 01000110 01111000 01001001 01000110 01011001 01100111 01100101 01011000 01011010 00110100 01100011 01101001 01000010 01111000 01011001 01101110 01010001 01100111 01100010 01101101 01000110 01111000 01001001 01000111 00110101 01101010 01011001 00110011 01101100 01111001 01001001 01000111 00110101 01101000 01100011 01010011 01000010 01101110 01011010 01011000 01001010 01111001 00001010",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_brainfuck():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"+[+++++++>+<]>-.-[+>-----<]>++.+++++++..+++.+[+>++<]>.[++>+<]>---.--[+++>-<]>.-[+>++++<]>.[++>+<]>--.-[+++>++<]>-.+[-->---<]>.--------.[+++++>+<]>+.-[+++>--<]>-.++++++++++.---[+>++<]>.[+++>-<]>++.+++..[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.-[+++>+<]>--.-[+>----<]>.++[+++>--<]>.---.++.------.[+++++>+<]>+.+[+>---<]>+.+++++++++++.--------.-[+++>-<]>--.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[+++>-<]>+.-[-->---<]>..----.-------.[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[++>+<]>++++.--.-------------..",
|
||||
)
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_brandon():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"R hvv blf tzgsvi yvuliv nv...sfmtib...gviirurvw... Xofgxsrmt blfi yzyvh gl blfi yivzhg. Vnkvili Vnsbi srh nzixsvw srh ovtrlmh rmgl lfi ozmwh... Ozrw hrvtv gl vevib uligivhh uiln sviv gl gsv Yofv Nlfmgzrmh. Izyrw zmw izevmlfh, sv yrgvh zmw yrgvh zdzb. Nvm lu gsv Mligs, blf hgzmw zg gsv kivxrkrxv. Blfi prmth szev uzrovw blf, hl mld blf gfim gl gsv tlwh! Zmw bvg blf wl mlg kovzw? Blf wl mlg pmvvo gl wfhg blfi svzwh drgs zhs? Rmhgvzw blf dzro, Dsb szev gsv tlwh ulihzpvm fh? Dv nfhg ollp rmgl gsv girzoh dv uzrovw olmt ztl! Rm z grnv kzhhvw, lfi dliow rmgvigdrmvw drgs zmlgsvi gsilfts zm fksvzezo hxslozih xzoo gsv Xlmqfmxgrlm lu gsv Hksvivh... Gsv tlwh zooldvw fmslob ulixvh gl hork rmgl lfi wlnzrm. Gsv luuhkirmt lu gszg xzgzxobhn dzh gsv mvuvirlfh ulixv xzoovw nztrx... Bvg dv wrw mlg yzmrhs rg, rmhgvzw hgfwbrmt gsv erov zixzmv uli lfi kldvi zmw dvzogs! Zmw gsv nlmhgvih zg lfi wlli...gsv fmslob ivorxgh lu gsrh Xlmqfmxgrlm? ...gsv gilooh...gsv xlikhv vzgvih...gsv dvivdloevh? Wrw dv izrhv lfi hdliwh ztzrmhg gsvn? Li szev dv ozrw gsrh yfiwvm lm lgsvih? Lm hl-xzoovw drgxsvih? Hgizb xsrowivm gzftsg gsv dzbh lu ulfo hlixvib, gsvri ylwrvh nfgzgvw gsilfts yozhksvnlfh irgfzo. Hvmg gl urtsg nlmhgvih gslfts gsvb xlfow mlg wrhgrmtfrhs tllw uiln vero. Gsv uorxpvi lu sfnzmrgb olmt vcgrmtfrhsvw drgsrm gsvn. Bvh, gsvri mfnyvih szev wdrmwovw gsilfts gsv bvzih. Yfg z uvd hgroo ilzn lfi ozmwh, luuvirmt gsvri yollwb dlip uli xlrm. Gl gsrh wzb gsvb hsznv fh drgs gsvri evib vcrhgvmxv! Gsv Mligs yovvwh, uolttvw yb dzi. Gsv yzggovh ziv gsv tlwh' dsrk, xszhgrhvnvmg uli lfi hrmh! Zmw ovg fh mlg ulitvg gsv gviilih, gsv hxlfitvh uiln yvblmw lfi dliow! Gsv Drow Sfmg irwvh gsv hpb drgs vevib ufoo nllm! Gsv wzip izrwvih zywfxg lfi xsrowivm rmgl ozmwh fmpmldm! Hlnv hzb gsvb svizow z hvxlmw Xlmqfmxgrlm! Xzm dv xszig z xlfihv yzxp rmgl gsv ortsg? Droo dv urmw gsv hgivmtgs gl yzmrhs gsv nztvh uiln lfi prmtwlnh? Fmrgv zilfmw gsv dzings lu gsv Vgvimzo Uriv? Mrts rh gsv Grnv lu gsv Hdliw zmw gsv Zcv! Mlmv droo urtsg gsrh dzi rm lfi hgvzw! Mrts rh gsv Grnv lu Nzwmvhh zmw Wrhwzrm!",
|
||||
)
|
||||
assert bool(res) is True
|
||||
|
||||
|
||||
def test_caesar():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"Uryyb zl anzr vf orr naq V yvxr qbt naq nccyr naq gerr",
|
||||
)
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_decimal():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"72 101 108 108 111 32 109 121 32 110 97 109 101 32 105 115 32 98 101 101 32 97 110 100 32 73 32 108 105 107 101 32 100 111 103 32 97 110 100 32 97 112 112 108 101 32 97 110 100 32 116 114 101 101",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_galactic():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"⍑ᒷꖎꖎ𝙹 ᒲ|| リᔑᒲᒷ ╎ᓭ ʖᒷᒷ ᔑリ↸ i ꖎ╎ꖌᒷ ↸𝙹⊣ ᔑリ↸ ᔑ!¡!¡ꖎᒷ ᔑリ↸ ℸ ̣ ∷ᒷᒷ",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_galactic_Xproblem():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"⍑ᔑꖎ╎⎓ᔑ ̇/, ̇/||ꖎ𝙹!¡⍑𝙹リᒷ, ᔑ ̇/ ᔑꖎ𝙹リᒷ ᔑリ↸ ̇/ᒷ∷𝙹 ̇/ ⎓∷𝙹ᒲ 𝙹 ̇/⎓𝙹∷↸",
|
||||
)
|
||||
assert res.lower() == "halifax, xylophone, a x alone and xerox from oxford"
|
||||
|
||||
|
||||
def test_hexadecimal():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"48 65 6c 6c 6f 20 6d 79 20 6e 61 6d 65 20 69 73 20 62 65 65 20 61 6e 64 20 49 20 6c 69 6b 65 20 64 6f 67 20 61 6e 64 20 61 70 70 6c 65 20 61 6e 64 20 74 72 65 65",
|
||||
)
|
||||
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_json_problem():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"0110100001100101011011000110110001101111",
|
||||
|
@ -190,10 +187,18 @@ def test_base69():
|
|||
assert res != "0110100001100101011011000110110001101111"
|
||||
|
||||
|
||||
def test_baudot():
|
||||
def test_leetspeak():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"10100 00001 10010 10010 11000 00100 11100 10101 00100 01100 00011 11100 00001 00100 00110 00101 00100 11001 00001 00001 00100 00011 01100 01001 00100 00110 00100 10010 00110 01111 00001 00100 01001 11000 11010 00100 00011 01100 01001 00100 00011 10110 10110 10010 00001 00100 00011 01100 01001 00100 10000 01010 00001 00001",
|
||||
"|-|3ll0 my n4m3 1s 833 4nd 1 l1k3 D06 4ND 4ppl3 4nd 7R33",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_morse_code():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
".... . .-.. .-.. ---/-- -.--/-. .- -- ./.. .../-... . ./.- -. -../../.-.. .. -.- ./-.. --- --./.- -. -../.- .--. .--. .-.. ./.- -. -../- .-. . .",
|
||||
)
|
||||
assert res == answer_str.upper()
|
||||
|
||||
|
@ -206,14 +211,59 @@ def test_multi_tap():
|
|||
assert res == answer_str.upper()
|
||||
|
||||
|
||||
def test_url():
|
||||
def test_new_line_at_start_returns():
|
||||
# Language Checker should return True by stripping new line
|
||||
# but the new line should be returned to the user as new lines are important
|
||||
res = decrypt(Config().library_default().complete_config(), "\npass\n")
|
||||
|
||||
assert res.lower() == "\npass\n"
|
||||
|
||||
|
||||
def test_new_line_strip_and_return():
|
||||
# Language Checker should return True by stripping new line
|
||||
# but the new line should be returned to the user as new lines are important
|
||||
res = decrypt(Config().library_default().complete_config(), "pass\n")
|
||||
|
||||
assert res.lower() == "pass\n"
|
||||
|
||||
|
||||
def test_octal():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"Hello%20my%20name%20is%20bee%20and%20I%20like%20dog%20and%20apple%20and%20tree",
|
||||
"110 145 154 154 157 40 155 171 40 156 141 155 145 40 151 163 40 142 145 145 40 141 156 144 40 111 40 154 151 153 145 40 144 157 147 40 141 156 144 40 141 160 160 154 145 40 141 156 144 40 164 162 145 145",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_plaintext():
|
||||
res = decrypt(Config().library_default().complete_config(), answer_str)
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_reversed_text():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"eert dna elppa dna god ekil I dna eeb si eman ym olleH",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
||||
def test_rot47():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"$A9:?I @7 3=24< BF2CEK[ ;F586 >J G@H",
|
||||
)
|
||||
assert res == "Sphinx of black quartz, judge my vow"
|
||||
|
||||
|
||||
def test_soundex():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"H236 I200 I500 T000 P230",
|
||||
)
|
||||
assert res.lower() == "history is in the past"
|
||||
|
||||
|
||||
def test_tap_code():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
|
@ -222,34 +272,10 @@ def test_tap_code():
|
|||
assert res == "test one two three".upper()
|
||||
|
||||
|
||||
def test_brandon():
|
||||
def test_url():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"R hvv blf tzgsvi yvuliv nv...sfmtib...gviirurvw... Xofgxsrmt blfi yzyvh gl blfi yivzhg. Vnkvili Vnsbi srh nzixsvw srh ovtrlmh rmgl lfi ozmwh... Ozrw hrvtv gl vevib uligivhh uiln sviv gl gsv Yofv Nlfmgzrmh. Izyrw zmw izevmlfh, sv yrgvh zmw yrgvh zdzb. Nvm lu gsv Mligs, blf hgzmw zg gsv kivxrkrxv. Blfi prmth szev uzrovw blf, hl mld blf gfim gl gsv tlwh! Zmw bvg blf wl mlg kovzw? Blf wl mlg pmvvo gl wfhg blfi svzwh drgs zhs? Rmhgvzw blf dzro, Dsb szev gsv tlwh ulihzpvm fh? Dv nfhg ollp rmgl gsv girzoh dv uzrovw olmt ztl! Rm z grnv kzhhvw, lfi dliow rmgvigdrmvw drgs zmlgsvi gsilfts zm fksvzezo hxslozih xzoo gsv Xlmqfmxgrlm lu gsv Hksvivh... Gsv tlwh zooldvw fmslob ulixvh gl hork rmgl lfi wlnzrm. Gsv luuhkirmt lu gszg xzgzxobhn dzh gsv mvuvirlfh ulixv xzoovw nztrx... Bvg dv wrw mlg yzmrhs rg, rmhgvzw hgfwbrmt gsv erov zixzmv uli lfi kldvi zmw dvzogs! Zmw gsv nlmhgvih zg lfi wlli...gsv fmslob ivorxgh lu gsrh Xlmqfmxgrlm? ...gsv gilooh...gsv xlikhv vzgvih...gsv dvivdloevh? Wrw dv izrhv lfi hdliwh ztzrmhg gsvn? Li szev dv ozrw gsrh yfiwvm lm lgsvih? Lm hl-xzoovw drgxsvih? Hgizb xsrowivm gzftsg gsv dzbh lu ulfo hlixvib, gsvri ylwrvh nfgzgvw gsilfts yozhksvnlfh irgfzo. Hvmg gl urtsg nlmhgvih gslfts gsvb xlfow mlg wrhgrmtfrhs tllw uiln vero. Gsv uorxpvi lu sfnzmrgb olmt vcgrmtfrhsvw drgsrm gsvn. Bvh, gsvri mfnyvih szev wdrmwovw gsilfts gsv bvzih. Yfg z uvd hgroo ilzn lfi ozmwh, luuvirmt gsvri yollwb dlip uli xlrm. Gl gsrh wzb gsvb hsznv fh drgs gsvri evib vcrhgvmxv! Gsv Mligs yovvwh, uolttvw yb dzi. Gsv yzggovh ziv gsv tlwh' dsrk, xszhgrhvnvmg uli lfi hrmh! Zmw ovg fh mlg ulitvg gsv gviilih, gsv hxlfitvh uiln yvblmw lfi dliow! Gsv Drow Sfmg irwvh gsv hpb drgs vevib ufoo nllm! Gsv wzip izrwvih zywfxg lfi xsrowivm rmgl ozmwh fmpmldm! Hlnv hzb gsvb svizow z hvxlmw Xlmqfmxgrlm! Xzm dv xszig z xlfihv yzxp rmgl gsv ortsg? Droo dv urmw gsv hgivmtgs gl yzmrhs gsv nztvh uiln lfi prmtwlnh? Fmrgv zilfmw gsv dzings lu gsv Vgvimzo Uriv? Mrts rh gsv Grnv lu gsv Hdliw zmw gsv Zcv! Mlmv droo urtsg gsrh dzi rm lfi hgvzw! Mrts rh gsv Grnv lu Nzwmvhh zmw Wrhwzrm!",
|
||||
)
|
||||
assert True
|
||||
|
||||
|
||||
def test_affine():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"Ihsst bf kxbh rd ghh xky R srjh ytz xky xccsh xky muhh",
|
||||
)
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_brainfuck():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"+[+++++++>+<]>-.-[+>-----<]>++.+++++++..+++.+[+>++<]>.[++>+<]>---.--[+++>-<]>.-[+>++++<]>.[++>+<]>--.-[+++>++<]>-.+[-->---<]>.--------.[+++++>+<]>+.-[+++>--<]>-.++++++++++.---[+>++<]>.[+++>-<]>++.+++..[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.-[+++>+<]>--.-[+>----<]>.++[+++>--<]>.---.++.------.[+++++>+<]>+.+[+>---<]>+.+++++++++++.--------.-[+++>-<]>--.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[+++>-<]>+.-[-->---<]>..----.-------.[+++++>+<]>+.[+++>-<]>+.+[-->---<]>+.----------.-[+++>-<]>-.[++>+<]>++++.--.-------------..",
|
||||
)
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_ascii_shift():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"\"?FFIzGSzH;G?zCMz<??z;H>z#zFCE?z>IAz;H>z;JJF?z;H>zNL??",
|
||||
"Hello%20my%20name%20is%20bee%20and%20I%20like%20dog%20and%20apple%20and%20tree",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
||||
|
@ -257,18 +283,28 @@ def test_ascii_shift():
|
|||
def test_uuencode():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"begin 644 /dev/stdout\nM2&5L;&\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9\"!T<F5E\n`\nend\n"
|
||||
'begin 644 /dev/stdout\nM2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n`\nend\n',
|
||||
)
|
||||
assert res == answer_str
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"M2&5L;&\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9\"!T<F5E\n"
|
||||
'M2&5L;&\\@;7D@;F%M92!I<R!B964@86YD($D@;&EK92!D;V<@86YD(&%P<&QE\n)(&%N9"!T<F5E\n',
|
||||
)
|
||||
assert res == answer_str
|
||||
|
||||
def test_soundex():
|
||||
|
||||
def test_vigenere():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"H236 I200 I500 T000 P230",
|
||||
"Rijvs ki rywi gc fco eln M jsoc nse krb ktnvi yxh rbic",
|
||||
)
|
||||
assert "history is in the past" == res
|
||||
|
||||
assert res == answer_str
|
||||
|
||||
|
||||
def test_xandy():
|
||||
res = decrypt(
|
||||
Config().library_default().complete_config(),
|
||||
"xDDxDxxx xDDxxDxD xDDxDDxx xDDxDDxx xDDxDDDD xxDxxxxx xDDxDDxD xDDDDxxD xxDxxxxx xDDxDDDx xDDxxxxD xDDxDDxD xDDxxDxD xxDxxxxx xDDxDxxD xDDDxxDD xxDxxxxx xDDxxxDx xDDxxDxD xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDxxDxxD xxDxxxxx xDDxDDxx xDDxDxxD xDDxDxDD xDDxxDxD xxDxxxxx xDDxxDxx xDDxDDDD xDDxxDDD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDxxxxD xDDDxxxx xDDDxxxx xDDxDDxx xDDxxDxD xxDxxxxx xDDxxxxD xDDxDDDx xDDxxDxx xxDxxxxx xDDDxDxx xDDDxxDx xDDxxDxD xDDxxDxD",
|
||||
)
|
||||
assert res.lower() == answer_str.lower()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
import cipheycore
|
||||
|
||||
data = sys.stdin.read()
|
||||
|
|
Loading…
Reference in New Issue