├── tests ├── __init__.py ├── cli.py ├── test_regex.py ├── test_click.py ├── test_quick.py ├── test_click_printing.py ├── dict.py ├── generate_tests.py ├── lukas.py └── test_advanced_ciphers.py ├── .github ├── config.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ ├── maintenance_suggestion.md │ └── bug_report.md ├── release-drafter.yml ├── FUNDING.yml ├── dependabot.yml ├── workflows │ ├── release.yml │ ├── releasetestpypi.yml │ ├── tests2.yml │ ├── coverage.yml │ └── terminaltest.yml └── lock.yml ├── ciphey ├── basemods │ ├── Searchers │ │ ├── __init__.py │ │ └── perfection.py │ ├── Resources │ │ ├── __init__.py │ │ ├── cipheydists.py │ │ └── files.py │ ├── __init__.py │ ├── Checkers │ │ ├── __init__.py │ │ ├── any.py │ │ ├── gtest.py │ │ ├── entropy.py │ │ ├── format.py │ │ ├── human.py │ │ ├── quorum.py │ │ ├── ezcheck.py │ │ ├── what.py │ │ ├── quadgrams.py │ │ └── regex.py │ ├── Crackers │ │ ├── __init__.py │ │ ├── xortool.py │ │ ├── baconian.py │ │ ├── rot47.py │ │ ├── ascii_shift.py │ │ ├── caesar.py │ │ ├── xandy.py │ │ └── hash.py │ └── Decoders │ │ ├── __init__.py │ │ ├── reverse.py │ │ ├── letters.archive │ │ ├── base91.py │ │ ├── base62.py │ │ ├── hexadecimal.py │ │ ├── gzip.py │ │ ├── base65536.py │ │ ├── base58_bitcoin.py │ │ ├── base64_url.py │ │ ├── base58_ripple.py │ │ ├── leetspeak.py │ │ ├── base58_flickr.py │ │ ├── unicode.py │ │ ├── z85.py │ │ ├── url.py │ │ ├── tap_code.py │ │ ├── baudot.py │ │ ├── dna.py │ │ ├── dtmf.py │ │ ├── bases.py │ │ ├── octal.py │ │ ├── binary.py │ │ ├── decimal.py │ │ ├── a1z26.py │ │ ├── atbash.py │ │ ├── uuencode.py │ │ ├── braille.py │ │ ├── multi_tap.py │ │ ├── base69.py │ │ ├── galactic.py │ │ └── morse_code.py ├── iface │ ├── _fwd.py │ └── __init__.py ├── __init__.py ├── common.py └── __main__.py ├── Pictures_for_README ├── .gitattributes ├── 3ways.gif ├── apple.png ├── arch.png ├── index.gif ├── docker.png ├── homebrew.png ├── lock1k1k.png ├── macports.png ├── python.png ├── windows.png ├── binoculars.png ├── lock250250.png ├── not_dying.gif ├── lock_text_1k1k.png ├── Favorites │ └── binoculars.jpg └── ciphey_gooder_cyberchef.gif ├── tools └── freq_analysis.py ├── codecov.yml ├── license ├── pyproject.toml ├── noxfile.py ├── translations ├── zh │ ├── CODE_OF_CONDUCT.md │ └── CONTRIBUTING.md ├── hu │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md ├── ru │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md ├── pt-br │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md ├── nl │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md ├── it │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md ├── id │ ├── CONTRIBUTING.md │ └── CODE_OF_CONDUCT.md └── de │ └── CODE_OF_CONDUCT.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── .gitignore /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | todo: 2 | keyword: "@TODO" 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /ciphey/basemods/Searchers/__init__.py: -------------------------------------------------------------------------------- 1 | from . import ausearch 2 | -------------------------------------------------------------------------------- /ciphey/iface/_fwd.py: -------------------------------------------------------------------------------- 1 | registry = None 2 | config = type(None) 3 | -------------------------------------------------------------------------------- /ciphey/basemods/Resources/__init__.py: -------------------------------------------------------------------------------- 1 | from . import cipheydists, files 2 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | template: | 2 | ## What’s Changed 3 | 4 | $CHANGES 5 | -------------------------------------------------------------------------------- /ciphey/__init__.py: -------------------------------------------------------------------------------- 1 | from . import basemods, common, iface 2 | from .ciphey import decrypt 3 | -------------------------------------------------------------------------------- /Pictures_for_README/.gitattributes: -------------------------------------------------------------------------------- 1 | render1596301769504.gif filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /ciphey/basemods/__init__.py: -------------------------------------------------------------------------------- 1 | from . import Checkers, Crackers, Decoders, Resources, Searchers 2 | -------------------------------------------------------------------------------- /Pictures_for_README/3ways.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/3ways.gif -------------------------------------------------------------------------------- /Pictures_for_README/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/apple.png -------------------------------------------------------------------------------- /Pictures_for_README/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/arch.png -------------------------------------------------------------------------------- /Pictures_for_README/index.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/index.gif -------------------------------------------------------------------------------- /Pictures_for_README/docker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/docker.png -------------------------------------------------------------------------------- /Pictures_for_README/homebrew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/homebrew.png -------------------------------------------------------------------------------- /Pictures_for_README/lock1k1k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/lock1k1k.png -------------------------------------------------------------------------------- /Pictures_for_README/macports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/macports.png -------------------------------------------------------------------------------- /Pictures_for_README/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/python.png -------------------------------------------------------------------------------- /Pictures_for_README/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/windows.png -------------------------------------------------------------------------------- /Pictures_for_README/binoculars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/binoculars.png -------------------------------------------------------------------------------- /Pictures_for_README/lock250250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/lock250250.png -------------------------------------------------------------------------------- /Pictures_for_README/not_dying.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/not_dying.gif -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/__init__.py: -------------------------------------------------------------------------------- 1 | from . import any, brandon, ezcheck, format, human, quadgrams, quorum, regex, what 2 | -------------------------------------------------------------------------------- /Pictures_for_README/lock_text_1k1k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/lock_text_1k1k.png -------------------------------------------------------------------------------- /Pictures_for_README/Favorites/binoculars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/Favorites/binoculars.jpg -------------------------------------------------------------------------------- /Pictures_for_README/ciphey_gooder_cyberchef.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e1abrador/Ciphey/master/Pictures_for_README/ciphey_gooder_cyberchef.gif -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: bee-san 4 | custom: ["https://www.buymeacoffee.com/beecodes", "https://paypal.me/cipheydevs"] 5 | -------------------------------------------------------------------------------- /tests/cli.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from sys import exit 3 | 4 | result = subprocess.check_output(["ciphey", "-q", "-t 'hello'"]) 5 | 6 | if "hello" in result: 7 | exit(0) 8 | else: 9 | exit(1) 10 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/__init__.py: -------------------------------------------------------------------------------- 1 | from . import ( 2 | affine, 3 | ascii_shift, 4 | baconian, 5 | caesar, 6 | rot47, 7 | soundex, 8 | vigenere, 9 | xandy, 10 | xortool, 11 | ) 12 | -------------------------------------------------------------------------------- /tools/freq_analysis.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | 4 | import cipheycore 5 | 6 | data = sys.stdin.read() 7 | 8 | analysis = cipheycore.analyse_string(data) 9 | 10 | print(json.dumps({i: j / len(data) for i, j in analysis.freqs.items()})) 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | ignore: 9 | - dependency-name: black 10 | versions: 11 | - 21.4b0 12 | - 21.4b1 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: brandonskerritt 7 | 8 | --- 9 | ### Problem: 10 | _What exactly do you think is missing? How does it impact you? Are there any hacks that people use instead?_ 11 | 12 | ### Solution: 13 | _How could this problem be solved? What could be added? How could it be integrated into the current system?_ 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/maintenance_suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Maintenance suggestion 3 | about: Suggest refactoring/restructuring that would help 4 | title: '' 5 | labels: maintenance 6 | assignees: brandonskerritt 7 | 8 | --- 9 | ### Idea 10 | _What exactly do you want to do?_ 11 | 12 | ### Pros 13 | _How would it help the code? Does it make things faster, or the code more maintainable?_ 14 | 15 | ### Cons 16 | _Would this break anything? Would it mean a rewrite of all the code?_ 17 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/__init__.py: -------------------------------------------------------------------------------- 1 | from . import ( 2 | a1z26, 3 | atbash, 4 | base58_bitcoin, 5 | base58_ripple, 6 | base62, 7 | base69, 8 | base91, 9 | bases, 10 | baudot, 11 | binary, 12 | braille, 13 | brainfuck, 14 | decimal, 15 | dna, 16 | dtmf, 17 | galactic, 18 | gzip, 19 | hexadecimal, 20 | leetspeak, 21 | morse_code, 22 | multi_tap, 23 | octal, 24 | reverse, 25 | tap_code, 26 | unicode, 27 | url, 28 | uuencode, 29 | ) 30 | -------------------------------------------------------------------------------- /ciphey/basemods/Searchers/perfection.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional, Set 2 | 3 | from ciphey.iface import Config, ParamSpec, registry 4 | 5 | from .ausearch import AuSearch, Node 6 | 7 | 8 | @registry.register 9 | class Perfection(AuSearch): 10 | @staticmethod 11 | def getParams() -> Optional[Dict[str, ParamSpec]]: 12 | return None 13 | 14 | def findBestNode(self, nodes: Set[Node]) -> Node: 15 | return next(iter(nodes)) 16 | 17 | def __init__(self, config: Config): 18 | super().__init__(config) 19 | -------------------------------------------------------------------------------- /ciphey/iface/__init__.py: -------------------------------------------------------------------------------- 1 | from ._config import Config 2 | 3 | from ._modules import ( 4 | Checker, 5 | Cracker, 6 | CrackInfo, 7 | CrackResult, 8 | Decoder, 9 | DecoderComparer, 10 | Distribution, 11 | ParamSpec, 12 | PolymorphicChecker, 13 | ResourceLoader, 14 | Searcher, 15 | SearchLevel, 16 | SearchResult, 17 | T, 18 | Translation, 19 | U, 20 | WordList, 21 | pretty_search_results, 22 | ) 23 | from ._registry import get_args, get_origin 24 | 25 | from ._fwd import registry 26 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "40...50" 8 | status: 9 | patch: no 10 | changes: no 11 | project: 12 | default: 13 | threshold: 2% 14 | paths: 15 | - "ciphey" 16 | 17 | parsers: 18 | gcov: 19 | branch_detection: 20 | conditional: yes 21 | loop: yes 22 | method: no 23 | macro: no 24 | 25 | comment: 26 | layout: "reach,diff,flags,tree" 27 | behavior: default 28 | require_changes: no 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/release.yml 2 | name: Release 3 | on: 4 | release: 5 | types: [published] 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-python@v1 12 | with: 13 | python-version: '3.8' 14 | architecture: x64 15 | - run: pip install nox 16 | - run: pip install poetry 17 | - run: nox 18 | - run: poetry build 19 | - run: poetry publish --username=__token__ --password=${{ secrets.PYPI_TOKEN }} 20 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/any.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Config, ParamSpec, PolymorphicChecker, registry 4 | 5 | 6 | @registry.register 7 | class Any(PolymorphicChecker): 8 | """Should only be used for debugging, frankly""" 9 | 10 | def getExpectedRuntime(self, text) -> float: 11 | return 0 # TODO: actually calculate this 12 | 13 | def __init__(self, config: Config): 14 | super().__init__(config) 15 | 16 | def check(self, text: str) -> Optional[str]: 17 | return "" 18 | 19 | @staticmethod 20 | def getParams() -> Optional[Dict[str, ParamSpec]]: 21 | pass 22 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/reverse.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 4 | 5 | 6 | @registry.register 7 | class Reverse(Decoder[str]): 8 | def decode(self, ctext: T) -> Optional[U]: 9 | return ctext[::-1] 10 | 11 | @staticmethod 12 | def priority() -> float: 13 | return 0.05 14 | 15 | def __init__(self, config: Config): 16 | super().__init__(config) 17 | 18 | @staticmethod 19 | def getParams() -> Optional[Dict[str, ParamSpec]]: 20 | return None 21 | 22 | @staticmethod 23 | def getTarget() -> str: 24 | return "reverse" 25 | -------------------------------------------------------------------------------- /ciphey/common.py: -------------------------------------------------------------------------------- 1 | """Some useful adapters""" 2 | from typing import Any 3 | 4 | 5 | def id_lambda(value: Any): 6 | """ 7 | A function used in dynamic class generation that abstracts away a constant return value (like in getName) 8 | """ 9 | return lambda *args: value 10 | 11 | 12 | def fix_case(target: str, base: str) -> str: 13 | """Returns the lower-case string target with the case of base""" 14 | ret = "".join( 15 | [ 16 | target[i].upper() if base[i].isupper() else target[i] 17 | for i in range(len(target)) 18 | ] 19 | ) 20 | return "".join( 21 | [ 22 | target[i].upper() if base[i].isupper() else target[i] 23 | for i in range(len(target)) 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /tests/test_regex.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from ciphey import decrypt 4 | from ciphey.iface import Config 5 | 6 | 7 | def test_regex_ip(): 8 | res = decrypt( 9 | Config().library_default().complete_config(), 10 | "MTkyLjE2MC4wLjE=", 11 | ) 12 | assert res == "192.160.0.1" 13 | 14 | 15 | def test_regex_domain(): 16 | res = decrypt( 17 | Config().library_default().complete_config(), 18 | "aHR0cHM6Ly9nb29nbGUuY29t", 19 | ) 20 | assert res == "https://google.com" 21 | 22 | 23 | def test_regex_bitcoin(): 24 | res = decrypt( 25 | Config().library_default().complete_config(), 26 | "M0ZaYmdpMjljcGpxMkdqZHdWOGV5SHVKSm5rTHRrdFpjNQ==", 27 | ) 28 | assert res == "3FZbgi29cpjq2GjdwV8eyHuJJnkLtktZc5" 29 | -------------------------------------------------------------------------------- /.github/workflows/releasetestpypi.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/test-pypi.yml 2 | name: TestPyPI 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | test_pypi: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-python@v1 13 | with: 14 | python-version: '3.8' 15 | architecture: x64 16 | - run: pip install poetry 17 | - run: >- 18 | poetry version patch && 19 | version=$(poetry version | awk '{print $2}') && 20 | poetry version $version.dev.$(date +%s) 21 | - run: poetry build 22 | - uses: pypa/gh-action-pypi-publish@v1.0.0a0 23 | with: 24 | user: __token__ 25 | password: ${{ secrets.TEST_PYPI_TOKEN }} 26 | repository_url: https://test.pypi.org/legacy/ 27 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/gtest.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 7 | 8 | 9 | @registry.register 10 | class GTestChecker(Checker[str]): 11 | 12 | """ 13 | G-test of fitness, similar to Chi squared. 14 | """ 15 | 16 | def check(self, text: T) -> Optional[str]: 17 | logging.debug("Trying entropy checker") 18 | pass 19 | 20 | def getExpectedRuntime(self, text: T) -> float: 21 | # TODO: actually bench this 22 | return 4e-7 * len(text) 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | pass 30 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/entropy.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 7 | 8 | 9 | @registry.register 10 | class Entropy(Checker[str]): 11 | 12 | """ 13 | Uses entropy to determine plaintext 14 | """ 15 | 16 | def check(self, text: T) -> Optional[str]: 17 | logging.debug("Trying entropy checker") 18 | pass 19 | 20 | def getExpectedRuntime(self, text: T) -> float: 21 | # TODO: actually bench this 22 | # Uses benchmark from Discord 23 | return 2e-7 * len(text) 24 | 25 | def __init__(self, config: Config): 26 | super().__init__(config) 27 | 28 | @staticmethod 29 | def getParams() -> Optional[Dict[str, ParamSpec]]: 30 | pass 31 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/letters.archive: -------------------------------------------------------------------------------- 1 | """ 2 | Not yet implemented. 3 | """ 4 | class letters: 5 | 6 | """Deals with Nato Strings / first letter of every word""" 7 | 8 | def __init__(self): 9 | None 10 | 11 | def __name__(self): 12 | return "Letters" 13 | 14 | def decrypt(self, text: str) -> dict: 15 | return text 16 | 17 | def first_letter_every_word(self, text): 18 | """ 19 | This should be supplied a string like "hello my name is" 20 | """ 21 | 22 | text = text.split(".") 23 | 24 | new_text = [] 25 | for sentence in text: 26 | for word in sentence.split(" "): 27 | new_text.append(word[0]) 28 | # Applies a space after every sentence 29 | # which might be every word 30 | new_text.append(" ") 31 | -------------------------------------------------------------------------------- /.github/workflows/tests2.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | jobs: 4 | tests: 5 | strategy: 6 | fail-fast: false 7 | matrix: 8 | python-version: ['3.7', '3.8', '3.9'] 9 | os: [ubuntu-latest, windows-latest] #macos-latest, 10 | runs-on: ${{ matrix.os }} 11 | name: Python ${{ matrix.python-version }} on ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-python@v2 15 | with: 16 | python-version: ${{ matrix.python-version }} 17 | architecture: x64 18 | - run: python -m pip install --upgrade pip 19 | - run: pip install codespell flake8 nox poetry 20 | - run: codespell --ignore-words-list="nd,te" --skip="translations,*.archive" 21 | - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 22 | - run: python -m nox 23 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base91.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base91 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base91(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base91 decoding 13 | """ 14 | try: 15 | return base91.decode(ctext).decode("utf-8") 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | # Not expected to show up often, but also very fast to check. 22 | return 0.05 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | return None 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "base91" 34 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base62.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base62 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base62(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base62 decoding 13 | """ 14 | try: 15 | return base62.decodebytes(ctext).decode("utf-8") 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | # Not expected to show up often, but also very fast to check. 22 | return 0.05 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | return None 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "base62" 34 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/hexadecimal.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 4 | 5 | 6 | @registry.register 7 | class Hexadecimal(Decoder[str]): 8 | def decode(self, ctext: T) -> Optional[U]: 9 | """ 10 | Performs Hexadecimal decoding 11 | """ 12 | ctext_decoded = "" 13 | try: 14 | ctext_decoded = bytearray.fromhex(ctext).decode("utf-8") 15 | return ctext_decoded 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | return 0.015 22 | 23 | def __init__(self, config: Config): 24 | super().__init__(config) 25 | 26 | @staticmethod 27 | def getParams() -> Optional[Dict[str, ParamSpec]]: 28 | return None 29 | 30 | @staticmethod 31 | def getTarget() -> str: 32 | return "hexadecimal" 33 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/gzip.py: -------------------------------------------------------------------------------- 1 | import zlib 2 | from typing import Dict, Optional 3 | 4 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 5 | 6 | 7 | @registry.register 8 | class Gzip(Decoder[bytes]): 9 | def decode(self, ctext: T) -> Optional[U]: 10 | """ 11 | Performs Gzip decoding 12 | """ 13 | try: 14 | return zlib.decompress(ctext, 16 + zlib.MAX_WBITS).decode("utf-8") 15 | except Exception: 16 | return None 17 | 18 | @staticmethod 19 | def priority() -> float: 20 | # Not expected to show up often, but also very fast to check. 21 | return 0.05 22 | 23 | def __init__(self, config: Config): 24 | super().__init__(config) 25 | 26 | @staticmethod 27 | def getParams() -> Optional[Dict[str, ParamSpec]]: 28 | return None 29 | 30 | @staticmethod 31 | def getTarget() -> str: 32 | return "gzip" 33 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base65536.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base65536 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base65536(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base65536 decoding 13 | """ 14 | try: 15 | return base65536.decode(ctext).decode("utf-8") 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | # Not expected to show up often, but also very fast to check. 22 | return 0.05 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | return None 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "base65536" 34 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base58_bitcoin.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base58 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base58_bitcoin(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base58 (Bitcoin) decoding 13 | """ 14 | try: 15 | return base58.b58decode(ctext).decode("utf-8") 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | # Not expected to show up often, but also very fast to check. 22 | return 0.05 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | return None 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "base58_bitcoin" 34 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base64_url.py: -------------------------------------------------------------------------------- 1 | import base64 2 | from typing import Dict, Optional 3 | 4 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 5 | 6 | 7 | @registry.register 8 | class Base64_url(Decoder[str]): 9 | def decode(self, ctext: T) -> Optional[U]: 10 | """ 11 | Performs Base64 URL decoding 12 | """ 13 | ctext_padding = ctext + "=" * (4 - len(ctext) % 4) 14 | try: 15 | return base64.urlsafe_b64decode(ctext_padding).decode("utf-8") 16 | except Exception: 17 | return None 18 | 19 | @staticmethod 20 | def priority() -> float: 21 | # Not expected to show up often, but also very fast to check. 22 | return 0.05 23 | 24 | def __init__(self, config: Config): 25 | super().__init__(config) 26 | 27 | @staticmethod 28 | def getParams() -> Optional[Dict[str, ParamSpec]]: 29 | return None 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "base64_url" 34 | -------------------------------------------------------------------------------- /tests/test_click.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | from ciphey.ciphey import main 3 | from ciphey.basemods.Checkers import human 4 | import mock 5 | 6 | 7 | def test_hello_world(): 8 | runner = CliRunner() 9 | result = runner.invoke(main, ["-g", "-t", "hello"]) 10 | assert result.exit_code == 0 11 | assert result.output == "hello\n" 12 | 13 | 14 | def test_ip_address(): 15 | runner = CliRunner() 16 | result = runner.invoke(main, ["-g", "-t", "MTkyLjE2OC4wLjE="]) 17 | assert result.exit_code == 0 18 | assert result.output == "192.168.0.1\n" 19 | 20 | 21 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="") 22 | def test_quick_visual_output(mock_click): 23 | # https://github.com/Ciphey/Ciphey/issues/655 24 | runner = CliRunner() 25 | mock_click.return_value = "y" 26 | result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="]) 27 | assert result.exit_code == 0 28 | assert "base32" in result.output 29 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base58_ripple.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base58 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base58_ripple(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base58 (Ripple) decoding 13 | """ 14 | try: 15 | return base58.b58decode(ctext, alphabet=base58.RIPPLE_ALPHABET).decode( 16 | "utf-8" 17 | ) 18 | except Exception: 19 | return None 20 | 21 | @staticmethod 22 | def priority() -> float: 23 | # Not expected to show up often, but also very fast to check. 24 | return 0.05 25 | 26 | def __init__(self, config: Config): 27 | super().__init__(config) 28 | 29 | @staticmethod 30 | def getParams() -> Optional[Dict[str, ParamSpec]]: 31 | return None 32 | 33 | @staticmethod 34 | def getTarget() -> str: 35 | return "base58_ripple" 36 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Copyright 2020 Brandon Skerritt 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/leetspeak.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 4 | 5 | 6 | @registry.register 7 | class Leetspeak(Decoder[str]): 8 | def decode(self, ctext: T) -> Optional[U]: 9 | for src, dst in self.translate.items(): 10 | ctext = ctext.replace(src, dst) 11 | return ctext 12 | 13 | @staticmethod 14 | def priority() -> float: 15 | return 0.05 16 | 17 | def __init__(self, config: Config): 18 | super().__init__(config) 19 | self.translate = config.get_resource(self._params()["dict"], Translation) 20 | 21 | @staticmethod 22 | def getParams() -> Optional[Dict[str, ParamSpec]]: 23 | return { 24 | "dict": ParamSpec( 25 | desc="The leetspeak dictionary to use", 26 | req=False, 27 | default="cipheydists::translate::leet", 28 | ) 29 | } 30 | 31 | @staticmethod 32 | def getTarget() -> str: 33 | return "leetspeak" 34 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base58_flickr.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import base58 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 6 | 7 | 8 | @registry.register 9 | class Base58_flickr(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Base58 (Flickr) decoding 13 | """ 14 | FLICKR_ALPHABET = b"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" 15 | try: 16 | return base58.b58decode(ctext, alphabet=FLICKR_ALPHABET).decode("utf-8") 17 | except Exception: 18 | return None 19 | 20 | @staticmethod 21 | def priority() -> float: 22 | # Not expected to show up often, but also very fast to check. 23 | return 0.05 24 | 25 | def __init__(self, config: Config): 26 | super().__init__(config) 27 | 28 | @staticmethod 29 | def getParams() -> Optional[Dict[str, ParamSpec]]: 30 | return None 31 | 32 | @staticmethod 33 | def getTarget() -> str: 34 | return "base58_flickr" 35 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, macos-latest, windows-latest] 9 | python-version: [3.6, 3.7, pypy3] 10 | # exclude: 11 | # - os: macos-latest 12 | # python-version: 3.8 13 | # - os: windows-latest 14 | # python-version: 3.6 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: ${{ matrix.python-version }} 21 | - name: Tests with Nox 22 | 23 | coverage: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v2 27 | - uses: actions/setup-python@v2 28 | with: 29 | python-version: '3.8' 30 | architecture: x64 31 | - run: pip3 install nox==2019.11.9 32 | - run: pip3 install poetry==1.0.5 33 | - run: nox --sessions tests coverage 34 | env: 35 | CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}} 36 | 37 | 38 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/format.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 8 | 9 | 10 | @registry.register 11 | class JsonChecker(Checker[str]): 12 | 13 | """ 14 | This object is effectively a prebuilt quorum (with requirement 1) of common patterns 15 | """ 16 | 17 | def check(self, text: T) -> Optional[str]: 18 | logging.debug("Trying json checker") 19 | 20 | # https://github.com/Ciphey/Ciphey/issues/389 21 | if text.isdigit(): 22 | return None 23 | 24 | try: 25 | json.loads(text) 26 | return "" 27 | except ValueError: 28 | return None 29 | 30 | def getExpectedRuntime(self, text: T) -> float: 31 | # TODO: actually bench this 32 | return 1e-7 * len(text) # From benchmarks I found online 33 | 34 | def __init__(self, config: Config): 35 | super().__init__(config) 36 | 37 | @staticmethod 38 | def getParams() -> Optional[Dict[str, ParamSpec]]: 39 | pass 40 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/unicode.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 7 | 8 | 9 | @registry.register 10 | class Utf8(Decoder[bytes]): 11 | def decode(self, ctext: T) -> Optional[U]: 12 | """ 13 | Performs UTF-8 decoding 14 | """ 15 | logging.debug("Attempting UTF-8 decoder") 16 | result = "" 17 | try: 18 | result = ctext.decode("utf-8") 19 | if result != ctext: 20 | logging.info(f"UTF-8 successful, returning '{result}'") 21 | return result 22 | else: 23 | return None 24 | except Exception: 25 | return None 26 | 27 | @staticmethod 28 | def priority() -> float: 29 | return 0.9 30 | 31 | def __init__(self, config: Config): 32 | super().__init__(config) 33 | 34 | @staticmethod 35 | def getParams() -> Optional[Dict[str, ParamSpec]]: 36 | return None 37 | 38 | @staticmethod 39 | def getTarget() -> str: 40 | return "utf8" 41 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/human.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Checker, Config, ParamSpec, registry 4 | from rich.console import Console 5 | from rich.markup import escape 6 | 7 | console = Console() 8 | 9 | 10 | @registry.register 11 | class HumanChecker(Checker[str]): 12 | 13 | """ 14 | Uses the person's decision to determine plaintext 15 | """ 16 | 17 | def check(self, ctext: str) -> Optional[str]: 18 | with self._config().pause_spinner_handle(): 19 | response = console.input( 20 | f"Possible plaintext: [blue bold]{escape(ctext.__repr__())}[/blue bold] ([green]y[/green]/[red]N[/red]): " 21 | ) 22 | if response == "y": 23 | return "" 24 | elif response in ("n", ""): 25 | return None 26 | else: 27 | return self.check(ctext) 28 | 29 | def getExpectedRuntime(self, text: str) -> float: 30 | return 1 # About a second 31 | 32 | @staticmethod 33 | def getParams() -> Optional[Dict[str, ParamSpec]]: 34 | return None 35 | 36 | def __init__(self, config: Config): 37 | super().__init__(config) 38 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "ciphey" 3 | version = "5.14.1" 4 | description = "Automated Decryption Tool" 5 | authors = ["Brandon "] 6 | license = "MIT" 7 | documentation = "https://github.com/Ciphey/Ciphey/wiki" 8 | exclude = ["tests/hansard.txt"] 9 | readme = "README.md" 10 | 11 | [tool.poetry.dependencies] 12 | python = "^3.7" 13 | rich = ">=4,<11" 14 | pyyaml = ">=5.3.1,<7.0.0" 15 | pylint = "^2.6.0" 16 | flake8 = ">=3.8.4,<5.0.0" 17 | cipheydists = "^0.3.35" 18 | cipheycore = "^0.3.2" 19 | appdirs = "^1.4.4" 20 | typing_inspect = { version = ">=0.6,<0.8", python = "~3.7" } 21 | base58 = "^2.0.1" 22 | base91 = "^1.0.1" 23 | pybase62 = ">=0.4.3,<0.6.0" 24 | click = ">=7.1.2,<9.0.0" 25 | mock = "^4.0.3" 26 | pywhat = "3.0.0" 27 | xortool-ciphey = "^0.1.16" 28 | 29 | [tool.poetry.dev-dependencies] 30 | pytest-cov = "^3.0.0" 31 | pytest = "^7.1.2" 32 | black = "^21.4b2" 33 | neovim = "^0.3.1" 34 | codecov = "^2.1.11" 35 | sphinx = "^5.0.1" 36 | sphinx-autodoc-typehints = "^1.11.1" 37 | nltk = "^3.5" 38 | 39 | [tool.poetry.scripts] 40 | ciphey = 'ciphey.ciphey:main' 41 | [build-system] 42 | requires = ["poetry-core"] 43 | build-backend = "poetry.core.masonry.api" 44 | 45 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/z85.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | from zmq.utils import z85 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 8 | 9 | 10 | @registry.register 11 | class Z85(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs Z85 decoding 15 | """ 16 | ctext_len = len(ctext) 17 | if ctext_len % 5: 18 | logging.debug( 19 | f"Failed to decode Z85 because length must be a multiple of 5, not '{ctext_len}'" 20 | ) 21 | return None 22 | try: 23 | return z85.decode(ctext).decode("utf-8") 24 | except Exception: 25 | return None 26 | 27 | @staticmethod 28 | def priority() -> float: 29 | # Not expected to show up often, but also very fast to check. 30 | return 0.05 31 | 32 | def __init__(self, config: Config): 33 | super().__init__(config) 34 | 35 | @staticmethod 36 | def getParams() -> Optional[Dict[str, ParamSpec]]: 37 | return None 38 | 39 | @staticmethod 40 | def getTarget() -> str: 41 | return "z85" 42 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/url.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | from urllib.parse import unquote_plus 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 8 | 9 | 10 | @registry.register 11 | class Url(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs URL decoding 15 | """ 16 | logging.debug("Attempting URL") 17 | result = "" 18 | try: 19 | result = unquote_plus(ctext, errors="strict") 20 | if result != ctext: 21 | logging.info(f"URL successful, returning '{result}'") 22 | return result 23 | else: 24 | return None 25 | except Exception: 26 | logging.debug("Failed to decode URL") 27 | return None 28 | 29 | @staticmethod 30 | def priority() -> float: 31 | return 0.05 32 | 33 | def __init__(self, config: Config): 34 | super().__init__(config) 35 | 36 | @staticmethod 37 | def getParams() -> Optional[Dict[str, ParamSpec]]: 38 | return None 39 | 40 | @staticmethod 41 | def getTarget() -> str: 42 | return "url" 43 | -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Lock Threads - https://github.com/dessant/lock-threads-app 2 | 3 | # Number of days of inactivity before a closed issue or pull request is locked 4 | daysUntilLock: 60 5 | 6 | # Skip issues and pull requests created before a given timestamp. Timestamp must 7 | # follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable 8 | skipCreatedBefore: false 9 | 10 | # Issues and pull requests with these labels will be ignored. Set to `[]` to disable 11 | exemptLabels: [] 12 | 13 | # Label to add before locking, such as `outdated`. Set to `false` to disable 14 | lockLabel: false 15 | 16 | # Comment to post before locking. Set to `false` to disable 17 | lockComment: > 18 | This thread has been automatically locked since there has not been 19 | any recent activity after it was closed. Please open a new issue for 20 | related bugs. 21 | 22 | # Assign `resolved` as the reason for locking. Set to `false` to disable 23 | setLockReason: true 24 | 25 | # Limit to only `issues` or `pulls` 26 | # only: issues 27 | 28 | # Optionally, specify configuration settings just for `issues` or `pulls` 29 | # issues: 30 | # exemptLabels: 31 | # - help-wanted 32 | # lockLabel: outdated 33 | 34 | # pulls: 35 | # daysUntilLock: 30 36 | 37 | # Repository to extend settings from 38 | # _extends: repo 39 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/tap_code.py: -------------------------------------------------------------------------------- 1 | # by https://github.com/RustyDucky and https://github.com/lukasgabriel 2 | 3 | from typing import Dict, Optional 4 | 5 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 6 | 7 | 8 | @registry.register 9 | class Tap_code(Decoder[str]): 10 | def decode(self, ctext: T) -> Optional[U]: 11 | """ 12 | Performs Tap code decoding 13 | """ 14 | try: 15 | result = "" 16 | combinations = ctext.split(" ") 17 | for fragment in combinations: 18 | result += self.TABLE.get(fragment) 19 | return result 20 | except Exception: 21 | return None 22 | 23 | @staticmethod 24 | def priority() -> float: 25 | return 0.06 26 | 27 | def __init__(self, config: Config): 28 | super().__init__(config) 29 | self.TABLE = config.get_resource(self._params()["dict"], Translation) 30 | 31 | @staticmethod 32 | def getParams() -> Optional[Dict[str, ParamSpec]]: 33 | return { 34 | "dict": ParamSpec( 35 | desc="The table of letters used for the tap code interpretation.", 36 | req=False, 37 | default="cipheydists::translate::tap_code", 38 | ) 39 | } 40 | 41 | @staticmethod 42 | def getTarget() -> str: 43 | return "tap_code" 44 | -------------------------------------------------------------------------------- /ciphey/basemods/Resources/cipheydists.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | from typing import Any, Dict, Optional, Set 3 | 4 | import cipheydists 5 | import logging 6 | 7 | from ciphey.iface import ( 8 | Config, 9 | Distribution, 10 | ParamSpec, 11 | ResourceLoader, 12 | Translation, 13 | WordList, 14 | registry, 15 | ) 16 | 17 | 18 | @registry.register_multi(WordList, Distribution, Translation) 19 | class CipheyDists(ResourceLoader): 20 | # _wordlists: Set[str] = frozenset({"english", "english1000", "englishStopWords"}) 21 | # _brandons: Set[str] = frozenset({"english"}) 22 | # _dists: Set[str] = frozenset({"twist"}) 23 | # _translates: Set[str] = frozenset({"morse"}) 24 | _getters = { 25 | "list": cipheydists.get_list, 26 | "dist": cipheydists.get_dist, 27 | "brandon": cipheydists.get_brandon, 28 | "translate": cipheydists.get_translate, 29 | } 30 | 31 | def whatResources(self) -> Optional[Set[str]]: 32 | pass 33 | 34 | @lru_cache() 35 | def getResource(self, name: str) -> Any: 36 | logging.debug(f"Loading cipheydists resource {name}") 37 | prefix, name = name.split("::", 1) 38 | return self._getters[prefix](name) 39 | 40 | def __init__(self, config: Config): 41 | super().__init__(config) 42 | 43 | @staticmethod 44 | def getParams() -> Optional[Dict[str, ParamSpec]]: 45 | return None 46 | -------------------------------------------------------------------------------- /.github/workflows/terminaltest.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | name: Ciphey terminal test 3 | jobs: 4 | terminal_test: 5 | name: On ubuntu-latest with python 6 | runs-on: ubuntu-latest 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | python-version: [3.7, 3.8, 3.9] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up Python ${{ matrix.python-version }} 14 | uses: actions/setup-python@v2 15 | with: 16 | python-version: ${{ matrix.python-version }} 17 | - name: Build ciphey 18 | run: | 19 | python -m pip install poetry 20 | poetry install 21 | - name: Test ciphey with plain text 22 | run: | 23 | plain_text="hello. Testing Ciphey." 24 | ciphey_out=$(poetry run ciphey -q -t "$plain_text") 25 | if [ "$ciphey_out" == "$plain_text" ] 26 | then 27 | exit 0 28 | else 29 | echo "Ciphey decryption on plain text failed" 30 | exit 1 31 | fi 32 | - name: Test ciphey with base64 encoded text 33 | run: | 34 | plain_text="hello. Testing Ciphey." 35 | base64_encoded=$(echo -n "$plain_text" | base64) 36 | ciphey_out=$(poetry run ciphey -q -t "$base64_encoded") 37 | if [ "$ciphey_out" == "$plain_text" ] 38 | then 39 | exit 0 40 | else 41 | echo "Ciphey decryption on base64 encoded string failed" 42 | exit 1 43 | fi 44 | -------------------------------------------------------------------------------- /ciphey/__main__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | """ 4 | Ciphey: https://github.com/Ciphey/Ciphey 5 | """ 6 | 7 | import platform 8 | import sys 9 | 10 | if __name__ == "__main__": 11 | major = sys.version_info[0] 12 | minor = sys.version_info[1] 13 | 14 | python_version = ( 15 | str(sys.version_info[0]) 16 | + "." 17 | + str(sys.version_info[1]) 18 | + "." 19 | + str(sys.version_info[2]) 20 | ) 21 | 22 | if major != 3 or minor < 6: 23 | print( 24 | f"Ciphey requires Python 3.6+, you are using {python_version}. Please install a higher Python version. https://www.python.org/downloads/" 25 | ) 26 | print( 27 | "Alternatively, visit our Discord and use the Ciphey bot in #bots http://discord.skerritt.blog" 28 | ) 29 | sys.exit(1) 30 | if platform.system() == "Windows": 31 | if minor > 8: 32 | print( 33 | "Ciphey does not currently support Python 3.9 on Windows. Please use the Discord bot at http://discord.skerritt.blog" 34 | ) 35 | sys.exit(1) 36 | 37 | if sys.maxsize > 2 ** 32 is False: 38 | print( 39 | "You are using Python 32 bit and Windows, Ciphey does not support this. Please upgrade to Python 64-bit here https://www.python.org/downloads/" 40 | ) 41 | sys.exit(1) 42 | from .ciphey import main 43 | 44 | main() 45 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/baudot.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 5 | 6 | 7 | @registry.register 8 | class Baudot(Decoder[str]): 9 | def decode(self, ctext: T) -> Optional[U]: 10 | result = "" 11 | switch_to_digit_map = 0 12 | if re.search("^[01]{5}$", ctext.split()[0]): 13 | for i in ctext.split(): 14 | if i == "11011": 15 | switch_to_digit_map = 1 16 | if i == "11111": 17 | switch_to_digit_map = 0 18 | if switch_to_digit_map == 1: 19 | result += self.BAUDOT_DICT["+" + i] 20 | if switch_to_digit_map == 0: 21 | result += self.BAUDOT_DICT[i] 22 | return result 23 | else: 24 | return None 25 | 26 | @staticmethod 27 | def priority() -> float: 28 | return 0.05 29 | 30 | def __init__(self, config: Config): 31 | super().__init__(config) 32 | self.BAUDOT_DICT = config.get_resource(self._params()["dict"], Translation) 33 | 34 | @staticmethod 35 | def getParams() -> Optional[Dict[str, ParamSpec]]: 36 | return { 37 | "dict": ParamSpec( 38 | desc="The baudot alphabet dictionary to use", 39 | req=False, 40 | default="cipheydists::translate::baudot", 41 | ) 42 | } 43 | 44 | @staticmethod 45 | def getTarget() -> str: 46 | return "baudot" 47 | -------------------------------------------------------------------------------- /tests/test_quick.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from ciphey import decrypt 4 | from ciphey.iface import Config 5 | from click.testing import CliRunner 6 | from ciphey.ciphey import main 7 | from ciphey.basemods.Checkers import human 8 | import mock 9 | 10 | answer_str = "Hello my name is bee and I like dog and apple and tree" 11 | 12 | 13 | def test_quick_base32(): 14 | res = decrypt( 15 | Config().library_default().complete_config(), 16 | "JBSWY3DPEBWXSIDOMFWWKIDJOMQGEZLFEBQW4ZBAJEQGY2LLMUQGI33HEBQW4ZBAMFYHA3DFEBQW4ZBAORZGKZI=", 17 | ) 18 | assert res.lower() == answer_str.lower() 19 | 20 | 21 | def test_quick_base58_ripple(): 22 | res = decrypt( 23 | Config().library_default().complete_config(), 24 | "aqY64A1PhaM8hgyagyw4C1Mmp5cwxGEwag8EjVm9F6YHebyfPZmsvt65XxS7ffteQgTEGbHNT8", 25 | ) 26 | assert res.lower() == answer_str.lower() 27 | 28 | 29 | def test_quick_greppable_works_with_ip_address(): 30 | runner = CliRunner() 31 | result = runner.invoke(main, ["-g", "-t", "MTkyLjE2OC4wLjE="]) 32 | assert result.exit_code == 0 33 | assert result.output == "192.168.0.1\n" 34 | 35 | 36 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="") 37 | def test_quick_visual_output(mock_click): 38 | # https://github.com/Ciphey/Ciphey/issues/655 39 | runner = CliRunner() 40 | mock_click.return_value = "y" 41 | result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="]) 42 | assert result.exit_code == 0 43 | assert "base32" in result.output 44 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/dna.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 8 | 9 | 10 | @registry.register 11 | class Dna(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs DNA decoding 15 | """ 16 | logging.debug("Attempting DNA decoder") 17 | ctext_decoded = "" 18 | ctext = re.sub(r"[,;:\-\s]", "", ctext) 19 | ctext = " ".join(ctext[i : i + 3] for i in range(0, len(ctext), 3)) 20 | ctext_split = ctext.split(" ") 21 | dna_keys = self.DNA_DICT.keys() 22 | 23 | for i in ctext_split: 24 | if i in dna_keys: 25 | ctext_decoded += self.DNA_DICT[i] 26 | else: 27 | return None 28 | logging.info(f"DNA successful, returning '{ctext_decoded}'") 29 | return ctext_decoded 30 | 31 | @staticmethod 32 | def priority() -> float: 33 | return 0.2 34 | 35 | def __init__(self, config: Config): 36 | super().__init__(config) 37 | self.DNA_DICT = config.get_resource(self._params()["dict"], Translation) 38 | 39 | @staticmethod 40 | def getParams() -> Optional[Dict[str, ParamSpec]]: 41 | return { 42 | "dict": ParamSpec( 43 | desc="The DNA alphabet dictionary to use", 44 | req=False, 45 | default="cipheydists::translate::dna", 46 | ) 47 | } 48 | 49 | @staticmethod 50 | def getTarget() -> str: 51 | return "dna" 52 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/dtmf.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 8 | 9 | 10 | @registry.register 11 | class Dtmf(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs DTMF decoding 15 | """ 16 | logging.debug("Attempting DTMF decoder") 17 | ctext_decoded = "" 18 | ctext = re.sub(r"[,;:\-\/\s]", "", ctext) 19 | ctext = " ".join(ctext[i : i + 7] for i in range(0, len(ctext), 7)) 20 | ctext_split = ctext.split(" ") 21 | dtmf_keys = self.DTMF_DICT.keys() 22 | 23 | for i in ctext_split: 24 | if i in dtmf_keys: 25 | ctext_decoded += self.DTMF_DICT[i] 26 | else: 27 | return None 28 | logging.info(f"DTMF successful, returning '{ctext_decoded}'") 29 | return ctext_decoded 30 | 31 | @staticmethod 32 | def priority() -> float: 33 | return 0.2 34 | 35 | def __init__(self, config: Config): 36 | super().__init__(config) 37 | self.DTMF_DICT = config.get_resource(self._params()["dict"], Translation) 38 | 39 | @staticmethod 40 | def getParams() -> Optional[Dict[str, ParamSpec]]: 41 | return { 42 | "dict": ParamSpec( 43 | desc="The DTMF alphabet dictionary to use", 44 | req=False, 45 | default="cipheydists::translate::dtmf", 46 | ) 47 | } 48 | 49 | @staticmethod 50 | def getTarget() -> str: 51 | return "dtmf" 52 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/bases.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import types 3 | from typing import Any, Callable, Optional 4 | 5 | import logging 6 | from rich.logging import RichHandler 7 | import re 8 | 9 | from ciphey.common import id_lambda 10 | from ciphey.iface import Decoder, registry 11 | 12 | 13 | def _dispatch(self: Any, ctext: str, func: Callable[[str], bytes]) -> Optional[bytes]: 14 | logging.debug(f"Attempting {self.getTarget()}") 15 | 16 | try: 17 | # remove all whitespace 18 | ctext = re.sub(r"\s+", "", ctext, re.UNICODE) 19 | result = func(ctext) 20 | logging.info(f"{self.getTarget()} successful, returning {result}") 21 | return result 22 | except ValueError: 23 | logging.debug(f"Failed to decode {self.getTarget()}") 24 | return None 25 | 26 | 27 | _bases = { 28 | "base16": (base64.b16decode, 0.4), 29 | "base32": (base64.b32decode, 0.01), 30 | "base64": (base64.b64decode, 0.4), 31 | "base85": (base64.b85decode, 0.01), 32 | "ascii85": (base64.a85decode, 0.1), 33 | } 34 | 35 | 36 | def gen_class(name, decoder, priority, ns): 37 | ns["_get_func"] = id_lambda(decoder) 38 | ns["decode"] = lambda self, ctext: _dispatch(self, ctext, self._get_func()) 39 | ns["getParams"] = id_lambda(None) 40 | ns["getTarget"] = id_lambda(name) 41 | ns["priority"] = id_lambda(priority) 42 | ns["__init__"] = lambda self, config: super(type(self), self).__init__(config) 43 | 44 | 45 | for name, (decoder, priority) in _bases.items(): 46 | t = types.new_class( 47 | name, 48 | (Decoder[str],), 49 | exec_body=lambda x: gen_class(name, decoder, priority, x), 50 | ) 51 | 52 | registry.register(t) 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | 7 | --- 8 | 9 | **⚠️IMPORTANT⚠️ if you do not fill this out, we will automatically delete your issue. We will not help anyone that cannot fill out this template.** 10 | 11 | - [ ] Have you read our [Wiki page "Common Issues & Their Solutions"?](https://github.com/Ciphey/Ciphey/wiki/Common-Issues-&-Their-Solutions) 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **Plaintext** 17 | **⚠️IMPORTANT⚠️ The below code is non-negotiable for "Ciphey didn't decrypt...." problems. If you do not tell us your plaintext, we will not help you.** 18 | 19 | ``` 20 | Include your plaintext here, replacing this 21 | ``` 22 | **Version** 23 | **⚠️IMPORTANT⚠️ We need this information because different environments will induce different bugs in Ciphey** 24 | - OS/Distro: [e.g. Windows, Debian 11.0, Arch, OS X El Capitan] 25 | - Python version: [python3 --version] 26 | - Ciphey versions: [python3 -m pip show ciphey cipheycore cipheydists] 27 | - Did you use Docker? 28 | 29 | **Verbose Output** 30 | **⚠️IMPORTANT⚠️ Verbose output will tell us why it's not working the way we expected it to be.** 31 | Run Ciphey with `ciphey -vvv` and paste the results into [Pastebin.com](https://pastebin.com) or a [GitHub Gist](https://gist.github.com/) 32 | 33 | **To Reproduce** 34 | Steps to reproduce the behavior: 35 | 1. What input did you use? 36 | 2. What flags / arguments did you use? 37 | 38 | **Expected behavior** 39 | A clear and concise description of what you expected to happen. 40 | 41 | **Any other information?** 42 | Add any other context about the problem here. 43 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/quorum.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Generic, Optional 2 | 3 | from ciphey.iface import Checker, Config, ParamSpec, T, _registry 4 | 5 | 6 | class Quorum(Generic[T], Checker[T]): 7 | def check(self, text: T) -> Optional[str]: 8 | left = self._params().k 9 | results = [] 10 | for checker in self.checkers: 11 | results.append(checker.check(text)) 12 | if results[-1] is None: 13 | continue 14 | left -= 1 15 | # Early return check 16 | if left == 0: 17 | return str(results) 18 | 19 | def __init__(self, config: Config): 20 | super().__init__(config) 21 | 22 | if self._params().k is None: 23 | k = len(self._params()["checker"]) 24 | # These checks need to be separate, to make sure that we do not have zero members 25 | if self._params().k == 0 or self._params().k > len(self._params()["checker"]): 26 | raise IndexError( 27 | "k must be between 0 and the number of checkers (inclusive)" 28 | ) 29 | 30 | self.checkers = [] 31 | for i in self._params()["checker"]: 32 | # This enforces type consistency 33 | self.checkers.append(_registry.get_named(i, Checker[T])) 34 | 35 | @staticmethod 36 | def getParams() -> Optional[Dict[str, ParamSpec]]: 37 | return { 38 | "checker": ParamSpec( 39 | req=True, desc="The checkers to be used for analysis", list=True 40 | ), 41 | "k": ParamSpec( 42 | req=False, 43 | desc="The minimum quorum size. Defaults to the number of checkers", 44 | ), 45 | } 46 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/octal.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 7 | 8 | 9 | @registry.register 10 | class Octal(Decoder[str]): 11 | def decode(self, ctext: T) -> Optional[U]: 12 | """ 13 | Performs Octal decoding 14 | """ 15 | str_converted = [] 16 | octal_seq = ctext.split(" ") 17 | if len(octal_seq) == 1: 18 | # Concatted octal must be formed of octal triplets 19 | if len(ctext) % 3 != 0: 20 | return None 21 | octal_seq = [ctext[i : i + 3] for i in range(0, len(ctext), 3)] 22 | logging.debug(f"Trying chunked octal {octal_seq}") 23 | try: 24 | for octal_char in octal_seq: 25 | if len(octal_char) > 3: 26 | logging.debug("Octal subseq too long") 27 | return None 28 | n = int(octal_char, 8) 29 | if ( 30 | n < 0 31 | ): # n cannot be greater than 255, as we checked that with the earlier length check 32 | logging.debug(f"Non octal char {octal_char}") 33 | return None 34 | str_converted.append(n) 35 | 36 | return bytes(str_converted) 37 | # Catch bad octal chars 38 | except ValueError: 39 | return None 40 | 41 | @staticmethod 42 | def priority() -> float: 43 | return 0.025 44 | 45 | def __init__(self, config: Config): 46 | super().__init__(config) 47 | 48 | @staticmethod 49 | def getParams() -> Optional[Dict[str, ParamSpec]]: 50 | return None 51 | 52 | @staticmethod 53 | def getTarget() -> str: 54 | return "octal" 55 | -------------------------------------------------------------------------------- /tests/test_click_printing.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | from ciphey.ciphey import main 3 | from ciphey.basemods.Checkers import human 4 | import mock 5 | 6 | 7 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value="") 8 | def test_fix_for_655(mock_click): 9 | # https://github.com/Ciphey/Ciphey/issues/655 10 | runner = CliRunner() 11 | mock_click.return_value = "y" 12 | result = runner.invoke(main, ["-t", "NB2HI4DTHIXS6Z3PN5TWYZJOMNXW2==="]) 13 | assert result.exit_code == 0 14 | assert "base32" in result.output 15 | 16 | 17 | """ 18 | TODO Mock 19 | 360d0c11450c114504421611100c0b0545000c06171b1511070145150c110a45081709110b45071b1100423d2a3045120a0c060a450c1145080d170042060a0f1509071d45160d040c45160b0b020e0045001c1107453d2d374b422c0b1111000301450d03450d0b091b4510110c0b05450442160c0c02090745071b110042030a104504420e001b45120a0c060a450c11450003161c42110a42071717110042030a10060042041642110d071700420c16420a0b0e1c4550505342150a11160c000c090b11001149450f1009160c45001c1107450e071c1642060a170901420d04140045160d0a170416030b0111450a0445150d16160b070c0e0c110716450f040e0b0b02420c11420d04100145160a450017101600030d1706074b453a2a37160a0a0e450c1145041500160d08004207000104101100450b114501040b42061703060e42070a160d45110c0b05090042071c160045030b014208100e110c42071c1600453a2a3742000b01171c121100064511071d114c452a0c060042260c120d001b450d0316453a2a37160a0a0e450c0c1100051704160001420c0b160a450b1149420c1142120c0e0945000045111015071745030804180c0b0545040c0145150c090e451012021703010042260c120d001b45110d450707450400090042110a42061703060e42060a0f1509071d453a2a3742000b01171c121100064511071d114c45320a1c450b1645160d0c114511071d1142160a42090a0c025a4227000104101100453a2a37160a0a0e45060d1009060b4216450610040609450c1645120a000b422c450f040107450c1645160a0a171600174c455f4a 20 | 21 | As it passes as a discover card 22 | """ 23 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/binary.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, List, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 8 | 9 | 10 | @registry.register 11 | class Binary(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | try: 14 | ctext = re.sub(r"[^\S \n]", " ", ctext, flags=re.UNICODE) 15 | ctext = ctext.replace("\n", " ") 16 | 17 | existing_split = self.try_split(ctext.split(" ")) 18 | if existing_split is not None: 19 | return existing_split 20 | 21 | # Now we try our own grouping 22 | 23 | # Remove final bit of whitespace 24 | ctext = ctext.replace(" ", "") 25 | # Split into bytes, and test 26 | return self.try_split([ctext[i : i + 8] for i in range(0, len(ctext), 8)]) 27 | # Catch bad octal chars 28 | except ValueError: 29 | return None 30 | 31 | def try_split(self, split_text: List[str]): 32 | ret = [] 33 | 34 | for i in split_text: 35 | if len(i) == 0: 36 | continue 37 | val = int(i, 2) 38 | if val > 255 or val < 0: 39 | return None 40 | ret.append(val) 41 | 42 | if len(ret) != 0: 43 | ret = bytes(ret) 44 | logging.info(f"binary successful, returning {ret.__repr__()}") 45 | return ret 46 | 47 | @staticmethod 48 | def priority() -> float: 49 | return 0.3 50 | 51 | def __init__(self, config: Config): 52 | super().__init__(config) 53 | 54 | @staticmethod 55 | def getParams() -> Optional[Dict[str, ParamSpec]]: 56 | return None 57 | 58 | @staticmethod 59 | def getTarget() -> str: 60 | return "binary" 61 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/decimal.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 8 | 9 | 10 | @registry.register 11 | class Decimal(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs Decimal decoding 15 | """ 16 | logging.debug("Attempting decimal") 17 | ctext_converted = [] 18 | ctext_split = re.split(r"[ ,;:\-\n]", ctext) 19 | delimiters = set(sorted(re.sub(r"[^ ,;:\-\n]", "", ctext))) 20 | ctext_num = re.sub(r"[,;:\-\s]", "", ctext) 21 | ctext_decoded = "" 22 | if ctext_num.isnumeric() is False: 23 | logging.debug("Failed to decode decimal due to non numeric character(s)") 24 | return None 25 | try: 26 | for i in ctext_split: 27 | val = int(i) 28 | if val > 255 or val < 0: 29 | logging.debug( 30 | f"Failed to decode decimal due to invalid number '{val}'" 31 | ) 32 | return None 33 | ctext_converted.append(chr(val)) 34 | ctext_decoded = "".join(ctext_converted) 35 | logging.info( 36 | f"Decimal successful, returning '{ctext_decoded}' with delimiter(s) {delimiters}" 37 | ) 38 | return ctext_decoded 39 | except Exception: 40 | return None 41 | 42 | @staticmethod 43 | def priority() -> float: 44 | return 0.05 45 | 46 | def __init__(self, config: Config): 47 | super().__init__(config) 48 | 49 | @staticmethod 50 | def getParams() -> Optional[Dict[str, ParamSpec]]: 51 | return None 52 | 53 | @staticmethod 54 | def getTarget() -> str: 55 | return "decimal" 56 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/a1z26.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 8 | 9 | 10 | @registry.register 11 | class A1z26(Decoder[str]): 12 | def decode(self, ctext: T) -> Optional[U]: 13 | """ 14 | Performs A1Z26 decoding 15 | """ 16 | logging.debug("Attempting A1Z26") 17 | ctext_converted = [] 18 | ctext_split = re.split(r"[ ,;:\-\n]", ctext) 19 | delimiters = set(sorted(re.sub(r"[^ ,;:\-\n]", "", ctext))) 20 | ctext_num = re.sub(r"[,;:\-\s]", "", ctext) 21 | ctext_decoded = "" 22 | if ctext_num.isnumeric() is False: 23 | logging.debug("Failed to decode A1Z26 due to non numeric character(s)") 24 | return None 25 | try: 26 | for i in ctext_split: 27 | val = int(i) 28 | if val > 26 or val < 1: 29 | logging.debug( 30 | f"Failed to decode A1Z26 due to invalid number '{val}'" 31 | ) 32 | return None 33 | val2 = int(i) + 96 34 | ctext_converted.append(chr(val2)) 35 | ctext_decoded = "".join(ctext_converted) 36 | logging.info( 37 | f"A1Z26 successful, returning '{ctext_decoded}' with delimiter(s) {delimiters}" 38 | ) 39 | return ctext_decoded 40 | except Exception: 41 | return None 42 | 43 | @staticmethod 44 | def priority() -> float: 45 | return 0.05 46 | 47 | def __init__(self, config: Config): 48 | super().__init__(config) 49 | 50 | @staticmethod 51 | def getParams() -> Optional[Dict[str, ParamSpec]]: 52 | return None 53 | 54 | @staticmethod 55 | def getTarget() -> str: 56 | return "a1z26" 57 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/atbash.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.common import fix_case 4 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry 5 | 6 | 7 | @registry.register 8 | class Atbash(Decoder[str]): 9 | def decode(self, ctext: T) -> Optional[U]: 10 | """ 11 | Takes an encoded string and attempts to decode it according to the Atbash cipher. 12 | 13 | The Atbash cipher is a very simple substitution cipher without a key. 14 | It operates by replacing every letter in the input by its 'counterpoint' 15 | in the alphabet. Example: A -> Z, B -> Y, ... , M -> N and vice versa. 16 | """ 17 | 18 | result = "" 19 | atbash_dict = {self.ALPHABET[i]: self.ALPHABET[::-1][i] for i in range(26)} 20 | 21 | for letter in ctext.lower(): 22 | if letter in atbash_dict.keys(): 23 | # Match every letter of the input to its atbash counterpoint 24 | result += atbash_dict[letter] 25 | else: 26 | # If the current character is not in the defined alphabet, 27 | # just accept it as-is (useful for numbers, punctuation, etc.) 28 | result += letter 29 | return fix_case(result, ctext) 30 | 31 | @staticmethod 32 | def priority() -> float: 33 | # Not expected to show up often, but also very fast to check. 34 | return 0.1 35 | 36 | def __init__(self, config: Config): 37 | super().__init__(config) 38 | self.ALPHABET = config.get_resource(self._params()["dict"], WordList) 39 | 40 | @staticmethod 41 | def getParams() -> Optional[Dict[str, ParamSpec]]: 42 | return { 43 | "dict": ParamSpec( 44 | desc="The alphabet used for the atbash operation.", 45 | req=False, 46 | default="cipheydists::list::englishAlphabet", 47 | ) 48 | } 49 | 50 | @staticmethod 51 | def getTarget() -> str: 52 | return "atbash" 53 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/ezcheck.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List, Optional 2 | 3 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 4 | 5 | from .brandon import Brandon 6 | from .format import JsonChecker 7 | from .human import HumanChecker 8 | from .quadgrams import Quadgrams 9 | from .regex import RegexList 10 | from .what import What 11 | 12 | 13 | @registry.register 14 | class EzCheck(Checker[str]): 15 | """ 16 | This object is effectively a prebuilt quorum (with requirement 1) of common patterns, followed by a human check 17 | """ 18 | 19 | def check(self, text: str) -> Optional[str]: 20 | for checker in self.checkers: 21 | res = checker.check(text) 22 | if ( 23 | res is not None 24 | and (self.decider is None or self.decider.check(text)) is not None 25 | ): 26 | return res 27 | return None 28 | 29 | def getExpectedRuntime(self, text: T) -> float: 30 | return sum( 31 | i.getExpectedRuntime(text) for i in self.checkers 32 | ) + self.decider.getExpectedRuntime(text) 33 | 34 | def __init__(self, config: Config): 35 | super().__init__(config) 36 | 37 | self.checkers: List[Checker[str]] = [] 38 | # Disable human checker for automated systems 39 | if config.verbosity >= 0: 40 | self.decider = config(HumanChecker) 41 | else: 42 | self.decider = None 43 | 44 | # We need to modify the config for each of the objects 45 | 46 | # First PyWhat, as it's the fastest 47 | self.checkers.append(config(What)) 48 | 49 | # Next, the json checker 50 | self.checkers.append(config(JsonChecker)) 51 | 52 | # Second to last, the quadgrams checker 53 | self.checkers.append(config(Quadgrams)) 54 | 55 | # Finally, the Brandon checker, as it is the slowest 56 | self.checkers.append(config(Brandon)) 57 | 58 | @staticmethod 59 | def getParams() -> Optional[Dict[str, ParamSpec]]: 60 | pass 61 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/uuencode.py: -------------------------------------------------------------------------------- 1 | from binascii import a2b_uu 2 | from codecs import decode 3 | from typing import Dict, Optional 4 | 5 | import logging 6 | from rich.logging import RichHandler 7 | 8 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 9 | 10 | 11 | @registry.register 12 | class Uuencode(Decoder[str]): 13 | def decode(self, ctext: T) -> Optional[U]: 14 | """ 15 | UUEncode (Unix to Unix Encoding) is a symmetric encryption 16 | based on conversion of binary data (split into 6-bit blocks) into ASCII characters. 17 | 18 | This function decodes the input string 'ctext' if it has been encoded using 'uuencoder' 19 | It will return None otherwise 20 | """ 21 | logging.debug("Attempting UUencode") 22 | result = "" 23 | try: 24 | # UUencoded messages may begin with prefix "begin" and end with suffix "end" 25 | # In that case, we use the codecs module in Python 26 | ctext_strip = ctext.strip() 27 | if ctext_strip.startswith("begin") and ctext_strip.endswith("end"): 28 | result = decode(bytes(ctext, "utf-8"), "uu").decode() 29 | else: 30 | # If there isn't a "being" prefix and "end" suffix, we use the binascii module instead 31 | # It is possible that the ctext has multiple lines, so convert each line and append 32 | ctext_split = list(filter(None, ctext.splitlines())) 33 | for _, value in enumerate(ctext_split): 34 | result += a2b_uu(value).decode("utf-8") 35 | logging.info(f"UUencode successful, returning '{result}'") 36 | return result 37 | except Exception: 38 | logging.debug("Failed to decode UUencode") 39 | return None 40 | 41 | @staticmethod 42 | def priority() -> float: 43 | # Not expected to show up often, but also very fast to check. 44 | return 0.05 45 | 46 | def __init__(self, config: Config): 47 | super().__init__(config) 48 | 49 | @staticmethod 50 | def getParams() -> Optional[Dict[str, ParamSpec]]: 51 | return None 52 | 53 | @staticmethod 54 | def getTarget() -> str: 55 | return "uuencode" 56 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | """ 2 | The file for Nox 3 | """ 4 | from typing import Any 5 | 6 | import nox 7 | from nox.sessions import Session 8 | 9 | locations = "ciphey/", "tests/", "docs/" 10 | nox.options.sessions = ["tests"] 11 | package = "ciphey" 12 | 13 | 14 | def install_with_constraints(session: Session, *args: str, **kwargs: Any) -> None: 15 | """Install packages constrained by Poetry's lock file. 16 | This function is a wrapper for nox.sessions.Session.install. It 17 | invokes pip to install packages inside of the session's virtualenv. 18 | Additionally, pip is passed a constraints file generated from 19 | Poetry's lock file, to ensure that the packages are pinned to the 20 | versions specified in poetry.lock. This allows you to manage the 21 | packages as Poetry development dependencies. 22 | Arguments: 23 | session: The Session object. 24 | args: Command-line arguments for pip. 25 | kwargs: Additional keyword arguments for Session.install. 26 | """ 27 | session.run( 28 | "poetry", 29 | "export", 30 | "--dev", 31 | "--format=requirements.txt", 32 | "--output=requirements.txt", 33 | external=True, 34 | ) 35 | session.install("--constraint=requirements.txt", *args, **kwargs) 36 | 37 | 38 | # noxfile.py 39 | @nox.session 40 | def black(session): 41 | args = session.posargs or locations 42 | session.install("black") 43 | session.run("black", *args) 44 | 45 | 46 | @nox.session(python="3.8") 47 | def coverage(session: Session) -> None: 48 | """Upload coverage data.""" 49 | install_with_constraints(session, "coverage[toml]", "codecov") 50 | session.run("pip3", "install", "cipheydists") 51 | session.run("coverage", "xml", "--fail-under=0") 52 | session.run("codecov", *session.posargs) 53 | 54 | 55 | # noxfile.py 56 | @nox.session 57 | def docs(session: Session) -> None: 58 | """Build the documentation.""" 59 | install_with_constraints(session, "sphinx") 60 | session.run("sphinx-build", "docs", "docs/_build") 61 | 62 | 63 | @nox.session 64 | def tests(session): 65 | session.run("pip3", "install", "cipheydists") 66 | session.run("poetry", "install", external=True) 67 | session.run("poetry", "run", "pytest", "--cov=ciphey") 68 | -------------------------------------------------------------------------------- /ciphey/basemods/Resources/files.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import json 3 | from functools import lru_cache 4 | from typing import Dict, Generic, Optional, Set 5 | 6 | from ciphey.iface import ( 7 | Config, 8 | Distribution, 9 | ParamSpec, 10 | ResourceLoader, 11 | T, 12 | WordList, 13 | registry, 14 | ) 15 | 16 | 17 | # We can use a generic resource loader here, as we can instantiate it later 18 | @registry.register_multi(WordList, Distribution) 19 | class Json(ResourceLoader): 20 | def whatResources(self) -> T: 21 | return self._names 22 | 23 | @lru_cache() 24 | def getResource(self, name: str) -> T: 25 | prefix, name = name.split("::", 1) 26 | return {"wordlist": (lambda js: {js}), "dist": (lambda js: js)}[prefix]( 27 | json.load(open(self._paths[int(name) - 1])) 28 | ) 29 | 30 | @staticmethod 31 | def getName() -> str: 32 | return "json" 33 | 34 | @staticmethod 35 | def getParams() -> Optional[Dict[str, ParamSpec]]: 36 | return {"path": ParamSpec(req=True, desc="The path to a JSON file", list=True)} 37 | 38 | def __init__(self, config: Config): 39 | super().__init__(config) 40 | self._paths = self._params()["path"] 41 | self._names = set(range(1, len(self._paths))) 42 | 43 | 44 | # We can use a generic resource loader here, as we can instantiate it later 45 | @registry.register_multi(WordList, Distribution) 46 | class Csv(Generic[T], ResourceLoader[T]): 47 | def whatResources(self) -> Set[str]: 48 | return self._names 49 | 50 | @lru_cache() 51 | def getResource(self, name: str) -> T: 52 | prefix, name = name.split("::", 1) 53 | return { 54 | "wordlist": (lambda reader: {i[0] for i in reader}), 55 | "dist": (lambda reader: {i[0]: float(i[1]) for i in reader}), 56 | }[prefix](csv.reader(open(self._paths[int(name) - 1]))) 57 | 58 | @staticmethod 59 | def getName() -> str: 60 | return "csv" 61 | 62 | @staticmethod 63 | def getParams() -> Optional[Dict[str, ParamSpec]]: 64 | return {"path": ParamSpec(req=True, desc="The path to a CSV file", list=True)} 65 | 66 | def __init__(self, config: Config): 67 | super().__init__(config) 68 | self._paths = self._params()["path"] 69 | self._names = set(range(1, len(self._paths))) 70 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/what.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 4 | import logging 5 | from rich.logging import RichHandler 6 | from pywhat import identifier 7 | from rich.console import Console 8 | 9 | console = Console() 10 | 11 | 12 | @registry.register 13 | class What(Checker[str]): 14 | 15 | """ 16 | Uses PyWhat to determine plaintext with regexes 17 | https://github.com/bee-san/pyWhat 18 | """ 19 | 20 | def check(self, ctext: T) -> Optional[str]: 21 | logging.debug("Trying PyWhat checker") 22 | returned_regexes = self.id.identify(ctext) 23 | if returned_regexes["Regexes"]: 24 | matched_regex = returned_regexes["Regexes"]['text'][0]["Regex Pattern"] 25 | 26 | ret = f'The plaintext is a [yellow]{matched_regex["Name"]}[/yellow]' 27 | human = ( 28 | f'\nI think the plaintext is a [yellow]{matched_regex["Name"]}[/yellow]' 29 | ) 30 | 31 | if "Description" in matched_regex and matched_regex["Description"]: 32 | s = matched_regex["Description"] 33 | # lowercases first letter so it doesn't look weird 34 | s = f", which is {s[0].lower() + s[1:]}\n" 35 | ret += s 36 | human += s 37 | 38 | # if URL is attached, include that too. 39 | if "URL" in matched_regex and matched_regex["URL"]: 40 | link = matched_regex["URL"] + ctext.replace(" ", "") 41 | ret += f"\nClick here to view in browser [#CAE4F1][link={link}]{link}[/link][/#CAE4F1]\n" 42 | 43 | # If greppable mode is on, don't print this 44 | if self.config.verbosity >= 0: 45 | # Print with full stop 46 | console.print(human) 47 | return ret 48 | return None 49 | 50 | def getExpectedRuntime(self, text: T) -> float: 51 | # TODO: actually bench this 52 | return 2e-7 * len(text) 53 | 54 | @staticmethod 55 | def getParams() -> Optional[Dict[str, ParamSpec]]: 56 | return None 57 | 58 | def __init__(self, config: Config): 59 | super().__init__(config) 60 | self.config = config 61 | self.id = identifier.Identifier() 62 | -------------------------------------------------------------------------------- /translations/zh/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | 翻译
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # 贡献者公约行为准则 15 | 16 | ## 我们的承诺 17 | 18 | 为了营造开放和热情的环境,我们贡献者和维护者保证参与我们的项目, 19 | 并且我们的社区为每个人, 20 | 不论年龄,身材,提供无骚扰的体验大小,残疾,种族,性别特征,性别认同和表达, 21 | 经验水平,教育程度,社会经济地位,国籍,个人 22 | 外观,种族,宗教或性身份和性取向。 23 | 24 | ## 我们的标准 25 | 26 | 有助于创造积极环境的行为例子 27 | 包括: 28 | 29 | - 使用欢迎和包容的语言 30 | - 尊重不同的观点和经验 31 | - 优雅地接受建设性的批评 32 | - 专注于对社会最有利的事物 33 | - 对其他成员表示同情 34 | 35 | 参与者不可接受的行为包括: 36 | 37 | - 使用性化的语言或图像,以及不受欢迎的性关注或进步 38 | - 拖钓,侮辱性/贬损性评论以及人身或政治攻击 39 | - 公开或私人骚扰 \*未经明确许可发布他人的私人信息,例如物理或电子信息 40 | 地址, 41 | - 可以合理地认为不适当的其他行为 42 | 专业设置 43 | 44 | ## 我们的责任 45 | 46 | 项目维护者负责澄清可接受的标准行为, 47 | 并期望在其中采取适当和公平的纠正措施 48 | 对任何不可接受行为的回应。 49 | 50 | 项目维护者有权利和责任删除,编辑或 51 | 拒绝评论,提交,代码,Wiki 编辑,问题和其他贡献 52 | 不符合本行为准则或暂时禁止或 53 | 永久为他们认为不适当的其他行为做出贡献, 54 | 威胁,冒犯或有害的 55 | 56 | ## 范围 57 | 58 | 这个《行为准则》适用于项目空间和公共空间 59 | 当个人代表项目或其社区时。示例 60 | 代表项目或社区,包括使用正式项目电子邮件 61 | 地址,通过官方社交媒体帐户发布或担任指定人员 62 | 代表在线或离线活动。项目的代表可能是 63 | 由项目维护者进一步定义和阐明。 64 | 65 | ## Enforcement 66 | 67 | 虐待,骚扰或其他不可接受的行为可能是 68 | 通过与 brandon_skerrit 联系项目团队进行报告。所有 69 | 投诉将进行审查和调查,并会做出以下回应: 70 | 被认为是必要且适合于具体情况的。项目团队是 71 | 有责任对事件的举报人保密。 72 | 具体实施政策的更多详细信息可能会单独发布。 73 | 74 | 未严格遵守或执行行为准则的项目维护者 75 | 信仰可能会面临其项目负责人决定的暂时或永久性影响。 76 | 77 | ## Attribution 78 | 79 | 这个的行为准则是根据 [贡献者盟约][主页], 1.4 版本, 80 | 可在 获得 81 | 82 | [主页]: https://www.contributor-covenant.org 83 | 84 | 有关此行为准则的常见问题的答案,请参见 85 | 86 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/quadgrams.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import re 3 | from math import log10 4 | from typing import Dict, Optional 5 | 6 | from ciphey.iface import Checker, Config, ParamSpec, T, Translation, registry 7 | from rich.logging import RichHandler 8 | 9 | 10 | @registry.register 11 | class Quadgrams(Checker[str]): 12 | 13 | """ 14 | Uses Quadgrams to determine plaintext 15 | """ 16 | 17 | def check(self, ctext: T) -> Optional[str]: 18 | logging.debug("Trying Quadgrams checker") 19 | # Capitalize and remove everything that's not a letter 20 | ctext = re.sub("[^A-Z]", "", ctext.upper()) 21 | quadgrams = self.QUADGRAMS_DICT 22 | quadgrams_sum = sum(quadgrams.values()) 23 | score = 0 24 | for key in quadgrams.keys(): 25 | quadgrams[key] = float(quadgrams[key]) / quadgrams_sum 26 | floor = log10(0.01 / quadgrams_sum) 27 | for i in range(len(ctext) - 4 + 1): 28 | # Get all quadgrams from ctext and check if they're in the dict 29 | # If yes then add the score of those quadgrams to the total score 30 | if ctext[i : i + 4] in quadgrams: 31 | score += quadgrams[ctext[i : i + 4]] 32 | else: 33 | score += floor 34 | if len(ctext) > 0: 35 | score = score / len(ctext) 36 | logging.info(f"Quadgrams is {score}") 37 | # The default threshold was found to work the best from lots of testing 38 | if score > self.threshold: 39 | return "" 40 | return None 41 | 42 | def getExpectedRuntime(self, text: T) -> float: 43 | # TODO: actually bench this 44 | return 2e-7 * len(text) 45 | 46 | @staticmethod 47 | def getParams() -> Optional[Dict[str, ParamSpec]]: 48 | return { 49 | "dict": ParamSpec( 50 | desc="The quadgrams dictionary to use", 51 | req=False, 52 | default="cipheydists::dist::quadgrams", 53 | ), 54 | "score": ParamSpec( 55 | desc="The score threshold to use", 56 | req=False, 57 | default=0.00011, 58 | ), 59 | } 60 | 61 | def __init__(self, config: Config): 62 | super().__init__(config) 63 | self.QUADGRAMS_DICT = config.get_resource(self._params()["dict"], Translation) 64 | self.threshold = float(self._params()["score"]) 65 | -------------------------------------------------------------------------------- /translations/zh/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | 翻译
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | 你好! 15 | 16 | 您有兴趣为 Ciphey 做贡献吗? 🤔 17 | 18 | 也许您对从哪里开始感到困惑,或者您认为自己的编码技能还不够“好”?好吧,对于后者-这太荒谬了!我们对“错误的代码”完全没问题,即使如此,如果您正在阅读本文档,您可能也是一个不错的程序员。我的意思是,新手通常不会学会为 GitHub 项目做贡献 😉 19 | 20 | 您可以通过以下方法为 Ciphey 做出贡献: 21 | 22 | - 新增语言 🧏 23 | - 添加更多加密方法 📚 24 | - 创建更多文档(非常重要!我们将非常感激) 25 | - 修复通过 GitHub 问题提交的错误(我们可以在此方面为您提供支持 😊) 26 | - 重构代码库 🥺 27 | 28 | 如果这些听起来很难,请不要担心!本文档将引导您确切地实现这些目标。另外,您的名字也会被添加到 Ciphey 的贡献者列表中,我们将永远感谢您! 🙏 29 | 30 | 我们有一个小的 Discord 聊天室供您与开发人员交谈并获得帮助。或者,您可以为您的建议写一个 GitHub 问题。如果您想加入 Discord,请与我们联系或以某种方式询问我们[Discord 链接](https://discord.gg/KfyRUWw) 31 | 32 | # 如何贡献 33 | 34 | Ciphey 始终需要更多解密工具!要了解如何将代码集成到 ciphey 中,请查看: 35 | 36 | - 一个非常简单的教程 37 | - 有关 API 的参考 38 | 39 | 如果您为此编写了一些测试,那就很好了,只需在 Ciphey / tests / test_main.py 中复制一个函数,并用用密码编码的内容替换密文。如果您不添加测试,我们可能仍会合并它,但是对我们来说,诊断错误会更加困难! 40 | 不用说,我们将把您添加到您的辛勤工作的贡献者名单中! 41 | 42 | # 新增语言 🧏 43 | 44 | 默认的语言检查器“ brandon”可使用多种语言。现在,这听起来令人生畏。 45 | 但老实说,您要做的就是拿字典,做一些分析(我们编写了代码来帮助您),将字典和分析添加到仓库中。然后将选项添加到“ settings.yml”。 46 | 47 | # 创建更多文档 48 | 49 | 文档是 Ciphey 最重要的部分。没有文档是极端的代码负担,我们不希望如此。 50 | 当我说的时候请相信我,如果您为出色的文档做出了贡献,那么您将与代码贡献者处于同一水平。文档非常重要。 51 | 52 | 您可以通过多种方式添加文档. 53 | 54 | - 代码中的文档字符串 55 | - 改进我们当前的文档(自述文件,此文件,Ciphey Wiki 页面) 56 | - 翻译文件 (这是非常重要的,越多的语言版本越好) 57 | 58 | 以及更多! 59 | 60 | # 修正代码中的错误 61 | 62 | 访问我们的 GitHub 问题页面,查找 Ciphey 的所有错误!压扁它们,您将被添加到贡献者列表。 ;) 63 | 64 | # 重构代码库 65 | 66 | 并非所有 Ciphey 都遵循 PEP8,并且某些代码会重复。 67 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/xortool.py: -------------------------------------------------------------------------------- 1 | """ 2 | ██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗ 3 | ██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝ 4 | ██║ ██║██████╔╝███████║█████╗ ╚████╔╝ 5 | ██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝ 6 | ╚██████╗██║██║ ██║ ██║███████╗ ██║ 7 | © Brandon Skerritt 8 | Github: bee-san 9 | """ 10 | from typing import Dict, List, Optional 11 | 12 | import logging 13 | from rich.logging import RichHandler 14 | 15 | from xortool_ciphey import tool_main 16 | 17 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry 18 | 19 | 20 | @registry.register 21 | class XorTool(Cracker[str]): 22 | def getInfo(self, ctext: str) -> CrackInfo: 23 | return CrackInfo( 24 | success_likelihood=0.1, 25 | # TODO: actually calculate runtimes 26 | success_runtime=1e-8, 27 | failure_runtime=1e-8, 28 | ) 29 | 30 | @staticmethod 31 | def getTarget() -> str: 32 | return "xortool" 33 | 34 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 35 | logging.debug("Trying xortool cipher") 36 | # TODO handle different charsets 37 | # TODO allow more config over xortool 38 | 39 | logging.debug(f"{ctext}") 40 | 41 | # https://github.com/Ciphey/xortool/discussions/4 42 | # for docs on this function 43 | try: 44 | result = tool_main.api(str.encode(ctext)) 45 | except: 46 | logging.debug("Xor failed.") 47 | return 48 | 49 | result = CrackResult(value=result[1]["Dexored"], key_info=result[0]["keys"]) 50 | 51 | return [result] 52 | 53 | @staticmethod 54 | def getParams() -> Optional[Dict[str, ParamSpec]]: 55 | return { 56 | "expected": ParamSpec( 57 | desc="The expected distribution of the plaintext", 58 | req=False, 59 | config_ref=["default_dist"], 60 | ), 61 | "p_value": ParamSpec( 62 | desc="The p-value to use for standard frequency analysis", 63 | req=False, 64 | default=0.01, 65 | ), 66 | } 67 | 68 | @staticmethod 69 | def score_utility() -> float: 70 | return 1.5 71 | 72 | def __init__(self, config: Config): 73 | super().__init__(config) 74 | self.expected = config.get_resource(self._params()["expected"]) 75 | self.cache = config.cache 76 | self.p_value = self._params()["p_value"] 77 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/braille.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 5 | import logging 6 | from rich.logging import RichHandler 7 | 8 | 9 | @registry.register 10 | class Braille(Decoder[str]): 11 | def decode(self, ctext: T) -> Optional[U]: 12 | """ 13 | Performs Braille decoding 14 | """ 15 | logging.debug("Attempting Braille") 16 | ctext_decoded = "" 17 | braille_matches = 0 18 | for symbol in self.BRAILLE_DICT_INV.values(): 19 | if symbol in ctext: 20 | braille_matches += 1 21 | else: 22 | continue 23 | if braille_matches == 0: 24 | logging.debug("Failed to decode Braille due to invalid characters") 25 | return None 26 | 27 | for pattern, value in self.BRAILLE_DICT.items(): 28 | ctext = re.sub(pattern, value, ctext) 29 | 30 | wordArr = [] 31 | for word in ctext.split(" "): 32 | # If two commas are in front of a word, uppercase the word and remove the comma 33 | if word[:2].find(",,") != -1: 34 | wordArr.append(word.replace(",,", "").upper()) 35 | else: 36 | wordArr.append(word) 37 | 38 | result = [] 39 | for word in wordArr: 40 | # If one comma is in front of a word, capitalize the word and remove the comma 41 | if word[0].find(",") != -1: 42 | result.append(word.replace(",", "").capitalize()) 43 | else: 44 | result.append(word) 45 | ctext_decoded = " ".join(result) 46 | logging.info(f"Braille successful, returning '{ctext_decoded}'") 47 | return ctext_decoded 48 | 49 | @staticmethod 50 | def priority() -> float: 51 | return 0.05 52 | 53 | def __init__(self, config: Config): 54 | super().__init__(config) 55 | self.BRAILLE_DICT = config.get_resource(self._params()["dict"], Translation) 56 | self.BRAILLE_DICT_INV = {v: k for k, v in self.BRAILLE_DICT.items()} 57 | 58 | @staticmethod 59 | def getParams() -> Optional[Dict[str, ParamSpec]]: 60 | return { 61 | "dict": ParamSpec( 62 | desc="The Braille dictionary to use", 63 | req=False, 64 | default="cipheydists::translate::braille", 65 | ) 66 | } 67 | 68 | @staticmethod 69 | def getTarget() -> str: 70 | return "braille" 71 | -------------------------------------------------------------------------------- /ciphey/basemods/Checkers/regex.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Checker, Config, ParamSpec, T, registry 8 | 9 | 10 | @registry.register 11 | class Regex(Checker[str]): 12 | def getExpectedRuntime(self, text: T) -> float: 13 | return 1e-5 # TODO: actually calculate this 14 | 15 | def __init__(self, config: Config): 16 | super().__init__(config) 17 | self.regexes = list(map(re.compile, self._params()["regex"])) 18 | logging.debug(f"There are {len(self.regexes)} regexes") 19 | 20 | def check(self, text: str) -> Optional[str]: 21 | for regex in self.regexes: 22 | logging.debug(f"Trying regex {regex} on {text}") 23 | res = regex.search(text) 24 | logging.debug(f"Results: {res}") 25 | if res: 26 | return f"Passed with regex {regex}. Want to contribute to Ciphey? Submit your regex here to allow Ciphey to automatically get this next time https://github.com/bee-san/pyWhat/wiki/Adding-your-own-Regex\n" 27 | 28 | @staticmethod 29 | def getParams() -> Optional[Dict[str, ParamSpec]]: 30 | return { 31 | "regex": ParamSpec( 32 | req=True, 33 | desc="The regex that must be matched (in a substring)", 34 | list=True, 35 | ) 36 | } 37 | 38 | 39 | @registry.register 40 | class RegexList(Checker[str]): 41 | def getExpectedRuntime(self, text: T) -> float: 42 | return 1e-5 # TODO: actually calculate this 43 | 44 | def __init__(self, config: Config): 45 | super().__init__(config) 46 | self.regexes = [] 47 | for i in self._params()["resource"]: 48 | self.regexes += [re.compile(regex) for regex in config.get_resource(i)] 49 | logging.debug(f"There are {len(self.regexes)} regexes") 50 | 51 | def check(self, text: str) -> Optional[str]: 52 | for regex in self.regexes: 53 | logging.debug(f"Trying regex {regex} on {text}") 54 | res = regex.search(text) 55 | logging.debug(f"Results: {res}") 56 | if res: 57 | return f"passed with regex {regex}" 58 | 59 | @staticmethod 60 | def getParams() -> Optional[Dict[str, ParamSpec]]: 61 | return { 62 | "resource": ParamSpec( 63 | req=True, 64 | desc="A list of regexes that could be matched", 65 | list=True, 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/multi_tap.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, registry 4 | 5 | 6 | @registry.register 7 | class Multi_tap(Decoder[str]): 8 | def decode(self, ctext: T) -> Optional[U]: 9 | result = "" 10 | for x in ctext.split(): 11 | if x == self.SPACE_DIGIT: # Check if it's a space 12 | result += " " 13 | elif not Multi_tap.valid_code_part(x): 14 | return None 15 | else: 16 | result += self.decode_num_to_char(x) 17 | 18 | return result 19 | 20 | @staticmethod 21 | def valid_code_part(code: str) -> bool: 22 | if not code.isdigit(): 23 | return False 24 | 25 | # if not all the digits are the same 26 | if not Multi_tap.is_all_dup(code): 27 | return False 28 | 29 | if int(code[0]) not in range(2, 10): 30 | return False 31 | 32 | if len(code) > 4: 33 | return False 34 | 35 | return True 36 | 37 | @staticmethod 38 | def decode_num_to_char(number: str) -> str: 39 | index = Multi_tap.calculate_index(number) 40 | return Multi_tap.number_index_to_char(index) 41 | 42 | @staticmethod 43 | def is_all_dup(code): 44 | return len(set(code)) == 1 45 | 46 | @staticmethod 47 | def calculate_index(number: str) -> int: 48 | first_number_as_int = int(number[0]) 49 | 50 | number_index = Multi_tap.get_index_from_first_digit(first_number_as_int) 51 | 52 | # Add to index the number of the char : "22" -> index += 1 53 | num_rest_numbers = len(number) - 1 54 | number_index += num_rest_numbers 55 | 56 | return number_index 57 | 58 | @staticmethod 59 | def number_index_to_char(index_number: int) -> str: 60 | start_ascii_value = ord("A") 61 | return chr(start_ascii_value + index_number) 62 | 63 | @staticmethod 64 | def get_index_from_first_digit(first_digit: int) -> int: 65 | number_index = 0 66 | if first_digit >= 8: # s have 4 chars 67 | number_index += 1 68 | 69 | first_digit -= 2 # start in 200 70 | 71 | number_index += first_digit * 3 # jump 3 every time 72 | 73 | return number_index 74 | 75 | @staticmethod 76 | def priority() -> float: 77 | return 0.05 78 | 79 | def __init__(self, config: Config): 80 | super().__init__(config) 81 | self.SPACE_DIGIT = "0" 82 | 83 | @staticmethod 84 | def getParams() -> Optional[Dict[str, ParamSpec]]: 85 | return None 86 | 87 | @staticmethod 88 | def getTarget() -> str: 89 | return "multi_tap" 90 | -------------------------------------------------------------------------------- /tests/dict.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.basemods.Checkers.brandon import Brandon 7 | 8 | config = dict() 9 | lc = config["checker"](config) 10 | 11 | logging.remove() 12 | 13 | 14 | class testDictionary(unittest.TestCase): 15 | def test_english_yes(self): 16 | dc = Brandon() 17 | result = dc.confirmlanguage( 18 | "hello again my friend this is my name and I like dogs!", "English" 19 | ) 20 | self.assertEqual(result, True) 21 | 22 | def test_english_yes_two(self): 23 | dc = Brandon() 24 | result = dc.confirmlanguage( 25 | "hello my name is brandon and this is a normal english text timtable fuse kindle hormone", 26 | "English", 27 | ) 28 | self.assertEqual(result, True) 29 | 30 | def test_english_false(self): 31 | dc = Brandon() 32 | result = dc.confirmlanguage("jdajj kop9u0r 9jjidasjp", "English") 33 | self.assertEqual(result, False) 34 | 35 | def test_english_false_two(self): 36 | dc = Brandon() 37 | result = dc.confirmlanguage( 38 | "pink jdajj red 9jjidasjp october whisky odiajdq", "English" 39 | ) 40 | self.assertEqual(result, True) 41 | 42 | # def test_english_percentage(self): 43 | # dc = Brandon() 44 | # result = dc.confirmlanguage( 45 | # "The password for my computer is tyu456q and the username is admin", 46 | # "English", 47 | # ) 48 | # self.assertEqual(dc.languagePercentage, 90.0) 49 | 50 | def test_english_perfect(self): 51 | dc = Brandon() 52 | result = dc.confirmlanguage( 53 | "Archimedes famously said: “Give me a lever long enough and a fulcrum on which to place it, and I shall move the world.” But what we are talking about here is not physical leverage. It is the leverage of ideas. When you create content, people can access your knowledge without taking your time. You no longer need to sell knowledge by the hour. Your ideas are the most valuable currency in a knowledge-driven economy. Just as an investment account allows your money to grow day and night without your involvement, content does the same with your ideas. Until recently, the average person wasn’t able to publish and distribute their ideas at a reasonable cost. But on the Internet, anybody, in any corner of the world, in any time zone, can access your best thinking. 24 hours a day. 7 days a week. 365 days a year. When you publish ideas, you create your own “Serendipity Vehicle” – a magnet for ideas and people and opportunities from potentially every corner of the globe. If your ideas resonate with people, people will discover you and bring you unexpected opportunities. They’ll open doors you never knew existed.", 54 | "English", 55 | ) 56 | self.assertEqual(result, True) 57 | -------------------------------------------------------------------------------- /tests/generate_tests.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create a class that can generate encryptions that ciphey can decrypt 3 | This class takes a random string from a large corpus of data and returns it as : 4 | {"Cipher": c, "Plaintext": p, "CipherUsed": cu, "Succeeds": true} 5 | 6 | It would also be good if it could return randomly generate text / plaintext too, so we can get some failure test cases. 7 | 8 | This class is used to create the class that contains the tests. 9 | So it'll have a format like: 10 | 11 | def test_description(self): 12 | assert(t, equal) 13 | where t is the decrypted text from Ciphey, and equal is the decrypted text. 14 | 15 | So this function does like: 16 | 17 | for i in range(1, 20000): 18 | grabCipher = grabCipher() 19 | # this returns a random cipher, encrypted text and plaintext combo 20 | toAppend =''' 21 | def test_{cipher}_{succeeds}_{plaintext[0:10]}(textToTest): 22 | cipheyObj = ciphey(text) 23 | output = cipheyObj.decrypt() 24 | assert(output, {plaintext}) 25 | ''' 26 | file.append() 27 | """ 28 | import random 29 | import string 30 | 31 | import enciphey 32 | from rich.progress import track 33 | 34 | 35 | class test_generator: 36 | def __init__(self): 37 | self.HOW_MANY_TESTS = 30 38 | self.enCiphey_obj = enciphey.encipher() 39 | 40 | def main(self): 41 | with open("test_main_generated.py", "w") as f: 42 | f.write("from ciphey.__main__ import main, make_default_config") 43 | print("Opened fild") 44 | for i in track(range(1, self.HOW_MANY_TESTS)): 45 | print("In the for loop") 46 | x = self.enCiphey_obj.getRandomEncryptedSentence() 47 | print(x) 48 | # if x["CipherUsed"] == "MorseCode": 49 | # self.make_test_lc_true_template(cipher=x) 50 | to_append = self.make_test_lc_true_template(cipher=x) 51 | print(f"Adding {to_append}") 52 | f.write(to_append) 53 | 54 | def make_test_true_template(self, cipher): 55 | id = self.randomString(8) 56 | return f""" 57 | def test_{cipher['Encrypted Texts']['CipherUsed']}_{id}(): 58 | # {cipher} 59 | res = ciphey.main('''{cipher['Encrypted Texts']['EncryptedText']}''', config={"offline": True}) 60 | assert(res == {cipher['Encrypted Texts']['PlainText']}) 61 | """ 62 | 63 | def make_test_lc_true_template(self, cipher): 64 | id = self.randomString(8) 65 | return f""" 66 | def test_{cipher['Encrypted Texts']['CipherUsed']}_{id}(): 67 | # {cipher} 68 | cfg = make_default_config('''{cipher['Encrypted Texts']['EncryptedText']}''') 69 | cfg["debug"] = "TRACE" 70 | result = main(cfg) 71 | 72 | assert result["IsPlaintext?"] == True 73 | """ 74 | 75 | def randomString(self, stringLength): 76 | letters = string.ascii_letters 77 | return "".join(random.choice(letters) for i in range(stringLength)) 78 | 79 | 80 | t = test_generator() 81 | t.main() 82 | 83 | 84 | # return {"PlainText": text, "EncryptedText": encryptedText, "CipherUsed": name} 85 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/base69.py: -------------------------------------------------------------------------------- 1 | # Translated to Python and adapted for Ciphey from the JS original at https://github.com/pshihn/base69 2 | 3 | 4 | import re 5 | from math import ceil 6 | from typing import Dict, Optional 7 | 8 | from ciphey.iface import Config, Decoder, ParamSpec, T, U, WordList, registry 9 | 10 | 11 | @registry.register 12 | class Base69(Decoder[str]): 13 | def decode(self, ctext: T) -> Optional[U]: 14 | """ 15 | Performs Base69 decoding 16 | """ 17 | # Remove whitespace 18 | try: 19 | ctext = re.sub(r"\s+", "", ctext, flags=re.UNICODE) 20 | extra_bytes = 0 21 | clen = len(ctext) 22 | 23 | if ctext[:-1] == "=": 24 | extra_bytes = int(ctext[clen - 2]) 25 | 26 | CHUNK_COUNT = ceil(clen / 16) 27 | result = [0 for _ in range(CHUNK_COUNT * 7 - extra_bytes)] 28 | 29 | for i in range(CHUNK_COUNT): 30 | chunk_string = ctext[i * 16 : (i + 1) * 16] 31 | if extra_bytes and (i == CHUNK_COUNT - 1): 32 | insert = self.decode_chunk(chunk_string) 33 | for n, elem in enumerate(insert[0 : 7 - extra_bytes]): 34 | result[n + i * 7] = elem 35 | else: 36 | insert = self.decode_chunk(chunk_string) 37 | for n, elem in enumerate(insert): 38 | result[n + i * 7] = elem % 256 39 | return bytearray(result).decode().strip("\x00") 40 | except Exception: 41 | return None 42 | 43 | def decode_chunk(self, s: str): 44 | padded_bytes = s.endswith("=") 45 | 46 | decoded = [0 for _ in range(8)] 47 | for i in range(8): 48 | decoded[i] = ( 49 | 0 50 | if i == 7 and padded_bytes 51 | else self.chars_to_byte(s[i * 2 : i * 2 + 2]) 52 | ) 53 | 54 | result = [0 for _ in range(7)] 55 | for i in range(7): 56 | t1 = decoded[i] << (i + 1) 57 | t2 = decoded[i + 1] >> (7 - i - 1) 58 | result[i] = t1 | t2 59 | return result 60 | 61 | def chars_to_byte(self, s: str): 62 | return (69 * self.CHARS.index(s[1])) + (self.CHARS.index(s[0])) 63 | 64 | @staticmethod 65 | def priority() -> float: 66 | # If this becomes lower or equal to the reverse, it breaks. 67 | # So I'll set it to 0.2 for now since it is very fast anyways. 68 | return 0.2 69 | 70 | def __init__(self, config: Config): 71 | super().__init__(config) 72 | self.CHARS = config.get_resource(self._params()["dict"], WordList) 73 | 74 | @staticmethod 75 | def getParams() -> Optional[Dict[str, ParamSpec]]: 76 | return { 77 | "dict": ParamSpec( 78 | desc="The charset used for the decoder.", 79 | req=False, 80 | default="cipheydists::list::base69", 81 | ) 82 | } 83 | 84 | @staticmethod 85 | def getTarget() -> str: 86 | return "base69" 87 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/galactic.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 7 | 8 | 9 | @registry.register 10 | class Galactic(Decoder[str]): 11 | def decode(self, ctext: T) -> Optional[U]: 12 | """ 13 | Takes a string written in the 'Standard Galactic Alphabet' 14 | (aka Minecraft Enchanting Table Symbols) and translates it to ASCII text. 15 | """ 16 | logging.debug("Attempting Standard Galactic Alphabet decoder") 17 | 18 | # To avoid complications, only move forward with the decoding if we can 19 | # reasonably assume that the input string is written in the galactic alphabet 20 | galactic_matches = 0 21 | for symbol in self.GALACTIC_DICT.keys(): 22 | # These symbols are assumed to be frequent enough in regular 23 | # text to be skipped when counting the matches. All others are counted. 24 | if symbol in ctext and symbol not in ["!", "|"]: 25 | galactic_matches += 1 26 | else: 27 | continue 28 | if galactic_matches == 0: 29 | logging.debug( 30 | "No matching galactic alphabet letters found. Skipping galactic decoder" 31 | ) 32 | return None 33 | logging.debug(f"{galactic_matches} galactic alphabet letters found. ") 34 | 35 | result = "" 36 | # Take out the problematic characters consisting of multiple symbols 37 | ctext = ( 38 | ctext.replace("||", "|") 39 | .replace("/", "") 40 | .replace("¡", "") 41 | .replace(" ̣ ", "") 42 | .replace("̇", "x") 43 | ) 44 | logging.debug(f"Modified string is {ctext}") 45 | 46 | for letter in ctext: 47 | if letter in self.GALACTIC_DICT.keys(): 48 | # Match every letter of the input to its galactic counterpoint 49 | result += self.GALACTIC_DICT[letter] 50 | else: 51 | # If the current character is not in the defined alphabet, 52 | # just accept it as-is (useful for numbers, punctuation, etc.) 53 | result += letter 54 | # Remove the trailing space (appearing as a leading space) 55 | # from the x that results from the diacritic replacement 56 | result = result.replace("x ", "x") 57 | logging.debug(f"Decoded string is {result}") 58 | return result 59 | 60 | @staticmethod 61 | def priority() -> float: 62 | # Not expected to show up often, but also very fast to check. 63 | return 0.01 64 | 65 | def __init__(self, config: Config): 66 | super().__init__(config) 67 | self.GALACTIC_DICT = config.get_resource(self._params()["dict"], Translation) 68 | 69 | @staticmethod 70 | def getParams() -> Optional[Dict[str, ParamSpec]]: 71 | return { 72 | "dict": ParamSpec( 73 | desc="The galactic alphabet dictionary to use", 74 | req=False, 75 | default="cipheydists::translate::galactic", 76 | ) 77 | } 78 | 79 | @staticmethod 80 | def getTarget() -> str: 81 | return "galactic" 82 | -------------------------------------------------------------------------------- /tests/lukas.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import cipheydists 4 | 5 | 6 | class galactic_encode: 7 | """ 8 | (Attempts to) encode an input string with the Standard Galactic Alphabet. 9 | """ 10 | 11 | def __init__(self, text: str): 12 | self.text = text.lower() 13 | self.ctext = "" 14 | 15 | imported = dict(cipheydists.get_translate("galactic")) 16 | self.galactic_dict = {value: key for (key, value) in imported.items()} 17 | 18 | def encode(self): 19 | for char in self.text: 20 | if char in self.galactic_dict.keys(): 21 | self.ctext += self.galactic_dict[char] 22 | else: 23 | self.ctext += char 24 | return self.ctext 25 | 26 | 27 | class atbash_encode: 28 | """ 29 | Encodes an input string with the Atbash cipher. 30 | """ 31 | 32 | def __init__(self, text: str): 33 | self.text = text.lower() 34 | self.letters = list("abcdefghijklmnopqrstuvwxyz") 35 | self.atbash_dict = {self.letters[::-1][i]: self.letters[i] for i in range(26)} 36 | self.ctext = "" 37 | 38 | def encode(self): 39 | for letter in self.text: 40 | if letter in self.atbash_dict.keys(): 41 | # Match every letter of the input to its atbash counterpoint 42 | self.ctext += self.atbash_dict[letter] 43 | else: 44 | # If the current character is not in the defined alphabet, 45 | # just accept it as-is (useful for numbers, punctuation,...) 46 | self.ctext += letter 47 | return self.ctext 48 | 49 | 50 | class XY_encrypt: 51 | """ 52 | Encrypts an input string using binary substitution (called XandY in Ciphey) in which 53 | first, the input string is converted to its binary representation and then the 0s and 1s 54 | of the binary string are replaced with any two characters. 55 | - flip: Which of the two possible rotations of the substitute characters is used? 56 | - randomize: If True, random spaces are inserted into the cstring, which Ciphey can handle. 57 | - key: Which two characters are used to represent the 0s and 1s? 58 | """ 59 | 60 | def __init__( 61 | self, 62 | text: str, 63 | flip: bool = bool(random.randint(0, 1)), 64 | randomize: bool = True, 65 | key: list = None, 66 | ): 67 | self.ASCII = cipheydists.get_charset("asciiTable") 68 | self.text = text.lower() 69 | self.ctext = "" 70 | self.flip = flip 71 | self.randomize = randomize 72 | self.key = key 73 | 74 | def randomizer(self): 75 | s = list(self.ctext) 76 | for i in range(len(s) - 1): 77 | while random.randrange(2): 78 | s[i] = s[i] + " " 79 | return "".join(s) 80 | 81 | def to_binary(self): 82 | return " ".join(f"{ord(i):08b}" for i in self.text) 83 | 84 | def encrypt(self): 85 | self.ctext = self.to_binary().replace(" ", "") 86 | 87 | if self.key: 88 | one, two = self.key[0], self.key[1] 89 | else: 90 | one, two = random.choice(self.ASCII), random.choice(self.ASCII) 91 | 92 | self.ctext = self.ctext.replace(str(int(self.flip)), one).replace( 93 | str(int(not self.flip)), two 94 | ) 95 | self.ctext = self.randomizer() if self.randomize is True else self.ctext 96 | 97 | return self.ctext 98 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at brandon_skerrit. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | 77 | -------------------------------------------------------------------------------- /ciphey/basemods/Decoders/morse_code.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Optional 2 | 3 | import logging 4 | from rich.logging import RichHandler 5 | 6 | from ciphey.iface import Config, Decoder, ParamSpec, T, Translation, U, registry 7 | 8 | 9 | @registry.register 10 | class Morse_code(Decoder[str]): 11 | # A priority list for char/word boundaries 12 | BOUNDARIES = {" ": 1, "/": 2, "\n": 3} 13 | PURGE = {ord(c): None for c in BOUNDARIES.keys()} 14 | MAX_PRIORITY = 3 15 | ALLOWED = {".", "-", " ", "/", "\n"} 16 | MORSE_CODE_DICT: Dict[str, str] 17 | MORSE_CODE_DICT_INV: Dict[str, str] 18 | 19 | def decode(self, ctext: T) -> Optional[U]: 20 | logging.debug("Attempting Morse code decoder") 21 | 22 | char_boundary = word_boundary = None 23 | 24 | char_boundary = word_boundary = None 25 | char_priority = word_priority = 0 26 | # Custom loop allows early break 27 | for i in ctext: 28 | i_priority = self.BOUNDARIES.get(i) 29 | if i_priority is None: 30 | if i in self.ALLOWED: 31 | continue 32 | logging.debug(f"Non-morse char '{i}' found") 33 | return None 34 | 35 | if i_priority <= char_priority or i == char_boundary or i == word_boundary: 36 | continue 37 | # Default to having a char boundary over a word boundary 38 | if ( 39 | i_priority > word_priority 40 | and word_boundary is None 41 | and char_boundary is not None 42 | ): 43 | word_priority = i_priority 44 | word_boundary = i 45 | continue 46 | char_priority = i_priority 47 | char_boundary = i 48 | 49 | logging.debug( 50 | f"Char boundary is unicode {ord(char_boundary)}, and word boundary is unicode {ord(word_boundary) if word_boundary is not None else None}" 51 | ) 52 | 53 | result = "" 54 | 55 | for word in ctext.split(word_boundary) if word_boundary else [ctext]: 56 | logging.debug(f"Attempting to decode word {word}") 57 | for char in word.split(char_boundary): 58 | char = char.translate(self.PURGE) 59 | if len(char) == 0: 60 | continue 61 | try: 62 | m = self.MORSE_CODE_DICT_INV[char] 63 | except KeyError: 64 | logging.debug(f"Invalid codeword '{char}' found") 65 | return None 66 | result = result + m 67 | # after every word add a space 68 | result = result + " " 69 | if len(result) == 0: 70 | logging.debug("Morse code failed to match") 71 | return None 72 | # Remove trailing space 73 | result = result[:-1] 74 | logging.info(f"Morse code successful, returning {result}") 75 | return result.strip().upper() 76 | 77 | @staticmethod 78 | def priority() -> float: 79 | return 0.05 80 | 81 | def __init__(self, config: Config): 82 | super().__init__(config) 83 | self.MORSE_CODE_DICT = config.get_resource(self._params()["dict"], Translation) 84 | self.MORSE_CODE_DICT_INV = {v: k for k, v in self.MORSE_CODE_DICT.items()} 85 | 86 | @staticmethod 87 | def getParams() -> Optional[Dict[str, ParamSpec]]: 88 | return { 89 | "dict": ParamSpec( 90 | desc="The morse code dictionary to use", 91 | req=False, 92 | default="cipheydists::translate::morse", 93 | ) 94 | } 95 | 96 | @staticmethod 97 | def getTarget() -> str: 98 | return "morse_code" 99 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/baconian.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, List, Optional 3 | 4 | from ciphey.iface import ( 5 | Config, 6 | Cracker, 7 | CrackInfo, 8 | CrackResult, 9 | ParamSpec, 10 | Translation, 11 | registry, 12 | ) 13 | import logging 14 | from rich.logging import RichHandler 15 | 16 | 17 | @registry.register 18 | class Baconian(Cracker[str]): 19 | def getInfo(self, ctext: str) -> CrackInfo: 20 | return CrackInfo( 21 | success_likelihood=0.1, 22 | success_runtime=1e-5, 23 | failure_runtime=1e-5, 24 | ) 25 | 26 | @staticmethod 27 | def getTarget() -> str: 28 | return "baconian" 29 | 30 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 31 | """ 32 | Attempts to decode both variants of the Baconian cipher. 33 | """ 34 | logging.debug("Attempting Baconian cracker") 35 | candidates = [] 36 | result = [] 37 | ctext_decoded = "" 38 | ctext_decoded2 = "" 39 | 40 | # Convert to uppercase and replace delimiters and whitespace with nothing 41 | ctext = re.sub(r"[,;:\-\s]", "", ctext.upper()) 42 | 43 | # Make sure ctext only contains A and B 44 | if bool(re.search(r"[^AB]", ctext)) is True: 45 | logging.debug("Failed to crack baconian due to non baconian character(s)") 46 | return None 47 | 48 | # Make sure ctext is divisible by 5 49 | ctext_len = len(ctext) 50 | if ctext_len % 5: 51 | logging.debug( 52 | f"Failed to decode Baconian because length must be a multiple of 5, not '{ctext_len}'" 53 | ) 54 | return None 55 | 56 | # Split ctext into groups of 5 57 | ctext = " ".join(ctext[i : i + 5] for i in range(0, len(ctext), 5)) 58 | ctext_split = ctext.split(" ") 59 | baconian_keys = self.BACONIAN_DICT.keys() 60 | 61 | # Decode I=J and U=V variant 62 | for i in ctext_split: 63 | if i in baconian_keys: 64 | ctext_decoded += self.BACONIAN_DICT[i] 65 | 66 | # Decode variant that assigns each letter a unique code 67 | for i in ctext_split: 68 | if "+" + i in baconian_keys: 69 | ctext_decoded2 += self.BACONIAN_DICT["+" + i] 70 | 71 | candidates.append(ctext_decoded) 72 | candidates.append(ctext_decoded2) 73 | for candidate in candidates: 74 | if candidate != "": 75 | if candidate == candidates[0]: 76 | result.append(CrackResult(value=candidate, key_info="I=J & U=V")) 77 | else: 78 | result.append(CrackResult(value=candidate)) 79 | logging.debug(f"Baconian cracker - Returning results: {result}") 80 | return result 81 | 82 | @staticmethod 83 | def getParams() -> Optional[Dict[str, ParamSpec]]: 84 | return { 85 | "expected": ParamSpec( 86 | desc="The expected distribution of the plaintext", 87 | req=False, 88 | config_ref=["default_dist"], 89 | ), 90 | "dict": ParamSpec( 91 | desc="The Baconian alphabet dictionary to use", 92 | req=False, 93 | default="cipheydists::translate::baconian", 94 | ), 95 | } 96 | 97 | def __init__(self, config: Config): 98 | super().__init__(config) 99 | self.BACONIAN_DICT = config.get_resource(self._params()["dict"], Translation) 100 | self.expected = config.get_resource(self._params()["expected"]) 101 | self.cache = config.cache 102 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/rot47.py: -------------------------------------------------------------------------------- 1 | """ 2 | ██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗ 3 | ██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝ 4 | ██║ ██║██████╔╝███████║█████╗ ╚████╔╝ 5 | ██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝ 6 | ╚██████╗██║██║ ██║ ██║███████╗ ██║ 7 | © Brandon Skerritt 8 | Github: brandonskerritt 9 | """ 10 | 11 | from typing import Dict, List, Optional 12 | 13 | import cipheycore 14 | import logging 15 | from rich.logging import RichHandler 16 | 17 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry 18 | 19 | 20 | @registry.register 21 | class Rot47(Cracker[str]): 22 | def getInfo(self, ctext: str) -> CrackInfo: 23 | analysis = self.cache.get_or_update( 24 | ctext, 25 | "cipheycore::simple_analysis", 26 | lambda: cipheycore.analyse_string(ctext), 27 | ) 28 | 29 | return CrackInfo( 30 | success_likelihood=cipheycore.caesar_detect(analysis, self.expected), 31 | # TODO: actually calculate runtimes 32 | success_runtime=1e-5, 33 | failure_runtime=1e-5, 34 | ) 35 | 36 | @staticmethod 37 | def getTarget() -> str: 38 | return "rot47" 39 | 40 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 41 | logging.info(f"Trying ROT47 cipher on {ctext}") 42 | 43 | logging.debug("Beginning cipheycore simple analysis") 44 | 45 | # Hand it off to the core 46 | analysis = self.cache.get_or_update( 47 | ctext, 48 | "cipheycore::simple_analysis", 49 | lambda: cipheycore.analyse_string(ctext), 50 | ) 51 | logging.debug("Beginning cipheycore::caesar") 52 | possible_keys = cipheycore.caesar_crack( 53 | analysis, self.expected, self.group, self.p_value 54 | ) 55 | 56 | n_candidates = len(possible_keys) 57 | logging.info(f"ROT47 returned {n_candidates} candidates") 58 | 59 | if n_candidates == 0: 60 | logging.debug("Filtering for better results") 61 | analysis = cipheycore.analyse_string(ctext, self.group) 62 | possible_keys = cipheycore.caesar_crack( 63 | analysis, self.expected, self.group, self.p_value 64 | ) 65 | 66 | candidates = [] 67 | 68 | for candidate in possible_keys: 69 | logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}") 70 | translated = cipheycore.caesar_decrypt(ctext, candidate.key, self.group) 71 | candidates.append(CrackResult(value=translated, key_info=candidate.key)) 72 | 73 | return candidates 74 | 75 | @staticmethod 76 | def getParams() -> Optional[Dict[str, ParamSpec]]: 77 | return { 78 | "expected": ParamSpec( 79 | desc="The expected distribution of the plaintext", 80 | req=False, 81 | config_ref=["default_dist"], 82 | ), 83 | "group": ParamSpec( 84 | desc="An ordered sequence of chars that make up the ROT47 cipher alphabet", 85 | req=False, 86 | default="""!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~""", 87 | ), 88 | "p_value": ParamSpec( 89 | desc="The p-value to use for standard frequency analysis", 90 | req=False, 91 | default=0.01, 92 | ) 93 | # TODO: add "filter" param 94 | } 95 | 96 | def __init__(self, config: Config): 97 | super().__init__(config) 98 | self.group = list(self._params()["group"]) 99 | self.expected = config.get_resource(self._params()["expected"]) 100 | self.cache = config.cache 101 | self.p_value = float(self._params()["p_value"]) 102 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Translations
3 | 🇩🇪 DE 4 | 🇭🇺 HU 5 | 🇮🇩 ID 6 | 🇮🇹 IT 7 | 🇳🇱 NL 8 | 🇧🇷 PT-BR 9 | 🇷🇺 RU 10 | 🇨🇳 ZH 11 |

12 | 13 | Howdy! 14 | 15 | So, you're interested in contributing to Ciphey? 🤔 16 | 17 | Perhaps you're confused as to where to start, or you believe your coding skills aren't "good enough"? Well, for the latter - that's ridiculous! We're perfectly okay with "bad code" and even then if you're reading this document you're probably a great programmer. I mean, newbies don't often learn to contribute to GitHub projects 😉 18 | 19 | Here are some ways you can contribute to Ciphey: 20 | 21 | - Add a new language 🧏 22 | - Add more encryption methods 📚 23 | - Create more documentation (very important! We would be eternally grateful) 24 | - Fix bugs submitted via GitHub issues (we can support you in this 😊) 25 | - Refactor the code base 🥺 26 | 27 | If these sound hard, do not worry! This document will walk you through exactly how to achieve any of these. Also, your name will be added to Ciphey's contributors list, and we'll be eternally grateful! 🙏 28 | 29 | We have a small Discord chat for you to talk to the developers and get some help. Alternatively, you can write a GitHub issue for your suggestion. If you want to be added to the Discord, DM us or ask us somehow. 30 | 31 | [Discord Server](https://discord.gg/KfyRUWw) 32 | 33 | # How to contribute 34 | 35 | Ciphey is always in need of more decryption tools! To learn how to integrate code into ciphey, check out: 36 | 37 | - for a simple tutorial 38 | - for a API reference 39 | 40 | It would be nice if you wrote some tests for it, by simply copying a function in the Ciphey/tests/test_main.py and replacing the ciphertext with something encoded with your cipher. If you don't add tests, we will probably still merge it, but it will be much harder for us to diagnose bugs! 41 | 42 | It goes without saying that we will add you to the list of contributors for your hard work! 43 | 44 | # Add a new language 🧏 45 | 46 | The default language checker, `brandon`, works with multiple languages. Now, this may sound daunting. 47 | But honestly, all you've got to do is take a dictionary, do a little analysis (we've written code to help you with this), add the dictionaries and analysis to a repo. And then add the option to `settings.yml`. 48 | 49 | # Create more documentation 50 | 51 | Documentation is the most important part of Ciphey. No documentation is extreme code debt, and we don't want that. 52 | 53 | Trust me when I say if you contribute to great documentation you will be seen on the same level as code contributors. Documentation is absolutely vital. 54 | 55 | There are lots of ways you can add documentation. 56 | 57 | - Doc strings in the code 58 | - Improving our current documentation (README, this file, our Ciphey Wiki pages) 59 | - Translating documentation 60 | 61 | And much more! 62 | 63 | # Fix bugs 64 | 65 | Visit our GitHub issues page to find all the bugs that Ciphey has! Squash them, and you'll be added to the contributors list. ;) 66 | 67 | # Refactor the code base 68 | 69 | Not all of Ciphey follows PEP8, and some of the code is repeated. 70 | -------------------------------------------------------------------------------- /tests/test_advanced_ciphers.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from click.testing import CliRunner 3 | import mock 4 | import re 5 | 6 | from ciphey import decrypt 7 | from ciphey.iface import Config 8 | from ciphey.ciphey import main 9 | from ciphey.basemods.Checkers import human 10 | 11 | def test_xor(): 12 | res = decrypt(Config().library_default().complete_config(),"Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/") 13 | assert re.findall("This is a test for XOR", res) 14 | 15 | @pytest.mark.skip("Skipping because it matches on Discover card, this is a PyWhat bug that's being fixed.") 16 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "") 17 | def test_xor_tui_multi_byte(mock_click): 18 | # https://github.com/Ciphey/Ciphey/issues/655 19 | runner = CliRunner() 20 | mock_click.return_value = "y" 21 | result = runner.invoke(main, ['-vvv', '-t', '360w0x11450x114504421611100x0y0545000x06171y1511070145150x110z45081709110y45071y1100423w2z3045120z0x060z450x1145080w170042060z0u1509071w45160w040x45160y0y020v0045001x1107453w2w374y422x0y1111000301450w03450w0y091y4510110x0y05450442160x0x02090745071y110042030z104504420v001y45120z0x060z450x11450003161x42110z42071717110042030z10060042041642110w071700420x16420z0y0v1x4550505342150z11160x000x090y11001149450u1009160x45001x1107450v071x1642060z170901420w04140045160w0z170416030y0111450z0445150w16160y070x0v0x110716450u040v0y0y02420x11420w04100145160z450017101600030w1706074y453z2z37160z0z0v450x1145041500160w08004207000104101100450y114501040y42061703060v42070z160w45110x0y05090042071x160045030y014208100v110x42071x1600453z2z3742000y01171x121100064511071w114x452z0x060042260x120w001y450w0316453z2z37160z0z0v450x0x1100051704160001420x0y160z450y1149420x1142120x0v0945000045111015071745030804180x0y0545040x0145150x090v451012021703010042260x120w001y45110w450707450400090042110z42061703060v42060z0u1509071w453z2z3742000y01171x121100064511071w114x45320z1x450y1645160w0x114511071w1142160z42090z0x025z4227000104101100453z2z37160z0z0v45060w1009060y4216450610040609450x1645120z000y422x450u040107450x1645160z0z171600174x455u4z']) 22 | assert result.exit_code == 0 23 | assert re.findall("This is a string encrypted with multi", str(result.output)) 24 | 25 | 26 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "") 27 | def test_xor_tui(mock_click): 28 | # https://github.com/Ciphey/Ciphey/issues/655 29 | runner = CliRunner() 30 | mock_click.return_value = "y" 31 | result = runner.invoke(main, ['-t', 'Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/']) 32 | assert result.exit_code == 0 33 | assert re.findall("This is a test for XOR", str(result.output)) 34 | 35 | @mock.patch("ciphey.basemods.Checkers.human.HumanChecker.check", return_value = "") 36 | def test_xor_tui_verbose_mode_doesnt_break(mock_click): 37 | # We had a bug where verbose mode broke xor 38 | # https://discord.com/channels/754001738184392704/814565556027654214/853183178104373310 39 | runner = CliRunner() 40 | mock_click.return_value = "y" 41 | result = runner.invoke(main, ['-v', '-t', 'Uihr!hr!`!udru!gns!YNS-!hu!hr!sd`mmx!mnof!un!l`jd!rtsd!ui`u!YNSunnm!b`o!fdu!hu/!Bhqidx!*!YNSunnm!hr!bnnm/']) 42 | assert result.exit_code == 0 43 | assert re.findall("This is a test for XOR", str(result.output)) 44 | 45 | def test_xor_atbash(): 46 | # Frsi!si!{!fwif!tmh!BMH-!sf!si!hw{nnc!nmlu!fm!o{qw!ighw!fr{f!BMHfmmn!y{l!uwf!sf/!Ysjrwc!*!BMHfmmn.si!ymmn/ 47 | # This is a test for XOR, it is really long to make sure that XORtool can get it. Ciphey + XORtool/is cool. 48 | # Previously xor only worked on level 1, this test ensures it always works on levels > 1 49 | res = decrypt(Config().library_default().complete_config(),"Frsi!si!{!fwif!tmh!BMH-!sf!si!hw{nnc!nmlu!fm!o{qw!ighw!fr{f!BMHfmmn!y{l!uwf!sf/!Ysjrwc!*!BMHfmmn.si!ymmn/") 50 | assert re.findall("This is a test for XOR", res) -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/ascii_shift.py: -------------------------------------------------------------------------------- 1 | """ 2 | ██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗ 3 | ██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝ 4 | ██║ ██║██████╔╝███████║█████╗ ╚████╔╝ 5 | ██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝ 6 | ╚██████╗██║██║ ██║ ██║███████╗ ██║ 7 | © Brandon Skerritt 8 | Github: brandonskerritt 9 | """ 10 | 11 | from typing import Dict, List, Optional 12 | 13 | import cipheycore 14 | import logging 15 | from rich.logging import RichHandler 16 | 17 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry 18 | 19 | 20 | @registry.register 21 | class Ascii_shift(Cracker[str]): 22 | def getInfo(self, ctext: str) -> CrackInfo: 23 | analysis = self.cache.get_or_update( 24 | ctext, 25 | "cipheycore::simple_analysis", 26 | lambda: cipheycore.analyse_string(ctext), 27 | ) 28 | 29 | return CrackInfo( 30 | success_likelihood=cipheycore.caesar_detect(analysis, self.expected), 31 | # TODO: actually calculate runtimes 32 | success_runtime=1e-5, 33 | failure_runtime=1e-5, 34 | ) 35 | 36 | @staticmethod 37 | def getTarget() -> str: 38 | return "ascii_shift" 39 | 40 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 41 | logging.info(f"Trying ASCII shift cipher on {ctext}") 42 | 43 | logging.debug("Beginning cipheycore simple analysis") 44 | 45 | # Hand it off to the core 46 | analysis = self.cache.get_or_update( 47 | ctext, 48 | "cipheycore::simple_analysis", 49 | lambda: cipheycore.analyse_string(ctext), 50 | ) 51 | logging.debug("Beginning cipheycore::caesar") 52 | possible_keys = cipheycore.caesar_crack( 53 | analysis, self.expected, self.group, self.p_value 54 | ) 55 | 56 | n_candidates = len(possible_keys) 57 | logging.info(f"ASCII shift returned {n_candidates} candidates") 58 | 59 | if n_candidates == 0: 60 | logging.debug("Filtering for better results") 61 | analysis = cipheycore.analyse_string(ctext, self.group) 62 | possible_keys = cipheycore.caesar_crack( 63 | analysis, self.expected, self.group, self.p_value 64 | ) 65 | 66 | candidates = [] 67 | 68 | for candidate in possible_keys: 69 | logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}") 70 | translated = cipheycore.caesar_decrypt(ctext, candidate.key, self.group) 71 | candidates.append(CrackResult(value=translated, key_info=candidate.key)) 72 | 73 | return candidates 74 | 75 | @staticmethod 76 | def getParams() -> Optional[Dict[str, ParamSpec]]: 77 | return { 78 | "expected": ParamSpec( 79 | desc="The expected distribution of the plaintext", 80 | req=False, 81 | config_ref=["default_dist"], 82 | ), 83 | "group": ParamSpec( 84 | desc="An ordered sequence of chars that make up the ASCII shift cipher alphabet", 85 | req=False, 86 | 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""", 87 | ), 88 | "p_value": ParamSpec( 89 | desc="The p-value to use for standard frequency analysis", 90 | req=False, 91 | default=0.01, 92 | ) 93 | # TODO: add "filter" param 94 | } 95 | 96 | def __init__(self, config: Config): 97 | super().__init__(config) 98 | self.group = list(self._params()["group"]) 99 | self.expected = config.get_resource(self._params()["expected"]) 100 | self.cache = config.cache 101 | self.p_value = float(self._params()["p_value"]) 102 | -------------------------------------------------------------------------------- /translations/hu/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Fordítások
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Mizu! 15 | 16 | Szóval érdekel a Ciphey-hoz történő közreműködés? 🤔 17 | 18 | De lehet, hogy zavarban vagy, hogy hol kezdd, vagy úgy gondolod, hogy a kódolási képességeid nem "elég jók". Nos, ez utóbbi - nevetséges! Teljesen rendben vagyunk a "rossz kóddal", és amúgy is, ha elolvastad ezt a dokumentumot, valószínűleg remek programozó vagy. Úgy értem, az újoncok nem gyakran járulnak hozzá GitHub projektekhez 😉 19 | 20 | Íme néhány módszer, amellyel hozzájárulhatsz a Ciphey-hoz: 21 | 22 | - Fordítsd le egy új nyelvre 🧏 23 | - Adj hozzá több titkosítási formát 📚 24 | - Készíts további dokumentumokat (nagyon fontos‼️ Örökké hálásak lennénk) 25 | - Javítsd ki a GitHub Issues-on szereplő bugokat (ebben segítünk 😊) 26 | - Alakítsd át a kódbázist 🥺 27 | 28 | Ha ezek keményen hangzanak, ne aggódj! Ez a dokumentum pontosan bemutatja, hogyan lehet elérni ezeket. És még többet .... A neved bekerül a Ciphey közreműködői listájába, és örökké hálásak leszünk! 🙏 29 | 30 | Van egy kis Discord szerverünk, ahol beszélgethetsz a fejlesztőkkel, és segítséget kaphatsz. Alternatív megoldásként írj egy GitHub-Issue-t a javaslatodról. Ha csatlakozni akarsz a Discordhoz: 31 | 32 | [Discord Server](https://discord.gg/KfyRUWw) 33 | 34 | # Hogy lehet hozzájárulni 35 | 36 | A Ciphey-nak mindig több dekódoló eszközre van szüksége! Ha meg szeretnéd tudni, hogyan integrálhatsz egy kódot a titkosításba, nézdd meg ezeket: 37 | 38 | - Egyszerű példa 39 | - API referencia 40 | 41 | Jó lenne, ha néhány tesztet írnál rá, egyszerűen másolj át egy függvényt a Ciphey / tests / test_main.py fájlba, és cseréld le a rejtjelszöveget a titkosításával kódolt valamire. Ha nem adsz hozzá teszteket, valószínűleg továbbra is egyesítjük a kódot, de sokkal nehezebb lesz diagnosztizálnunk a hibákat! 42 | 43 | Magától értetődik, hogy felveszünk téged a közreműködők listájába kemény munkádért! 44 | 45 | # Adj hozzá egy új nyelvet 🧏 46 | 47 | Az alapértelmezett nyelvellenőrző, `brandon`, több nyelvvel is működik. Ez ijesztően hangozhat. 48 | De őszintén szólva mindössze annyit kell tenned, hogy veszel egy szótárat, elvégzel egy kis elemzést (ehhez van segítő kódunk), majd hozzáadod a szótárat és az elemzéseket egy repóhoz. Ezután hozzáadod a nyelvet a `settings.yml` fájlhoz. 49 | 50 | # Készíts további dokumentációt 51 | 52 | A dokumentáció a Ciphey legfontosabb része. Minél több dokumentáció, annál jobb. 53 | 54 | És bízz bennem, amikor azt mondom, ha hozzájárulsz a nagyszerű dokumentációhoz, akkor ugyanazon a szinten leszel látható, mint a kód-közreműködők. A dokumentáció elengedhetetlen. 55 | 56 | Nagyon sokféleképpen járulhatsz hozzá a dokumentációhoz. 57 | 58 | - Doc stringek beillesztése a kódba 59 | - A jelenlegi dokumentáció javítása (README, ez a fájl, a Read The Docs oldalunk) 60 | - Dokumentáció fordítása 61 | 62 | És még sok más! 63 | 64 | # Javíts bugokat 65 | 66 | Látogass el a GitHub-Issues oldalunkra, ahol megtalálod a Ciphey összes hibáját! Javítsd ki őket és felkerülsz a közreműködők listájára ;) 67 | 68 | # Alakítsd át a kódbázist 69 | 70 | Ciphey nem minden része követi a PEP8 szabályzatot, és sok az ismétlődő kódrészlet. 71 | -------------------------------------------------------------------------------- /translations/ru/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Translations
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Привет! 15 | 16 | Итак, вы заинтересованы в том, чтобы внести свой вклад в Ciphey? 🤔 17 | 18 | Может быть, ты не совсем уверен, с чего начать. Или, может быть, вы считаете, что ваши навыки программирования "недостаточно хороши". Что касается последнего - полная чушь! Мы совсем не против "плохого кода". Кроме того, то, что вы читаете этот документ, говорит о том, что вы отличный программист. Ведь в проектах GitHub участвует очень мало новичков. 😉. 19 | 20 | Вот несколько способов, которыми вы можете внести свой вклад: 21 | 22 | - Добавить новый язык 🧏 23 | - Добавьте больше методов шифрования 24 | - Доработать документацию (очень важно! Мы будем бесконечно благодарны) 25 | - Исправить ошибки, представленные через GitHub issues (мы можем поддержать вас в этом 😊) 26 | - Рефакторинг нашей кодовой базы 🥺 27 | 28 | Если все это кажется сложным, не волнуйтесь! В этом документе вы узнаете, как достичь любой из этих целей. Кроме того, ваше имя будет добавлено в список соавторов Ciphey, и мы будем вам бесконечно благодарны! 🙏 29 | 30 | У нас есть небольшой чат Discord, где вы можете пообщаться с разработчиками и получить помощь. Кроме того, вы можете написать GitHub issue в отношении вашего предложения. Если вы хотите, чтобы вас добавили в Discord, напишите нам DM или попросите нас как-то иначе. 31 | 32 | [Discord Server](https://discord.gg/KfyRUWw) 33 | 34 | # Как внести вклад 35 | 36 | Ciphey всегда нуждается в новых инструментах расшифровки! Чтобы узнать, как интегрировать код в Ciphey, посмотрите: 37 | 38 | - - простое руководство 39 | - - справка по API 40 | 41 | Было бы неплохо, если бы вы написали несколько тестов для своего кода. Это очень просто: скопируйте функцию в **Ciphey/tests/test_main.py** и замените шифрованный текст на что-то, закодированное вашим шифром. Если вы не добавите тесты, мы, вероятно, все равно примем ваш код, но нам будет гораздо труднее диагностировать ошибки! 42 | 43 | Само собой разумеется, что мы добавим вас в список участниуов за вашу тяжелую работу! 44 | 45 | ## Добавить новый язык 🧏 46 | 47 | Стандартная программа проверки языка, `brandon`, работает с несколькими языками. Это может показаться сложным. 48 | Но, честно говоря, все, что вам нужно сделать, это взять словарь, сделать небольшой анализ (мы написали код, чтобы помочь вам в этом), добавить словари и анализ в репозиторий. А затем добавить опцию в `settings.yml`. 49 | 50 | ## Доработать документацию 51 | 52 | Документация - самая важная часть Ciphey. Отсутствие документации - это огромный технический долг кода, а мы хотим этого избежать. 53 | 54 | Поверьте мне, когда я говорю, что если вы внесете свой вклад в создание отличной документации, вас будут воспринимать на том же уровне, что и авторов кода. Документация абсолютно необходима. 55 | 56 | Существует множество способов добавления документации. 57 | 58 | - Строки документации в коде 59 | - Улучшение нашей текущей документации (README, этот файл, наши страницы Ciphey Wiki) 60 | - Перевод документации 61 | 62 | И многое другое! 63 | 64 | # Исправление ошибок 65 | 66 | Посетите нашу страницу проблем на GitHub, чтобы посмотреть все известные ошибки, которые есть в Ciphey! Исправьте их, и вы будете добавлены в список соавторов. ;) 67 | 68 | # Рефакторинг кодовой базы 69 | 70 | Не весь Ciphey следует PEP8, и часть кода повторяется. 71 | -------------------------------------------------------------------------------- /translations/pt-br/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Traduções
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Olá! 15 | 16 | Então você está interessado em contribuir com Ciphey? 🤔 17 | 18 | Talves você esteja confudo em onde começar, ou você acredita que suas habilidades em escrever código não são "boas o bastante"? Bom, para a segunda opção - isso é ridículo! Nós estamos de boa com "código ruim" e mesmo assim, se você está lendo esse documento, você provavelmente é um programador bom. Quer dizer, iniciantes normalmente não aprendem a contribuir em projetos do GitHub. 😉 19 | 20 | Aqui estão algumas maneiras de contribuir com Ciphey: 21 | 22 | - Adicione uma linguagem nova 🧏 23 | - Adicione metodos de criptografia 📚 24 | - Crie mais documentação (muito importante! Nós seriamos eternamente gratos) 25 | - Resolva bugs nas questoes do GitHub (nós podemos te ajudar nisso 😊) 26 | - Refatore o código 🥺 27 | 28 | Se esses parecem difíceis, não se preocupe! Esse documento vai te ensinar exatamente como alcançar qualquer um desses. Além disso, seu nome será adicionado para a lista de contribuidores do Ciphey e nós seremos eternamente gratos! 🙏 29 | 30 | Nós temos um pequeno chat do Discord para você conversar com os desenvolvedores e receber uma ajuda. Alternativamente, você pode escrever uma issue no GitHub para a sua sugestão. Se você quiser ser adicionado no Discord, mande uma DM ou nos pergunte de alguma maneira. 31 | 32 | [Servidor do Discord](https://discord.gg/KfyRUWw) 33 | 34 | # Como contribuir 35 | 36 | Ciphey sempre precisa mais ferramentas de descriptografia! Para aprender como integrar código no Ciphey, dê uma olhada: 37 | 38 | - para um tutorial simples 39 | - para a referência da API 40 | 41 | Seria bom se você escrever testes, simplesmente copiando a função em Ciphey/tests/test_main.py e substituindo o texto cifrado por algo codificado pela sua cifra. Se você não adicionar testes, nós provavelmente ainda aceitaremos, mas vai ser muito mais difícil para nós diagnosticar os bugs! 42 | 43 | Não precisa nem dizer que nós adicionaremos você para a lista de contribuidores por seu trabalho duro! 44 | 45 | # Adicionar uma linguagem nova 🧏 46 | 47 | O verificador de linguagem padrão, `brandon`, trabalha com multiplas linguagens. Agora, isso pode soar assustador. 48 | Mas honestamente, tudo oque você deve fazer é pegar um dicionário, fazer uma pequena análise (nós escrevemos código para te ajudar com isso), adicionar os dicionários e análise para o repositório. E então adicionar a opção para `settings.yml`. 49 | 50 | # Criar mais documentação 51 | 52 | Documentação é a parte mais importante de Ciphey. Sem documentação o codigo fica dificil de entender e nós não queremos isso. 53 | 54 | Acredite quando eu digo, se você contribuir com boa documentação, você será visto no mesmo nível de contribuidores de códifo. Documentação é absolutamente vital. 55 | 56 | Existem várias maneiras de adicionar documentação. 57 | 58 | - Documentando strings no código 59 | - Melhorando a documentação atual (README, esse arquivo, as paginas Wiki do Ciphey) 60 | - Traduzindo documentação 61 | 62 | E muito mais! 63 | 64 | # Resolver bugs 65 | 66 | Visite nossa página de GitHub issues para encontrar todos os bugs que Ciphey tem! Acabe com eles e você será adicionado na lista de contribuidores. ;) 67 | 68 | # Refactorar o código 69 | 70 | Nem todo código de Ciphey segue PEP8 e uma parte do código é repetida. 71 | -------------------------------------------------------------------------------- /translations/nl/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Vertalingen
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Hey daar! 15 | 16 | Dus je bent geïnteresseerd om bij te dragen aan Ciphey? 🤔 17 | 18 | Misschien weet u niet waar u moet beginnen, of denkt u dat uw programmeervaardigheden niet "goed genoeg" zijn? Nou, voor het laatste - dat is belachelijk! We zijn helemaal in orde met "slechte code" en zelfs dan, als je dit document leest, ben je waarschijnlijk een geweldige programmeur. Ik bedoel, nieuwelingen leren niet vaak om bij te dragen aan GitHub-projecten 😉 19 | 20 | Hier zijn enkele manieren waarop u kunt bijdragen aan Ciphey: 21 | 22 | - Voeg een nieuwe taal toe 🧏 23 | - Voeg meer encryptiemethoden toe 📚 24 | - Maak meer documentatie (erg belangrijk! We zouden je eeuwig dankbaar zijn) 25 | - Fix bugs die zijn ingediend via GitHub Issues (we kunnen u hierbij ondersteunen 😊) 26 | - Refactor de codebase 🥺 27 | 28 | Als deze moeilijk klinken, hoeft u zich geen zorgen te maken! In dit document wordt precies uitgelegd hoe u elk van deze kunt bereiken. Je naam wordt ook toegevoegd aan de lijst met bijdragers van Ciphey, en we zullen je eeuwig dankbaar zijn! 🙏 29 | 30 | We hebben een kleine Discord-chatroom om met de ontwikkelaars te praten en hulp te krijgen. U kunt ook een GitHub Issue schrijven voor uw suggestie. Als je aan de Discord wilt worden toegevoegd, stuur ons dan een DM of vraag het ons op een of andere manier. 31 | [Discord Server](https://discord.gg/KfyRUWw) 32 | 33 | # Hoe u kunt bijdragen 34 | 35 | Ciphey heeft altijd meer decoderingstools nodig! Voor meer informatie over het integreren van code in ciphey, ga je naar: 36 | 37 | - voor een simpele tutorial 38 | - voor een API-referentie 39 | 40 | Het zou leuk zijn als je er enkele tests voor zou schrijven, door simpelweg een functie in de Ciphey/tests/test_main.py te kopiëren en de cijfertekst te vervangen door iets dat met je cipher is gecodeerd. Als u geen tests toevoegt, zullen we deze waarschijnlijk nog steeds merge,, maar het zal veel moeilijker voor ons zijn om bugs te vinden! 41 | 42 | Het is vanzelfsprekend dat we u voor uw harde werk aan de lijst met bijdragers zullen toevoegen! 43 | 44 | # Voeg een nieuwe taal toe 🧏 45 | 46 | De standaard taalcontrole, `brandon`, werkt met meerdere talen. Dit klinkt misschien ontmoedigend. 47 | Maar eerlijk gezegd hoef je alleen maar een woordenboek te nemen, een kleine analyse uit te voeren (we hebben code geschreven om je hierbij te helpen), de woordenboeken en analyse toe te voegen aan een repository. En voeg dan de optie toe aan `settings.yml`. 48 | 49 | # Maak meer documentatie 50 | 51 | Documentatie is het belangrijkste onderdeel van Ciphey. Geen enkele documentatie is een extreme 'codeschuld', en dat willen we niet. 52 | 53 | Geloof me wanneer ik zeg dat als je bijdraagt aan geweldige documentatie, je op hetzelfde niveau wordt gezien als codebijdragers. Documentatie is absoluut essentieel. 54 | 55 | Er zijn veel manieren waarop u documentatie kunt toevoegen. 56 | 57 | - Doc strings in de code 58 | - Verbeteren van onze huidige documentatie (README, dit bestand, onze Ciphey Wiki pagina's) 59 | - Vertalen van documentatie 60 | 61 | En nog veel meer! 62 | 63 | # Fix bugs 64 | 65 | Bezoek onze GitHub-problemenpagina om alle bugs te vinden die Ciphey heeft! Fix ze en je wordt toegevoegd aan de lijst met bijdragers. ;) 66 | 67 | # Refactor de codebase 68 | 69 | Niet alle Ciphey volgt PEP8, en een deel van de code wordt herhaald. 70 | -------------------------------------------------------------------------------- /translations/it/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Traduzioni
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Salve! 15 | 16 | Allora, sei interessato a contribuire a Ciphey? 🤔 17 | 18 | Forse sei confuso su dove cominciare, o credi che le tue capacità di codifica non siano "abbastanza buone"? Beh, per quest'ultimo - è ridicolo! Siamo perfettamente a nostro agio con il "cattivo codice" e anche così, se stai leggendo questo documento, probabilmente sei un grande programmatore. Voglio dire, i neofiti non imparano spesso a contribuire ai progetti di GitHub 😉 19 | 20 | Alcuni consigli su come contribuire a Ciphey: 21 | 22 | - Aggiungendo una nuova lingua 🧏 23 | - Aggiungiendo altri metodi di crittografia 📚 24 | - Creando più documentazione (di grande importanza! Te ne saremmo eternamente grati) 25 | - Correggendo i bug inviati tramite i problemi di GitHub (possiamo supportarti in questo 😊) 26 | - Rifattorizzando il codice base 🥺 27 | 28 | Se, a primo impatto, ciò ti sembra molto difficile, non ti preoccupare! Questo documento ti spiegherà esattamente come raggiungere uno di questi obiettivi. Inoltre, il tuo nome sarà aggiunto alla lista dei collaboratori di Ciphey, e te ne saremo eternamente grati! 🙏 29 | 30 | Abbiamo un piccolo server Discord per parlare con gli sviluppatori e chiedere aiuto. In alternativa, puoi scrivere un issue di GitHub per il tuo suggerimento. Se vuoi essere aggiunto a Discord, inviaci un DM (messaggio privato diretto) o chiedi a noi in qualche altro modo. 31 | 32 | [Server Discord](https://discord.gg/KfyRUWw) 33 | 34 | # Come contribuire 35 | 36 | Ciphey ha sempre bisogno di più strumenti di decrittazione! Per imparare a integrare il codice nella cifratura, guarda: 37 | 38 | - https://github.com/Ciphey/Ciphey/wiki/Adding-your-own-ciphers per un semplice tutorial 39 | - https://github.com/Ciphey/Ciphey/wiki/Extending-Ciphey per un riferimento API 40 | 41 | Sarebbe bello se tu scrivessi dei test per questo, semplicemente copiando una funzione nel Ciphey/tests/test_main.py e sostituendo il testo cifrato con qualcosa codificato con il tuo cifrario. Se non aggiungi dei test, probabilmente uniremo comunque i tuoi cambiamenti, ma peer noi sarà molto più difficile diagnosticare i bug! 42 | 43 | Ovviamente ti aggiungeremo alla lista dei collaboratori per il tuo duro lavoro! 44 | 45 | # Aggiungere una nuova lingua 🧏 46 | 47 | "brandon" corregge le traduzioni e funziona con più lingue. Ora, questo può sembrare scoraggiante. 48 | Tutto quello che devi fare è prendere un dizionario, fare una piccola analisi (abbiamo scritto del codice per aiutarti in questo), aggiungere i dizionari e l'analisi ad un repo. E poi aggiungere l'opzione a `settings.yml`. 49 | 50 | # Creare più documentazione 51 | 52 | La documentazione è la parte più importante di Ciphey. Non avere una documentazione è una grande mancanza, e noi non vogliamo far mancare una documentazione. 53 | 54 | Fidati di me quando dico che se contribuisci ad una grande documentazione sarai visto allo stesso livello di chi contribuisce al codice. La documentazione è assolutamente vitale. 55 | 56 | Ci sono molti modi per aggiungere documentazione. 57 | 58 | - Stringhe di documenti nel codice 59 | - Migliorare la nostra attuale documentazione (il README, questo file e le pagine della wiki di Ciphey) 60 | - Traduzione della documentazione 61 | 62 | E molto di più! 63 | 64 | # Risolvi i bug 65 | 66 | Visita la pagina degli issue di GitHub per trovare tutti i bug che Ciphey ha! Schiacciali e sarai aggiunto alla lista dei collaboratori 67 | 68 | # Rifattorizza il codice base 69 | 70 | Non tutti i Ciphey seguono il PEP8, e una parte del codice si ripete. 71 | -------------------------------------------------------------------------------- /translations/id/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 |

2 | Terjemahan
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | Howdy! 15 | 16 | Jadi, Anda tertarik untuk berkontribusi di Ciphey? 🤔 17 | 18 | Tapi mungkin Anda bingung harus mulai dari mana, atau Anda yakin bahwa keahlian coding Anda tidak "cukup baik". Nah, untuk yang terakhir - itu konyol! Kami baik-baik saja dengan "kode buruk", dan meskipun demikian, jika Anda membaca dokumen ini, Anda mungkin seorang programmer yang hebat. Maksud saya, pemula jarang sekali belajar berkontribusi pada proyek GitHub 😉 19 | 20 | Berikut beberapa cara Anda dapat berkontribusi kepada Ciphey: 21 | 22 | - Tambahkan bahasa baru 🧏 23 | - Tambahkan lebih banyak metode enkripsi 📚 24 | - Buat lebih banyak dokumentasi (sangat penting‼️ Kami akan berterima kasih selamanya) 25 | - Perbaiki bug yang dikirimkan melalui GitHub Issues (kami dapat membantu Anda dalam hal ini 😊) 26 | - Refactor basis kode 🥺 27 | 28 | Jika ini terdengar sulit, jangan khawatir! Dokumen ini akan memandu Anda bagaimana tepatnya mencapai semua ini. Dan juga... Nama Anda akan ditambahkan ke daftar kontributor Ciphey, dan kami akan sangat berterima kasih! 🙏 29 | 30 | Kami memiliki Discord server kecil agar Anda dapat berbicara dengan pengembang Ciphey dan mendapatkan bantuan. Atau, anda juga bisa menulis saran-saran anda di GitHub issue kita. Jika Anda ingin ditambahkan ke Discord, DM kami atau tanyakan kepada kami. 31 | 32 | [Server Discord](https://discord.gg/KfyRUWw) 33 | 34 | # Bagaimana cara berkontribusi? 35 | 36 | Ciphey selalu membutuhkan lebih banyak alat dekripsi! Untuk mempelajari cara mengintegrasikan kode ke dalam ciphey, bacalah: 37 | 38 | - untuk tutorial sederhana 39 | - untuk referensi API 40 | 41 | Akan lebih bagus jika anda bisa menulis beberapa test untuknya. Ini bisa dilakukan hanya dengan menyalin fungsi di Ciphey/tests/test_main.py dan menganti ciphertest dengan sesuatu yang dikodekan dengan cipher anda. Jika anda tidak menambahkan test, ada kemungkinan besar kami akan tetap menggabungkannya, tetapi akan lebih sulit bagi kamu untuk mendiagnosis bug! 42 | 43 | Tak perlu dikatakan bahwa kami akan menambahkan Anda ke daftar kontributor atas kerja keras Anda! 44 | 45 | # Tambahkan bahasa baru 🧏 46 | 47 | Pemeriksa bahasa yang kita pakai, `brandon`, berfungsi dengan banyak bahasa. Sekarang, ini mungkin terdengar menakutkan. 48 | Tapi sejujurnya, yang harus Anda lakukan adalah mengambil kamus, melakukan sedikit analisis (kami telah menulis kode untuk membantu Anda dalam hal ini), menambahkan kamus dan analisisnya ke repo. Dan kemudian tambahkan opsi ke `settings.yml`. 49 | 50 | # Buat lebih banyak dokumentasi 51 | 52 | Dokumentasi adalah bagian terpenting dari Ciphey. Tidak ada dokumentasi merupakan hutang kode yang ekstrim, dan kami tidak menginginkannya. 53 | 54 | Dan percayalah ketika saya mengatakan, jika Anda berkontribusi dengan baik kepada dokumentasi, Anda akan berada pada level yang sama dengan kontributor kode. Dokumentasi sangatlah vital. 55 | 56 | Ada banyak cara anda bisa menambahkan dokumentasi. 57 | 58 | - Menambahkan Docstrings di kode 59 | - Membaikan dokumentasi kamu saat ini (README, file ini, halaman Read The Docs kami) 60 | - Menerjemahkan dokumentasi 61 | 62 | dan lain-lain! 63 | 64 | # Perbaiki Bug 65 | 66 | Kunjungi halaman GitHub Issue kami untuk menemukan semua bug yang dimiliki Ciphey! Dan hancurkan mereka, Anda akan ditambahkan ke daftar kontributor ;) 67 | 68 | # Refacor basis kode 69 | 70 | Tidak semua kode Ciphey mengikuti PEP8, dan beberapa kode diulang-ulang. 71 | -------------------------------------------------------------------------------- /translations/pt-br/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Traduções
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Código de conduta do colaborador 15 | 16 | ## Nosso juramento 17 | 18 | No interesse de promover um ambiente aberto e acolhedor, nós como contribuidores e mantedores juramos fazer com que a participação no nosso projeto e comunidade, uma experiência livre de assédio para todos, independente de idade, tamanho do corpo, deficiência, etnia, características sexuais, identidade de gênero e expressão, nível de experiência, educação, status sócio-econômico, nacionalidade, aparência pessoal, raça, religião ou identidade e orientação sexual. 19 | 20 | ## Nossas normas 21 | 22 | Exemplos de comportamentos que contribuem em criar um ambiente positivo incluem: 23 | 24 | - Usar linguagem acolhedora e inclusiva 25 | - Respeitar diferentes pontos de vista e experiências 26 | - Aceitar críticas construtivas 27 | - Focar no que é melhor para a comunidade 28 | - Demonstrar empatia para os outros membros da comunidade 29 | 30 | Exemplos de comportamentos inaceitáveis por participantes incluem: 31 | 32 | - Uso de linguagem ou imagens sexuais e avanços ou atenções sexuais indesejáveis. 33 | - Comentários indesejáveis, insultantes/derrogatórios e ataques pessoais ou políticos. 34 | - Abuso público ou privado 35 | - Publicar informação privada de alguem, como endereço fisíco ou virtual, sem permissão explícita. 36 | - Outras condutas que poderiam ser consideradas inapropriadas num ambiente profissional 37 | 38 | ## Nossas Responsabilidades 39 | 40 | Mantedores do projeto são responsáveis por clarificar as normas de comportamento aceitável e é esperado que tomem ações corretivas apropriadas e justas em resposta a qualquer instância de comportamento inaceitável. 41 | 42 | São responsabilidades e direitos dos mantedores do projeto:remover, editar ou rejeitar comentários, commits, códifo, edições na wiki, questões e outras contribuições que não se alinhem com esse código de conduta, ou banir temporáriamente ou permanentemente qualquer contribuidor por outro comportamento que são dados como inapropriados, ameaçadores, ofensivos ou prejudiciais. 43 | 44 | ## Escopo 45 | 46 | Esse código de conduta aplica tanto em espaços para o projeto como em espaços públicos em quem um indivíduo esteja representando o projeto ou a comunidade. Exemplos de representação do projeto ou comunidade incluem usar um endereço de e-mail oficial do projeto, publicações numa conta oficial do projeto em uma rede social ouo agindo como um representante num evento online ou offline. Representação do projeto pode ser definido e clarificado posteriormente por mantedores do projeto. 47 | 48 | ## Execução 49 | 50 | Instâncias de comportamento abusivo, assediante ou inaceitável poderá ser reportado contactando o time do projeto em brandon_skerrit. Todas reclamações serão revisadas e investigadas e resultarão em uma resposta que seja decidida necessária e apropriada para as circunstâncias. O time do projeto é obrigado a manter confidencialidade em relação ao relator de um incidente. Mais detalhes da política de execução específica podem ser publicados separadamente. 51 | 52 | Mantedores do projeto que não seguirem ou executarem o códico de conduta em boa fé podem sofrer repercussões temporárias ou permanentes como determinado por outros membros da liderança do projeto. 53 | 54 | ## Atribuição 55 | 56 | Esse código de conduta é adaptado do [Contributor Covenant][homepage], versão 1.4, 57 | disponível em 58 | 59 | [homepage]: https://www.contributor-covenant.org 60 | 61 | Para respostas de perguntas comuns sobre esse código de conduta, veja 62 | 63 | -------------------------------------------------------------------------------- /translations/id/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Terjemahan
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Kode Etik Contributor Covenant 15 | 16 | ## Ikrar Kami 17 | 18 | Dalam minat kami untuk menumbuhkan lingkungan yang terbuka dan ramah, kami sebagai 19 | kontributor dan pengelola berjanji untuk membuat partisipasi dalam proyek kami 20 | dan komunitas kami bebas dari pelecehan bagi semua orang, tanpa memandang usia, 21 | ukuran tubuh, disabilitas, kelompok etnis, identitas gender dan ekspresinya, tingkat pengalaman, pendidikan, status sosial ekonomi, kewarganegaraan, penampilan pribadi, ras, agama, atau identitas dan orientasi seksual. 22 | 23 | ## Standar Kami 24 | 25 | Contoh perilaku dalam berkontribusi yang baik untuk menciptakan sebuah lingkungan yang positif meliputi : 26 | 27 | * Memakai bahasa yang ramah dan inklusif 28 | * Menghormati sudut pandang dan pengalaman yang berbeda 29 | * Menerima kritik konstruktif dengan baik 30 | * Fokus terhadap apa yang terbaik bagi komunitas 31 | * Menunjukkan empati kepada anggota komunitas yang lain 32 | 33 | Contoh perilaku yang tidak dapat diterima oleh partisipan meliputi : 34 | 35 | * Penggunaan bahasa atau citra seksual dan perhatian seksual yang tidak diinginkan. 36 | * Trolling, komentar menghina/merendahkan, dan serangan terhadap individual atau pandangan politik. 37 | * Pelecahan secara umum atau pribadi 38 | * Menerbitkan informasi pribadi orang lain, seperti alamat fisik atau elektronik, tanpa izin. 39 | * Perilaku lain yang secara wajar dapat dianggap tidak sesuai dalam lingkungan profesional 40 | 41 | ## Tanggung Jawab Kami 42 | 43 | Pengelola proyek bertanggung jawab untuk mengklarifikasi standar perilaku yang dapat diterima dan diharapkan untuk melakukan tindakan korektif yang tepat dan adil dalam menanggapi setiap kasus perilaku yang tidak dapat diterima. 44 | 45 | Pengelola proyek mempunyai hak dan tanggung jawab untuk menghapus, mengedit, atau 46 | menolak komentar, commit, kode, suntingan wiki, isu, dan kontribusi lainnya 47 | yang tidak sesuai dengan Kode Etik ini, atau untuk melarang sementara 48 | atau secara permanen, berkontribusi dalam hal perilaku lain yang di anggap tidak pantas, mengancam, menyinggung, atau berbahaya. 49 | 50 | ## Lingkup 51 | 52 | Kode Etik ini berlaku baik di dalam proyek maupun di ruang publik 53 | ketika seseorang mewakili proyek atau komunitasnya. Contoh dari 54 | mewakili sebuah proyek atau komunitas termasuk dalam menggunakan alamat email resmi proyek, posting melalui akun media sosial resmi, atau bertindak sebagai orang yang ditunjuk menjadi perwakilan di acara online atau offline. Representasi proyek mungkin selanjutnya didefinisikan dan diklarifikasi oleh pengelola proyek. 55 | 56 | ## Penegakan 57 | 58 | Kejadian perilaku kasar, pelecehan, atau tidak dapat diterima yang terjadi 59 | dapat dilaporkan kepada tim inti proyek di brandon_skerrit. Semua keluhan 60 | akan ditinjau, diselidiki dan akan menghasilkan tanggapan yang dianggap perlu 61 | dan sesuai dengan keadaan. Tim inti proyek berkewajiban menjaga kerahasiaan pelapor yang berkenaan dengan pelaporan suatu insiden. Rincian lebih lanjut tentang kebijakan penegakan khusus akan dipublikasikan secara terpisah. 62 | 63 | Pengelola proyek yang tidak mengikuti atau melaksanakan Kode Etik dengan itikad 64 | baik mungkin akan menghadapi dampak sementara atau permanen seperti yang ditentukan 65 | oleh para anggota lain dari pimpinan proyek. 66 | 67 | ## Atribut 68 | 69 | Kode Etik ini diadaptasi dari [Contributor Covenant][homepage], versi 1.4, 70 | tersedia di [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html][version] 71 | 72 | [homepage]: https://www.contributor-covenant.org 73 | [version]: http://contributor-covenant.org/version/1/4/ 74 | -------------------------------------------------------------------------------- /translations/hu/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Fordítások
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Közreműködői magatartási kódex 15 | 16 | ## Zálogunk 17 | 18 | A nyitott és barátságos környezet elősegítése érdekében, mi, 19 | a közreműködők és fenntartók ígéretet teszünk arra, hogy részt veszünk projektünkben, és 20 | mindent megteszünk, hogy közösségünk zaklatásmentes élményt nyújtson mindenkinek, 21 | kortól, testtől, mérettől, fogyatékosságtól, etnikumtól, nemi jellemzőktől, nemi identitás és kifejezés, 22 | tapasztalati szint, végzettség, társadalmi-gazdasági helyzet, nemzetiség, személyes 23 | megjelenés, faj, vallás vagy szexuális identitás és orientációtól függetlenül. 24 | 25 | ## Szabványaink 26 | 27 | Példák olyan viselkedésre, melyek hozzájárulnak a pozitív környezet kialakításához: 28 | 29 | - Üdvözlő és befogadó nyelv használata 30 | - Tiszteletben tartani az eltérő nézőpontokat és tapasztalatokat 31 | - Építő kritikák elfogadása 32 | - Összpontosítás arra, ami a közösség számára a legjobb 33 | - Empátia mutatása a közösség többi tagjával szemben 34 | 35 | Példák a résztvevők által elfogadhatatlan viselkedésre: 36 | 37 | - Szexualizált nyelvezet vagy képek használata és nem kívánt szexuális figyelem vagy tolakodáss 38 | - Trollkodás, sértő / becsmérlő megjegyzések és személyes vagy politikai támadások 39 | - Nyilvános vagy magán zaklatás 40 | - Mások személyes adatainak, például fizikai vagy elektronikus címének közzététele kifejezett engedély nélkül 41 | - Egyéb magatartás, amely szakmai körülmények között ésszerűen helytelennek tekinthető 42 | 43 | ## Feladataink 44 | 45 | A projekt fenntartói felelősek az elfogadható szabványok tisztázásáért 46 | viselkedését, és várhatóan megfelelő és tisztességes korrekciós intézkedéseket foganatosítanak 47 | válaszként az elfogadhatatlan viselkedés esetére. 48 | 49 | A projektfenntartóknak joguk és felelősségük van eltávolítani, szerkeszteni vagy 50 | elutasítani azokat a megjegyzéseket, elkötelezettségeket, kódokat, wiki-szerkesztéseket, kérdéseket és az egyéb hozzászólásokat amelyek nem felelnek meg ennek a magatartási kódexnek, vagy ideiglenesen vagy 51 | tartósan közreműködő más magatartás miatt, amelyet nem tartunk megfelelőnek, fenyegető, sértő vagy káros. 52 | 53 | ## Hatály 54 | 55 | Ez a magatartási kódex a projekttereken és a nyilvános tereken egyaránt érvényes 56 | amikor az egyén képviseli a projektet vagy közösségét. Például 57 | egy projekt vagy közösség képviseletéhez tartozik egy hivatalos projekt e-mail használata, egy hivatalos közösségi médiafiókon keresztül történő közzététel, vagy kinevezettként való eljárás 58 | képviselője egy online vagy offline eseményen. A projekt képviseletét 59 | tovább meghatározzák és pontosítják a projektfenntartók. 60 | 61 | ## Végrehajtás 62 | 63 | Erőszakos, zaklató vagy más módon elfogadhatatlan viselkedés 64 | jelenltésre kerül a projekt csapatával. Minden panaszt felül fognak vizsgálni és kivizsgálják, és a körülményekhez megfelelőnek tekinthető választ fognak adni. A projekt csapata 65 | köteles megőrizni a titoktartást az eseménnyel kapcsolatban. 66 | A konkrét végrehajtási irányelvek további részleteit külön közzétehetjük. 67 | 68 | Azok a projektfenntartók, akik nem követik és nem tartják be megfelelően a magatartási kódexet, bizalmi megvonásban részesülnek átmenetileg vagy véglegesen a projekt vezetésének tagjai által. 69 | 70 | ## Hozzárendelés 71 | 72 | Ez a magatartási kódexet a [Contributor Covenant][homepage], formájára készült, version 1.4, 73 | elérhető 74 | 75 | [honlap]: https://www.contributor-covenant.org 76 | 77 | A magatartási kódex-szel kapcsolatos gyakori kérdésekre adott válaszokért lásd: 78 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/caesar.py: -------------------------------------------------------------------------------- 1 | """ 2 | ██████╗██╗██████╗ ██╗ ██╗███████╗██╗ ██╗ 3 | ██╔════╝██║██╔══██╗██║ ██║██╔════╝╚██╗ ██╔╝ 4 | ██║ ██║██████╔╝███████║█████╗ ╚████╔╝ 5 | ██║ ██║██╔═══╝ ██╔══██║██╔══╝ ╚██╔╝ 6 | ╚██████╗██║██║ ██║ ██║███████╗ ██║ 7 | © Brandon Skerritt 8 | Github: brandonskerritt 9 | """ 10 | from distutils import util 11 | from typing import Dict, List, Optional, Union 12 | 13 | import cipheycore 14 | import logging 15 | from rich.logging import RichHandler 16 | 17 | from ciphey.common import fix_case 18 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry 19 | 20 | 21 | @registry.register 22 | class Caesar(Cracker[str]): 23 | def getInfo(self, ctext: str) -> CrackInfo: 24 | analysis = self.cache.get_or_update( 25 | ctext, 26 | "cipheycore::simple_analysis", 27 | lambda: cipheycore.analyse_string(ctext), 28 | ) 29 | 30 | return CrackInfo( 31 | success_likelihood=cipheycore.caesar_detect(analysis, self.expected), 32 | # TODO: actually calculate runtimes 33 | success_runtime=1e-5, 34 | failure_runtime=1e-5, 35 | ) 36 | 37 | @staticmethod 38 | def getTarget() -> str: 39 | return "caesar" 40 | 41 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 42 | logging.info(f"Trying caesar cipher on {ctext}") 43 | # Convert it to lower case 44 | # 45 | # TODO: handle different alphabets 46 | if self.lower: 47 | message = ctext.lower() 48 | else: 49 | message = ctext 50 | 51 | logging.debug("Beginning cipheycore simple analysis") 52 | 53 | # Hand it off to the core 54 | analysis = self.cache.get_or_update( 55 | ctext, 56 | "cipheycore::simple_analysis", 57 | lambda: cipheycore.analyse_string(ctext), 58 | ) 59 | logging.debug("Beginning cipheycore::caesar") 60 | possible_keys = cipheycore.caesar_crack( 61 | analysis, self.expected, self.group, self.p_value 62 | ) 63 | 64 | n_candidates = len(possible_keys) 65 | logging.info(f"Caesar returned {n_candidates} candidates") 66 | 67 | if n_candidates == 0: 68 | logging.debug("Filtering for better results") 69 | analysis = cipheycore.analyse_string(ctext, self.group) 70 | possible_keys = cipheycore.caesar_crack( 71 | analysis, self.expected, self.group, self.p_value 72 | ) 73 | 74 | candidates = [] 75 | 76 | for candidate in possible_keys: 77 | logging.debug(f"Candidate {candidate.key} has prob {candidate.p_value}") 78 | translated = cipheycore.caesar_decrypt(message, candidate.key, self.group) 79 | candidates.append( 80 | CrackResult(value=fix_case(translated, ctext), key_info=candidate.key) 81 | ) 82 | 83 | return candidates 84 | 85 | @staticmethod 86 | def getParams() -> Optional[Dict[str, ParamSpec]]: 87 | return { 88 | "expected": ParamSpec( 89 | desc="The expected distribution of the plaintext", 90 | req=False, 91 | config_ref=["default_dist"], 92 | ), 93 | "group": ParamSpec( 94 | desc="An ordered sequence of chars that make up the caesar cipher alphabet", 95 | req=False, 96 | default="abcdefghijklmnopqrstuvwxyz", 97 | ), 98 | "lower": ParamSpec( 99 | desc="Whether or not the ciphertext should be converted to lowercase first", 100 | req=False, 101 | default=True, 102 | ), 103 | "p_value": ParamSpec( 104 | desc="The p-value to use for standard frequency analysis", 105 | req=False, 106 | default=0.01, 107 | ) 108 | # TODO: add "filter" param 109 | } 110 | 111 | def __init__(self, config: Config): 112 | super().__init__(config) 113 | self.lower: Union[str, bool] = self._params()["lower"] 114 | if not isinstance(self.lower, bool): 115 | self.lower = util.strtobool(self.lower) 116 | self.group = list(self._params()["group"]) 117 | self.expected = config.get_resource(self._params()["expected"]) 118 | self.cache = config.cache 119 | self.p_value = float(self._params()["p_value"]) 120 | -------------------------------------------------------------------------------- /translations/ru/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Translations
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Кодекс поведения участников 15 | 16 | ## Наши обязательства 17 | 18 | В интересах создания открытой и доброжелательной атмосферы мы, разработчики и соавторы проекта, обязуемся сделать участие в нашем проекте и сообществе свободным от притеснений для всех, независимо от возраста, размеров тела, инвалидности, этнической принадлежности, половых признаков, гендерной идентичности и самовыражения, уровня опыта, образования, социально-экономического статуса, национальности, внешнего вида, расы, религии, сексуальной идентичности и ориентации. 19 | 20 | ## Наши стандарты 21 | 22 | Примеры поведения, способствующего созданию благоприятной среды: 23 | 24 | * Использовать приветливый и инклюзивный язык 25 | * Уважительно относиться к различным точкам зрения и опыту 26 | * Великодушно принимать конструктивную критику 27 | * Сосредотачиваться на том, что лучше для сообщества 28 | * Проявлять эмпатию по отношению к другим членам сообщества 29 | 30 | Примеры неприемлемого поведения участников: 31 | 32 | * Использование сексуально окрашенного языка или образов, а также нежелательное сексуальное внимание или ухаживания. 33 | * Троллинг, оскорбительные/уничижительные комментарии, личные или политические нападки 34 | * Публичные или частные домогательства 35 | * Публикация чужой частной информации, такой как физический или электронный адрес, без прямого разрешения. 36 | * Другое поведение, которое можно обоснованно считать неуместным в профессиональной среде. 37 | 38 | ## Наша ответственность 39 | 40 | Руководители проекта несут ответственность за разъяснение стандартов приемлемого поведения и должны предпринимать соответствующие и справедливые меры по исправлению ситуации в случаях неприемлемого поведения. 41 | 42 | Разработчики проекта имеют право и несут ответственность за удаление, редактирование или отклонение комментариев, коммитов, кода, правок в Вики, вопросов и других материалов, которые не соответствуют этому Кодексу поведения, или временно или навсегда забанить любого участника за поведение, которое они считают неприемлемым, угрожающим, оскорбительным или вредным. 43 | 44 | ## Область применения 45 | 46 | Настоящий Кодекс поведения применяется как в рамках проекта, так и в общественном пространстве, когда пользователь представляет проект или его сообщество. Примерами представления проекта или сообщества являются использование официального адреса электронной почты проекта, размещение информации через официальный аккаунт в социальных сетях, или выступление в качестве назначенного представителя на онлайн или офлайн мероприятии. Представление проекта может быть определяться и уточняться разработчиками проекта. 47 | 48 | ## Правоприменение 49 | 50 | О случаях оскорбительного, притеснительного или иного неприемлемого поведения можно сообщить, обратившись к команде проекта на имя brandon_skerrit. Все жалобы будут рассмотрены и расследованы, по результатам чего будет принят ответ, который будет сочтен необходимым и соответствующим обстоятельствам. Команда проекта обязуется соблюдать конфиденциальность в отношении лица, сообщившего об инциденте. Более подробная информация о конкретных политиках правоприменения может быть опубликована отдельно. 51 | 52 | Участники проекта, не соблюдающие или недобросовестно выполняющие Кодекс поведения, могут быть подвержены временным или постоянным мерам воздействия, которые определяются руководством проекта. 53 | 54 | ## Авторстов 55 | 56 | Настоящий Кодекс поведения составлен на основе [Contributor Covenant][homepage], версии 1.4, оригинал доступен по ссылке 57 | 58 | [homepage]: https://www.contributor-covenant.org 59 | 60 | Ответы на распространенные вопросы о данном кодексе поведения см. 61 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/xandy.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import Dict, List, Optional 3 | 4 | import logging 5 | from rich.logging import RichHandler 6 | 7 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, registry 8 | 9 | 10 | @registry.register 11 | class Xandy(Cracker[str]): 12 | def getInfo(self, ctext: str) -> CrackInfo: 13 | return CrackInfo( 14 | success_likelihood=0.1, 15 | success_runtime=1e-5, 16 | failure_runtime=1e-5, 17 | ) 18 | 19 | @staticmethod 20 | def binary_to_ascii(variant): 21 | # Convert the binary string to an integer with base 2 22 | binary_int = int(variant, 2) 23 | byte_number = binary_int.bit_length() + 7 // 8 24 | 25 | # Convert the resulting int to a bytearray and then decode it to ASCII text 26 | binary_array = binary_int.to_bytes(byte_number, "big") 27 | try: 28 | ascii_text = binary_array.decode() 29 | logging.debug(f"Found possible solution: {ascii_text[:32]}") 30 | return ascii_text 31 | except UnicodeDecodeError as e: 32 | logging.debug(f"Failed to crack X-Y due to a UnicodeDecodeError: {e}") 33 | return "" 34 | 35 | @staticmethod 36 | def getTarget() -> str: 37 | return "xandy" 38 | 39 | def attemptCrack(self, ctext: str) -> List[CrackResult]: 40 | """ 41 | Checks an input if it only consists of two or three different letters. 42 | If this is the case, it attempts to regard those letters as 43 | 0 and 1 (with the third characters as an optional delimiter) and then 44 | converts it to ASCII text. 45 | """ 46 | logging.debug("Attempting X-Y replacement") 47 | variants = [] 48 | candidates = [] 49 | result = [] 50 | 51 | # Convert the ctext to all-lowercase and regex-match & replace all whitespace 52 | ctext = re.sub(r"\s+", "", ctext.lower(), flags=re.UNICODE) 53 | 54 | # cset contains every unique value in the ctext 55 | cset = list(set(list(ctext))) 56 | cset_len = len(cset) 57 | 58 | if not 1 < cset_len < 4: 59 | # We only consider inputs with two or three unique values 60 | logging.debug( 61 | "Failed to crack X-Y due to not containing two or three unique values" 62 | ) 63 | return None 64 | 65 | logging.debug(f"String contains {cset_len} unique values: {cset}") 66 | 67 | # In case of three unique values, we regard the least frequent character as the delimiter 68 | if cset_len == 3: 69 | # Count each unique character in the set to determine the least frequent one 70 | counting_list = [] 71 | for char in cset: 72 | counting_list.append(ctext.count(char)) 73 | val, index = min((val, index) for (index, val) in enumerate(counting_list)) 74 | delimiter = cset[index] 75 | logging.debug( 76 | f"{delimiter} occurs {val} times and is the probable delimiter" 77 | ) 78 | # Remove the delimiter from the ctext and compute new cset 79 | ctext = ctext.replace(delimiter, "") 80 | cset = list(set(list(ctext))) 81 | 82 | # Form both variants of the substitution 83 | for i in range(2): 84 | if i: 85 | variants.append(ctext.replace(cset[0], "1").replace(cset[1], "0")) 86 | else: 87 | variants.append(ctext.replace(cset[0], "0").replace(cset[1], "1")) 88 | 89 | # Apply function to both variants and strip stray NULL characters 90 | for variant in variants: 91 | candidates.append(self.binary_to_ascii(variant).strip("\x00")) 92 | for i, candidate in enumerate(candidates): 93 | if candidate != "": 94 | keyinfo = f"{cset[0]} -> {i} & {cset[1]} -> {str(int(not i))}" 95 | result.append(CrackResult(value=candidate, key_info=keyinfo)) 96 | logging.debug(f"X-Y cracker - Returning results: {result}") 97 | return result 98 | 99 | @staticmethod 100 | def getParams() -> Optional[Dict[str, ParamSpec]]: 101 | return { 102 | "expected": ParamSpec( 103 | desc="The expected distribution of the plaintext", 104 | req=False, 105 | config_ref=["default_dist"], 106 | ) 107 | } 108 | 109 | def __init__(self, config: Config): 110 | super().__init__(config) 111 | self.expected = config.get_resource(self._params()["expected"]) 112 | self.cache = config.cache 113 | -------------------------------------------------------------------------------- /translations/nl/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Vertalingen
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Gedragscode voor Bijdragersconvenant 15 | 16 | ## Onze belofte 17 | 18 | In het belang van het bevorderen van een open en gastvrije omgeving, beloven wij als 19 | bijdragers en onderhouders het deelnemen aan ons project en 20 | onze gemeenschap een intimidatie-vrije ervaring voor iedereen, ongeacht leeftijd, 21 | lichaamsgrootte, handicap, etniciteit, geslachtskenmerken, genderidentiteit en expressie, 22 | ervaringsniveau, opleiding, sociaaleconomische status, nationaliteit, uiterlijk, 23 | ras, religie of seksuele identiteit en geaardheid. 24 | 25 | ## Onze normen 26 | 27 | Voorbeelden van gedrag dat bijdraagt aan het creëren van een positieve omgeving 28 | omvatten: 29 | 30 | - Gastvrije en inclusieve taal gebruiken 31 | - Respectvol zijn voor verschillende standpunten en ervaringen 32 | - Constructieve kritiek aanvaarden 33 | - Focussen op wat het beste is voor de gemeenschap 34 | - Empathie tonen naar andere leden van de gemeenschap 35 | 36 | Voorbeelden van onaanvaardbaar gedrag van deelnemers omvatten: 37 | 38 | - Het gebruik van geseksualiseerde taal of beelden en ongewenste seksuele aandacht 39 | - Trollen, beledigende / denigrerende opmerkingen en persoonlijke of politieke aanvallen 40 | - Intimidatie in het openbaar of privé 41 | - Het publiceren van privégegevens van anderen, zoals fysieke of elektronische adressen, 42 | zonder uitdrukkelijke toestemming 43 | - Ander gedrag dat redelijkerwijs als ongepast zou kunnen worden beschouwd in een 44 | professionele setting 45 | 46 | ## Onze verantwoordelijkheden 47 | 48 | Projectbeheerders zijn verantwoordelijk voor het verduidelijken van de normen van aanvaardbaar 49 | gedrag en wordt verwacht dat ze passende en eerlijke corrigerende maatregelen nemen in 50 | reactie op gevallen van onaanvaardbaar gedrag. 51 | 52 | Projectbeheerders hebben het recht en de verantwoordelijkheid om opmerkingen, commits, 53 | code, wiki-bewerkingen, issues en andere contributies die niet in overeenstemming zijn 54 | met deze Gedragscode te verwijderen, bewerken of weigeren, of om tijdelijk of permanent 55 | de toegang te verbieden van elke bijdrager voor ander gedrag dat zij ongepast, 56 | bedreigend, beledigend of schadelijk achten. 57 | 58 | ## Reikwijdte 59 | 60 | Deze Gedragscode is zowel van toepassing binnen projectruimten als in openbare ruimten 61 | wanneer een persoon het project of zijn gemeenschap vertegenwoordigt. Voorbeelden van 62 | het vertegenwoordigen van een project of gemeenschap omvat het gebruik van een officiële project-e-mail 63 | adres, posten via een officieel sociale media-account of optreden als een aangestelde 64 | vertegenwoordiger bij een online of offline evenement. Wat onder de vertegenwoordiging 65 | van een project kan vallen kan verder gedefinieerd en verduidelijkt worden door projectbeheerders. 66 | 67 | ## Handhaving 68 | 69 | Gevallen van grofheid, intimidatie of anderzijds onaanvaardbaar gedrag kan 70 | gemeld worden door contact op te nemen met het projectteam op brandon_skerrit. Alle 71 | klachten worden beoordeeld en onderzocht en resulteren in een reactie die 72 | noodzakelijk en passend geacht worden onder de omstandigheden. Het projectteam is 73 | verplicht tot geheimhouding met betrekking tot de melder van een incident. 74 | Verdere details van het handhavingsbeleid kunnen afzonderlijk worden gepost. 75 | 76 | Projectbeheerders die de Gedragscode niet in goed vertrouwen naleven of handhaven kunnen 77 | tijdelijke of permanente gevolgen ondervinden, zoals bepaald door anderen 78 | leden van de projectleiding. 79 | 80 | ## Attributie 81 | 82 | Deze gedragscode is gebaseerd op de [Contributor Covenant][homepage], versie 1.4, 83 | beschikbaar op 84 | 85 | [homepage]: https://www.contributor-covenant.org 86 | 87 | Voor antwoorden op veelgestelde vragen over deze gedragscode, zie 88 | -------------------------------------------------------------------------------- /translations/de/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Übersetzungen
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Vereinbarung über Verhaltenskodex für Mitwirkende 15 | 16 | ## Unsere Verpflichtung 17 | 18 | Im Interesse der Förderung eines offenen und einladenden Umfeldes wollen wir uns als Teilnehmer und Verantwortliche unseres Projektes verpflichten, die Teilnahme an dem Projekt und unserer Gemeinschaft zu einer belästigungsfreien Erfahrung zu machen – unabhängig von Alter, Körpergröße, Behinderung, ethnischer Zuordnung, geschlechtlicher Identität und Ausdruck, Erfahrungsstufe, Nationalität, persönlicher Erscheinung, Rasse, Religion oder sexueller Identität oder Orientierung. 19 | 20 | ## Unsere Standards 21 | 22 | Beispiele für Verhaltensweisen, welche dazu beitragen ein positives Umfeld zu erzeugen, beinhalten: 23 | 24 | - Die Verwendung von einladenden und einbindenden Formulierungen 25 | - Abweichenden Ansichten und Erfahrungen wird Respekt entgegengebracht 26 | - Konstruktive Kritik wird höflich entgegengenommen 27 | - Fokussierung auf das, was das Beste ist für die Gemeinschaft 28 | - Verständnis zeigen gegenüber anderen Mitgliedern der Gemeinschaft 29 | 30 | Beispiele für nicht akzeptables Verhalten beinhalten: 31 | 32 | - Die Verwendung sexualisierter Sprache, Bilder oder Symbolik sowie unerwünschte Versuche sexueller Anbahnung 33 | - Beleidigende / abwertende Kommentare, persönliche oder politische Angriffe, Nutzung des Internets für unbilliges Verhalten 34 | - Öffentliche oder private Belästigungen 35 | - Das Veröffentlichen von privaten Informationen Anderer, wie zum Beispiel physische oder elektronische Adressen, ohne deren ausdrückliche Erlaubnis 36 | - Anderes Verhalten, welches in einem professionellen Umfeld begründet als unangemessen betrachtet werden kann 37 | 38 | ## Unsere Verantwortlichkeiten 39 | 40 | Die Projektverantwortlichen sind verantwortlich dafür, die Standards für ein akzeptables Benehmen klarzustellen und es wird von ihnen erwartet, dass sie als Reaktion auf jegliches inakzeptables Verhalten passende und faire berichtigende Maßnahmen ergreifen. 41 | 42 | Die Projektverantwortlichen haben das Recht und die Verantwortung, Kommentare, Commits, Code, Wiki-Bearbeitungen, Support-Tickets und andere Beiträge, die nicht mit diesem Verhaltenskodex vereinbar sind, zu entfernen, zu bearbeiten oder abzulehnen, und jene Mitwirkende für Verhaltensweisen, die sie für unangemessen, bedrohend, beleidigend oder verletzend halten, zeitweilig oder dauerhaft zu sperren. 43 | 44 | ## Geltungsbereich 45 | 46 | Dieser Verhaltenskodex gilt sowohl innerhalb des Projektbereichs als auch in öffentlichen Bereichen, wenn eine Person das Projekt oder seine Gemeinschaft repräsentiert. Beispiele für die Repräsentation eines Projektes oder der Gemeinschaft beinhalten die Verwendung einer offiziellen Projekt-E-Mail-Adresse, das Versenden von Nachrichten über einen öffentlichen Social-Media-Account oder das Handeln als Repräsentant während einer Online- oder Offline-Veranstaltung. Der Begriff "Repräsentation des Projektes" kann durch die Projektverantwortlichen weiter ausformuliert und klargestellt werden. 47 | 48 | ## Umsetzung 49 | 50 | Fälle von missbräuchlichem, belästigendem oder anderweitig nicht akzeptablem Verhalten können dem Projektteam unter brandon_skerrit gemeldet werden. Alle Beschwerden werden geprüft und untersucht und werden zu einer Antwort führen, die angesichts der Umstände für notwendig und angemessen gehalten wird. Das Projektteam ist verpflichtet, über diejenigen, die Vorfälle gemeldet haben, Verschwiegenheit zu wahren. Weitere Einzelheiten zu speziellen Umsetzungsgrundsätzen können gesondert mitgeteilt werden. 51 | 52 | Projektverantwortliche, welche den Verhaltenskodex nicht befolgen, oder nicht nach bestem Wissen und Glauben für dessen Einhaltung sorgen, können sich vorübergehenden oder dauerhaften Auswirkungen gegenüberstehen, die durch andere Mitglieder der Projektleitung bestimmt wurden. 53 | 54 | ## Bezug 55 | 56 | Dieser Verhaltenskodex basiert auf dem Contributor Covenant, Version 1.4, verfügbar unter 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/git,python,virtualenv 3 | # Edit at https://www.gitignore.io/?templates=git,python,virtualenv 4 | 5 | ### Git ### 6 | # Created by git for backups. To disable backups in Git: 7 | # $ git config --global mergetool.keepBackup false 8 | *.orig 9 | 10 | 11 | # Created by https://www.gitignore.io/api/venv 12 | # Edit at https://www.gitignore.io/?templates=venv 13 | 14 | ### venv ### 15 | # Virtualenv 16 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 17 | .Python 18 | pyvenv.cfg 19 | .env 20 | .venv 21 | env/ 22 | venv/ 23 | ENV/ 24 | env.bak/ 25 | venv.bak/ 26 | pip-selfcheck.json 27 | ciphey.egg-info 28 | dist/ 29 | dist 30 | 31 | hansard.txt 32 | poetry.lock 33 | # End of https://www.gitignore.io/api/venv 34 | 35 | # Created by git when using merge tools for conflicts 36 | *.BACKUP.* 37 | *.BASE.* 38 | *.LOCAL.* 39 | *.REMOTE.* 40 | *_BACKUP_*.txt 41 | *_BASE_*.txt 42 | *_LOCAL_*.txt 43 | *_REMOTE_*.txt 44 | 45 | ### Python ### 46 | # Byte-compiled / optimized / DLL files 47 | __pycache__/ 48 | *.py[cod] 49 | *$py.class 50 | 51 | # C extensions 52 | *.so 53 | 54 | # Distribution / packaging 55 | .Python 56 | build/ 57 | develop-eggs/ 58 | dist/ 59 | downloads/ 60 | eggs/ 61 | .eggs/ 62 | lib/ 63 | lib64/ 64 | parts/ 65 | sdist/ 66 | var/ 67 | wheels/ 68 | pip-wheel-metadata/ 69 | share/python-wheels/ 70 | *.egg-info/ 71 | .installed.cfg 72 | *.egg 73 | MANIFEST 74 | 75 | # PyInstaller 76 | # Usually these files are written by a python script from a template 77 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 78 | *.manifest 79 | 80 | 81 | # Installer logs 82 | pip-log.txt 83 | pip-delete-this-directory.txt 84 | 85 | # Unit test / coverage reports 86 | htmlcov/ 87 | .tox/ 88 | .nox/ 89 | .coverage 90 | .coverage.* 91 | .cache 92 | nosetests.xml 93 | coverage.xml 94 | *.cover 95 | .hypothesis/ 96 | .pytest_cache/ 97 | 98 | # Translations 99 | *.mo 100 | *.pot 101 | 102 | # Django stuff: 103 | *.log 104 | local_settings.py 105 | db.sqlite3 106 | db.sqlite3-journal 107 | 108 | # Flask stuff: 109 | instance/ 110 | .webassets-cache 111 | 112 | # Scrapy stuff: 113 | .scrapy 114 | 115 | # Sphinx documentation 116 | docs/_build/ 117 | 118 | # PyBuilder 119 | target/ 120 | 121 | # Jupyter Notebook 122 | .ipynb_checkpoints 123 | 124 | # IPython 125 | profile_default/ 126 | ipython_config.py 127 | 128 | # pyenv 129 | .python-version 130 | 131 | # pipenv 132 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 133 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 134 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 135 | # install all needed dependencies. 136 | #Pipfile.lock 137 | 138 | # celery beat schedule file 139 | celerybeat-schedule 140 | 141 | # SageMath parsed files 142 | *.sage.py 143 | 144 | # Environments 145 | .env 146 | .venv 147 | env/ 148 | venv/ 149 | ENV/ 150 | env.bak/ 151 | venv.bak/ 152 | 153 | # Spyder project settings 154 | .spyderproject 155 | .spyproject 156 | 157 | # Rope project settings 158 | .ropeproject 159 | 160 | # mkdocs documentation 161 | /site 162 | 163 | # mypy 164 | .mypy_cache/ 165 | .dmypy.json 166 | dmypy.json 167 | 168 | # Pyre type checker 169 | .pyre/ 170 | 171 | ### VirtualEnv ### 172 | # Virtualenv 173 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 174 | [Bb]in 175 | [Ii]nclude 176 | [Ll]ib 177 | [Ll]ib64 178 | [Ll]ocal 179 | [Ss]cripts 180 | pyvenv.cfg 181 | pip-selfcheck.json 182 | 183 | # End of https://www.gitignore.io/api/git,python,virtualenv 184 | .vscode/ 185 | 186 | .vim/coc-settings.json 187 | 188 | # Poetry stuff 189 | dist/ 190 | poetry.lock 191 | 192 | # Nano 193 | *.swp 194 | 195 | # PyCharm 196 | .idea/ 197 | 198 | ciphey/LanguageChecker/create\?max_size=60&spelling=US&spelling=GBs&max_variant=2&diacritic=both&special=hacker&special=roman-numerals&download=wordlist&encoding=utf-8&format=inline 199 | 200 | ciphey/LanguageChecker/create\?max_size=80&spelling=US&spelling=GBs&spelling=GBz&spelling=CA&spelling=AU&max_variant=2&diacritic=both&special=hacker&special=roman-numerals&download=wordlist&encoding=utf-8&format=inline 201 | 202 | ciphey/LanguageChecker/aspell.txt 203 | dictionary.txt 204 | aspell.txt 205 | 206 | ciphey.spec 207 | 208 | ciphey/__main__.spec 209 | 210 | __main__.spec 211 | 212 | .entry_point.spec/entry_point.spec 213 | 214 | BEANOS INVADES THE FORTNITE ITEM SHOP AT 8_00 PM.EXE-uG0WJcr-cuI.f299.mp4.part 215 | 216 | run.yml 217 | 218 | tests/interface.rst 219 | 220 | 221 | # Test Generator 222 | test_main_generated.py 223 | 224 | run.yml 225 | 226 | tests/interface.rst 227 | 228 | test.py 229 | 230 | # Mac OS Files 231 | .DS_Store 232 | .AppleDouble 233 | .LSOverride 234 | Icon 235 | ._* 236 | -------------------------------------------------------------------------------- /translations/it/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 |

2 | Traduzioni
3 | 🇩🇪 DE 4 | 🇬🇧 EN 5 | 🇭🇺 HU 6 | 🇮🇩 ID 7 | 🇮🇹 IT 8 | 🇳🇱 NL 9 | 🇧🇷 PT-BR 10 | 🇷🇺 RU 11 | 🇨🇳 ZH 12 |

13 | 14 | # Codice di condotta 15 | 16 | ## Il nostro impegno 17 | 18 | Nell'interesse di promuovere un ambiente aperto e accogliente, noi, in qualità di collaboratori e manutentori, ci impegniamo a rendere la partecipazione al nostro progetto e alla nostra comunità un'esperienza senza molestie per tutti, indipendentemente dall'età, dalle dimensioni del corpo, dalla disabilità, dall'etnia, dalle caratteristiche del sesso, dall'identità e dall'espressione di genere, dal livello di esperienza, dall'istruzione, dallo status socio-economico, dalla nazionalità, dall'aspetto personale, dalla razza, dalla religione o dall'identità e dall'orientamento sessuale. 19 | 20 | ## I nostri standard 21 | 22 | Esempi di comportamenti che contribuiscono a creare un ambiente positivo includono: 23 | 24 | - Uso di un linguaggio accogliente e inclusivo 25 | - Essere rispettosi dei diversi punti di vista e delle diverse esperienze 26 | - Accettare con tolleranza le critiche costruttive 27 | - Concentrandosi su ciò che è meglio per la comunità 28 | - Mostrare empatia verso gli altri membri della comunità 29 | 30 | Tra gli esempi di comportamento da parte dei partecipanti ritenuti inaccettabili vi sono i seguenti: 31 | 32 | - L'uso di un linguaggio sessualizzato o di immagini sessualizzate e di attenzioni sessuali indesiderate o progressi 33 | - Trolling, commenti offensivi/derogatori e attacchi personali o politici 34 | - Molestie pubbliche o private 35 | - Pubblicazione di informazioni private altrui, come ad esempio informazioni fisiche o elettroniche 36 | indirizzo, senza autorizzazione esplicita 37 | - Altri comportamenti che potrebbero ragionevolmente essere considerati inappropriati in un 38 | ambiente professionale 39 | 40 | ## Le nostre responsabilità 41 | 42 | I responsabili del progetto hanno la responsabilità di chiarire gli standard di accettabilità del comportamento e ci si aspetta che intraprendano azioni correttive appropriate ed eque in risposta a qualsiasi caso di comportamento considerato inaccettabile. 43 | 44 | I responsabili del progetto hanno il diritto e la responsabilità di rimuovere, modificare o 45 | rifiutare commenti, impegni, codice, modifiche alla wiki, problemi e altri contributi che non sono allineati al presente Codice di Condotta, o di bloccare temporaneamente o permanentemente a qualsiasi contribuente di partecipare per altri comportamenti ritenuti inappropriati, minacciosi, offensivi o dannosi. 46 | 47 | ## Portata 48 | 49 | Il presente Codice di Condotta si applica sia all'interno degli spazi di progetto che negli spazi pubblici 50 | quando un individuo rappresenta il progetto o la sua comunità. Esempi di rappresentare un progetto o una comunità includono l'utilizzo di una e-mail ufficiale del progetto indirizzo, invio tramite un account ufficiale sui social media o in qualità di incaricato rappresentante ad un evento online o offline. La rappresentanza di un progetto può essere ulteriormente definita e chiarita dai responsabili del progetto. 51 | 52 | ## Applicazione 53 | 54 | I casi di comportamento abusivo, molesto o comunque inaccettabile possono essere segnalati contattando il team del progetto brandon_skerrit. Tutti 55 | I reclami saranno esaminati e analizzati e daranno luogo a una risposta che ritenuta necessaria e adeguatoa alle circostanze. Il team del progetto è obbligato a mantenere la riservatezza nei confronti del segnalante di un incidente. 56 | Ulteriori dettagli sulle politiche di applicazione specifiche possono essere pubblicati separatamente. 57 | 58 | I responsabili del progetto che non seguono o non fanno seguire il qui presente Codice di condotta in buona fede puossono subire ripercussioni temporanee o permanenti, come determinato da altri membri incaricati della gestione del progetto. 59 | 60 | ## Attribuzione 61 | 62 | Il presente Codice di Condotta è adattato dal [Contributor Covenant][homepage], versione 1.4, 63 | disponibile all'indirizzo 64 | 65 | [homepage]: https://www.contributor-covenant.org 66 | 67 | Per le risposte alle domande più comuni su questo codice di condotta, vedere 68 | 69 | -------------------------------------------------------------------------------- /ciphey/basemods/Crackers/hash.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is Hashbuster but slightly modified to work with Ciphey. 3 | Why reinvent the wheel? 4 | Changes (that I can remember) 5 | * timeout set, as hashbuster took AGES before timeout was set. 6 | https://github.com/s0md3v/Hash-Buster 7 | """ 8 | 9 | import re 10 | from typing import Dict, List, Optional 11 | 12 | import requests 13 | import logging 14 | from rich.logging import RichHandler 15 | 16 | from ciphey.iface import Config, Cracker, CrackInfo, CrackResult, ParamSpec, T, registry 17 | 18 | thread_count = 4 19 | 20 | 21 | def alpha(ctext, hashtype): 22 | return None 23 | 24 | 25 | def beta(ctext, hashtype): 26 | try: 27 | response = requests.get( 28 | "https://hashtoolkit.com/reverse-hash/?hash=", ctext, timeout=5 29 | ).text 30 | except requests.exceptions.ReadTimeout as e: 31 | logging.info(f"Beta failed timeout {e}") 32 | match = re.search(r'/generate-hash/?text=.*?"', response) 33 | if match: 34 | return match.group(1) 35 | return None 36 | 37 | 38 | def gamma(ctext, hashtype): 39 | try: 40 | response = requests.get( 41 | "https://www.nitrxgen.net/md5db/" + ctext, timeout=5 42 | ).text 43 | except requests.exceptions.ReadTimeout as e: 44 | logging.info(f"Gamma failed with {e}") 45 | if response: 46 | return response 47 | else: 48 | return None 49 | 50 | 51 | def delta(ctext, hashtype): 52 | return None 53 | 54 | 55 | def theta(ctext, hashtype): 56 | try: 57 | response = requests.get( 58 | "https://md5decrypt.net/Api/api.php?hash=%s&hash_type=%s&email=deanna_abshire@proxymail.eu&code=1152464b80a61728" 59 | % (ctext, hashtype), 60 | timeout=5, 61 | ).text 62 | except requests.exceptions.ReadTimeout as e: 63 | logging.info(f"Gamma failed with {e}") 64 | if len(response) != 0: 65 | return response 66 | else: 67 | return None 68 | 69 | 70 | md5 = [gamma, alpha, beta, theta, delta] 71 | sha1 = [alpha, beta, theta, delta] 72 | sha256 = [alpha, beta, theta] 73 | sha384 = [alpha, beta, theta] 74 | sha512 = [alpha, beta, theta] 75 | 76 | 77 | result = {} 78 | 79 | 80 | def crack(ctext): 81 | raise "Error Crack is called" 82 | 83 | 84 | def threaded(ctext): 85 | resp = crack(ctext) 86 | if resp: 87 | print(ctext + " : " + resp) 88 | result[ctext] = resp 89 | 90 | 91 | @registry.register 92 | class HashBuster(Cracker[str]): 93 | @staticmethod 94 | def getTarget() -> str: 95 | return "hash" 96 | 97 | @staticmethod 98 | def getParams() -> Optional[Dict[str, ParamSpec]]: 99 | return None 100 | 101 | @staticmethod 102 | def priority() -> float: 103 | return 0.05 104 | 105 | def getInfo(self, ctext: T) -> CrackInfo: 106 | # TODO calculate these properly 107 | return CrackInfo( 108 | success_likelihood=0.5, 109 | success_runtime=5, 110 | failure_runtime=5, 111 | ) 112 | 113 | def attemptCrack(self, ctext: T) -> List[CrackResult]: 114 | logging.info("Starting to crack hashes") 115 | result = False 116 | 117 | candidates = [] 118 | if len(ctext) == 32: 119 | for api in md5: 120 | r = api(ctext, "md5") 121 | if result is not None or r is not None: 122 | logging.debug("MD5 returns True {r}") 123 | candidates.append(result, "MD5") 124 | elif len(ctext) == 40: 125 | for api in sha1: 126 | r = api(ctext, "sha1") 127 | if result is not None and r is not None: 128 | logging.debug("sha1 returns true") 129 | candidates.append(result, "SHA1") 130 | elif len(ctext) == 64: 131 | for api in sha256: 132 | r = api(ctext, "sha256") 133 | if result is not None and r is not None: 134 | logging.debug("sha256 returns true") 135 | candidates.append(result, "SHA256") 136 | elif len(ctext) == 96: 137 | for api in sha384: 138 | r = api(ctext, "sha384") 139 | if result is not None and r is not None: 140 | logging.debug("sha384 returns true") 141 | candidates.append(result, "SHA384") 142 | elif len(ctext) == 128: 143 | for api in sha512: 144 | r = api(ctext, "sha512") 145 | if result is not None and r is not None: 146 | logging.debug("sha512 returns true") 147 | candidates.append(result, "SHA512") 148 | 149 | # TODO what the fuck is this code? 150 | logging.debug(f"Hash buster returning {result}") 151 | # TODO add to 5.1 make this return multiple possible candidates 152 | return [CrackResult(value=candidates[0][0], misc_info=candidates[1][1])] 153 | 154 | def __init__(self, config: Config): 155 | super().__init__(config) 156 | --------------------------------------------------------------------------------