├── .github └── workflows │ └── build.yml ├── .gitignore ├── FlipperNested ├── __init__.py ├── __main__.py ├── bridge.py ├── cli.py ├── main.py └── proto │ ├── __init__.py │ ├── flipper.proto │ ├── flipper_pb2.py │ ├── storage.proto │ └── storage_pb2.py ├── FlipperNestedRecoveryGUI_2.0.py ├── FlipperNestedRecoveryGUI_2.0_mac.py ├── HardNestedSolver ├── bucketsort.c ├── bucketsort.h ├── cmdhfmfhard.c ├── cmdhfmfhard.h ├── crapto1.c ├── crapto1.h ├── crypto1.c ├── hardnested │ ├── hardnested_benchmark_data.h │ ├── hardnested_bf_core.c │ ├── hardnested_bf_core.h │ ├── hardnested_bitarray_core.c │ ├── hardnested_bitarray_core.h │ ├── hardnested_bruteforce.c │ ├── hardnested_bruteforce.h │ ├── tables.c │ └── tables.h ├── library.c ├── library.h ├── parity.h ├── pm3 │ ├── ansi.h │ ├── common.h │ ├── commonutil.c │ ├── commonutil.h │ ├── emojis.h │ ├── emojis_alt.h │ ├── ui.c │ ├── ui.h │ ├── util.c │ ├── util.h │ ├── util_posix.c │ └── util_posix.h └── python.c ├── LICENSE.md ├── MANIFEST.in ├── NestedSolver ├── bucketsort.c ├── bucketsort.h ├── crapto1.c ├── crapto1.h ├── crypto1.c ├── library.c ├── library.h ├── parity.h ├── progress.c ├── progress.h └── python.c ├── README.md ├── README_CN.md ├── README_TW.md ├── hacker.icns ├── hacker.ico ├── setup.py └── tests ├── .clean_nonces ├── test_calculate.py ├── test_import.py └── test_parse.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_wheels: 7 | name: Build wheels on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macOS-latest, windows-latest] 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Set up QEMU 17 | if: runner.os == 'Linux' 18 | uses: docker/setup-qemu-action@v2 19 | with: 20 | platforms: all 21 | 22 | - name: Install Microsoft Visual C++ 2010 Redistributable Package 23 | if: runner.os == 'Windows' 24 | run: | 25 | curl -L -o vcredist.exe https://download.microsoft.com/download/1/6/5/165255E7-1014-4D0A-B094-B6A430A6BFFC/vcredist_x64.exe 26 | Start-Process -FilePath vcredist.exe -ArgumentList '/Q' -Wait -PassThru 27 | 28 | - name: Set up pthreads 29 | if: runner.os == 'Windows' 30 | run: | 31 | curl -O https://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip 32 | 7z x -y pthreads-w32-2-9-1-release.zip -opthreads 33 | robocopy pthreads\Pre-built.2\dll\x64 build\pthreads /COPYALL /E || true 34 | robocopy pthreads\Pre-built.2\include build\pthreads /COPYALL /E || true 35 | robocopy pthreads\Pre-built.2\lib\x64 build\pthreads /COPYALL /E || true 36 | 37 | - name: Set up lzma 38 | if: runner.os == 'Windows' 39 | run: | 40 | curl -O -L https://github.com/ShiftMediaProject/liblzma/releases/download/v5.4.1/liblzma_v5.4.1_msvc17.zip 41 | 7z x -y liblzma_v5.4.1_msvc17.zip -oliblzma 42 | robocopy liblzma\bin\x64 build\lzma /COPYALL /E || true 43 | robocopy liblzma\include build\lzma /COPYALL /E || true 44 | robocopy liblzma\lib\x64 build\lzma /COPYALL /E || true 45 | 46 | - name: Build wheels 47 | uses: pypa/cibuildwheel@v2.17.0 48 | env: 49 | CIBW_ARCHS_MACOS: "x86_64 arm64" 50 | CIBW_ARCHS_LINUX: "x86_64 aarch64" 51 | CIBW_ARCHS_WINDOWS: "AMD64" 52 | CIBW_TEST_REQUIRES: pytest 53 | CIBW_TEST_COMMAND: "pytest {project}/tests" 54 | CIBW_TEST_SKIP: "*-*linux_aarch64 *-macosx_arm64" 55 | CIBW_BEFORE_BUILD_WINDOWS: "pip install delvewheel" 56 | CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path build\\pthreads;build\\lzma -w {dest_dir} {wheel}" 57 | # CIBW_BEFORE_ALL_LINUX: "yum install -y xz xz-devel || apk add xz-dev" 58 | CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*" 59 | # Use manylinux_2_28 image 60 | CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 61 | CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 62 | # Robust package installation 63 | CIBW_BEFORE_ALL_LINUX: | 64 | if command -v dnf; then \ 65 | dnf install -y xz xz-devel; \ 66 | elif command -v yum; then \ 67 | yum install -y xz xz-devel; \ 68 | elif command -v apt-get; then \ 69 | apt-get update && apt-get install -y xz-utils liblzma-dev; \ 70 | elif command -v apk; then \ 71 | apk add xz-dev; \ 72 | else \ 73 | echo "No known package manager found"; \ 74 | exit 1; \ 75 | fi 76 | # Install xz on macOS 77 | CIBW_BEFORE_ALL_MACOS: brew install xz 78 | 79 | - uses: actions/upload-artifact@v3 80 | with: 81 | path: ./wheelhouse/*.whl 82 | 83 | build_sdist: 84 | name: Build source distribution 85 | runs-on: ubuntu-latest 86 | steps: 87 | - uses: actions/checkout@v4 88 | 89 | - name: Build sdist 90 | run: pipx run build --sdist 91 | 92 | - uses: actions/upload-artifact@v3 93 | with: 94 | path: dist/*.tar.gz -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | bin/ 10 | build/ 11 | develop-eggs/ 12 | dist/ 13 | eggs/ 14 | lib/ 15 | lib64/ 16 | parts/ 17 | sdist/ 18 | var/ 19 | *.egg-info/ 20 | .installed.cfg 21 | *.egg 22 | wheelhouse/ 23 | 24 | # Installer logs 25 | pip-log.txt 26 | pip-delete-this-directory.txt 27 | 28 | # Unit test / coverage reports 29 | .tox/ 30 | .coverage 31 | .cache 32 | nosetests.xml 33 | coverage.xml 34 | .pytest_cache 35 | 36 | # Flipper Nested files 37 | *.nonces 38 | *.keys -------------------------------------------------------------------------------- /FlipperNested/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldip/FlipperNestedRecovery-GUI/79aff2118748f7e7538cbe5b40da467b8266d76b/FlipperNested/__init__.py -------------------------------------------------------------------------------- /FlipperNested/__main__.py: -------------------------------------------------------------------------------- 1 | from FlipperNested.cli import main 2 | import multiprocessing 3 | 4 | if __name__ == "__main__": 5 | multiprocessing.freeze_support() 6 | main() 7 | -------------------------------------------------------------------------------- /FlipperNested/bridge.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import serial 3 | import serial.tools.list_ports 4 | from google.protobuf.internal.encoder import _VarintBytes 5 | from google.protobuf.json_format import MessageToDict 6 | 7 | import FlipperNested.proto.flipper_pb2 as flipper_pb2 8 | import FlipperNested.proto.storage_pb2 as storage_pb2 9 | 10 | 11 | class FlipperBridge: 12 | def __init__(self, port: str = None): 13 | self.port = port 14 | self.device_info = None 15 | self._serial = None 16 | self.command_id = 0 17 | self.connect() 18 | 19 | def connect(self): 20 | self._serial = self.open_port() 21 | self.start_rpc_session() 22 | 23 | def open_port(self): 24 | if not self.port: 25 | self.port = self.get_port() 26 | if not self.port: 27 | raise ConnectionError("Flipper is missing") 28 | flipper = serial.Serial(self.port, timeout=1) 29 | flipper.flushOutput() 30 | flipper.flushInput() 31 | 32 | return flipper 33 | 34 | def start_rpc_session(self) -> None: 35 | self._serial.read_until(b">: ") 36 | self._serial.write(b"start_rpc_session\r") 37 | self._serial.read_until(b"\n") 38 | 39 | def get_port(self): 40 | ports = serial.tools.list_ports.comports() 41 | potential_ports = [] 42 | for port, desc, hwid in ports: 43 | a = hwid.split() 44 | if "VID:PID=0483:5740" in a: 45 | return port 46 | elif hwid == "n/a": 47 | potential_ports.append(port) 48 | for port in potential_ports: 49 | if self.check_port(port): 50 | return port 51 | if len(potential_ports): 52 | print("[Error] Can't guess Flipper Zero serial port. Fallback to manual mode") 53 | print("Make sure Flipper Zero is connected and not used by any other software") 54 | for port in potential_ports: 55 | if input("Is {} your Flipper Zero serial port? [y/n] > ".format(port)).lower() == "y": 56 | return port 57 | 58 | @staticmethod 59 | def check_port(port): 60 | try: 61 | flipper = serial.Serial(port, timeout=1) 62 | flipper.flushOutput() 63 | flipper.flushInput() 64 | if b"Flipper Zero Command Line Interface!" in flipper.read_until(b">: "): 65 | return True 66 | except: 67 | pass 68 | 69 | def _read_varint_32(self) -> int: 70 | MASK = (1 << 32) - 1 71 | 72 | result = 0 73 | shift = 0 74 | while 1: 75 | b = int.from_bytes(self._serial.read(size=1), byteorder="little", signed=False) 76 | result |= (b & 0x7F) << shift 77 | 78 | if not b & 0x80: 79 | result &= MASK 80 | result = int(result) 81 | return result 82 | shift += 7 83 | 84 | def get_command_id(self) -> int: 85 | self.command_id += 1 86 | result = self.command_id 87 | return result 88 | 89 | def _rpc_send(self, cmd_data, cmd_name, command_id=None, has_next=False) -> None: 90 | flipper_message = flipper_pb2.Main() 91 | flipper_message.command_id = command_id 92 | if not command_id: 93 | flipper_message.command_id = self.get_command_id() 94 | flipper_message.has_next = has_next 95 | 96 | flipper_message.command_status = flipper_pb2.CommandStatus.Value("OK") 97 | getattr(flipper_message, cmd_name).CopyFrom(cmd_data) 98 | data = bytearray(_VarintBytes(flipper_message.ByteSize()) + flipper_message.SerializeToString()) 99 | 100 | self._serial.write(data) 101 | 102 | def _rpc_read_answer(self): 103 | while True: 104 | data = self._rpc_read_any() 105 | if data.command_id == self.command_id: 106 | break 107 | return data 108 | 109 | def _rpc_send_and_read_answer(self, cmd_data, cmd_name, has_next=False): 110 | self._rpc_send(cmd_data, cmd_name, has_next) 111 | return self._rpc_read_answer() 112 | 113 | def _rpc_read_any(self): 114 | length = self._read_varint_32() 115 | data = flipper_pb2.Main() 116 | data.ParseFromString(self._serial.read(size=length)) 117 | return data 118 | 119 | def get_files(self, path="/ext") -> list: 120 | storage_response = [] 121 | cmd_data = storage_pb2.ListRequest() 122 | 123 | cmd_data.path = path 124 | rep_data = self._rpc_send_and_read_answer(cmd_data, "storage_list_request") 125 | 126 | storage_response.extend(self._message_to_dict(rep_data.storage_list_response)["file"]) 127 | 128 | while rep_data.has_next: 129 | rep_data = self._rpc_read_answer() 130 | storage_response.extend(self._message_to_dict(rep_data.storage_list_response)["file"]) 131 | 132 | return storage_response 133 | 134 | @staticmethod 135 | def _message_to_dict(message): 136 | if 'including_default_value_fields' in inspect.signature(MessageToDict).parameters: 137 | return MessageToDict(message=message, including_default_value_fields=True) 138 | else: 139 | return MessageToDict(message=message, always_print_fields_with_no_presence=True) 140 | 141 | def file_read(self, path=None): 142 | storage_response = [] 143 | cmd_data = storage_pb2.ReadRequest() 144 | cmd_data.path = path 145 | 146 | rep_data = self._rpc_send_and_read_answer(cmd_data, "storage_read_request") 147 | 148 | storage_response.append(rep_data.storage_read_response.file.data) 149 | 150 | while rep_data.has_next: 151 | rep_data = self._rpc_read_answer() 152 | storage_response.append(rep_data.storage_read_response.file.data) 153 | 154 | return b"".join(storage_response) 155 | 156 | def file_write(self, path=None, data=""): 157 | cmd_data = storage_pb2.WriteRequest() 158 | cmd_data.path = path 159 | 160 | if isinstance(data, str): 161 | data = data.encode() 162 | 163 | chunk_size = 512 164 | data_len = len(data) 165 | command_id = self.get_command_id() 166 | for chunk in range(0, data_len, chunk_size): 167 | 168 | chunk_data = data[chunk: chunk + chunk_size] 169 | 170 | cmd_data.file.data = chunk_data 171 | 172 | if (chunk + chunk_size) < data_len: 173 | self._rpc_send(cmd_data, "storage_write_request", has_next=True, command_id=command_id, ) 174 | else: 175 | self._rpc_send(cmd_data, "storage_write_request", has_next=False, command_id=command_id, ) 176 | break 177 | 178 | self._rpc_read_answer() 179 | 180 | def file_delete(self, path=None): 181 | cmd_data = storage_pb2.DeleteRequest() 182 | cmd_data.path = path 183 | cmd_data.recursive = True 184 | 185 | self._rpc_send_and_read_answer(cmd_data, "storage_delete_request") 186 | 187 | def mkdir(self, path="/ext"): 188 | cmd_data = storage_pb2.MkdirRequest() 189 | cmd_data.path = path 190 | 191 | self._rpc_send_and_read_answer(cmd_data, "storage_mkdir_request") 192 | 193 | def file_rename(self, old, new): 194 | cmd_data = storage_pb2.RenameRequest() 195 | cmd_data.old_path = old 196 | cmd_data.new_path = new 197 | 198 | self._rpc_send_and_read_answer(cmd_data, "storage_rename_request") 199 | -------------------------------------------------------------------------------- /FlipperNested/cli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from FlipperNested.main import FlipperNested 4 | 5 | 6 | def main(): 7 | parser = argparse.ArgumentParser(description="Recover keys after Nested attack") 8 | parser.add_argument("--uid", type=str, help="Recover only for this UID", default="") 9 | parser.add_argument("--port", type=str, help="Port to connect", default="") 10 | parser.add_argument("--progress", action="store_true", help="Show key recovery progress bar") 11 | parser.add_argument("--save", action="store_true", help="Debug: Save nonces/keys from Flipper") 12 | parser.add_argument("--preserve", action="store_true", help="Debug: Don't remove nonces after recovery") 13 | parser.add_argument("--file", type=argparse.FileType("r"), help="Debug: Recover keys from local .nonces file") 14 | parser.set_defaults(debug=False) 15 | args = parser.parse_args() 16 | flipper = FlipperNested() 17 | flipper.run(args) 18 | -------------------------------------------------------------------------------- /FlipperNested/main.py: -------------------------------------------------------------------------------- 1 | import _queue 2 | import os.path 3 | import re 4 | import tempfile 5 | from multiprocessing import Manager, Process 6 | 7 | from FlipperNested.bridge import FlipperBridge 8 | 9 | 10 | def wrapper(queue, *args): 11 | queue.put(FlipperNested.calculate_keys(*args)) 12 | 13 | 14 | def wrapper_hard(queue, *args): 15 | queue.put(FlipperNested.calculate_keys_hard(*args)) 16 | 17 | 18 | class FlipperNested: 19 | VERSION = 3 20 | FILE_TYPES = ["Flipper Nested Nonce Manifest File", "Flipper Nested Nonces File"] 21 | DEPTH_VALUES = {1: 25, 2: 50, 3: 100} 22 | FLIPPER_PATH = "/ext/nfc/.nested/" 23 | LEGACY_PATH = "/ext/nfc/nested/" 24 | 25 | def __init__(self): 26 | self.connection = None 27 | self.filename = None 28 | self.nonces = None 29 | self.found_keys = None 30 | self.bruteforce_distance = [0, 0] 31 | self.progress_bar = False 32 | self.save = False 33 | self.preserve = False 34 | self.uid = "" 35 | 36 | def run(self, args=None): 37 | if args: 38 | self.progress_bar = args.progress 39 | self.save = args.save 40 | self.preserve = args.preserve 41 | self.uid = args.uid 42 | if not args or args and not args.file: 43 | self.connection = FlipperBridge(args.port) 44 | self.extract_nonces_from_flipper() 45 | else: 46 | self.extract_nonces_from_file(args.file) 47 | 48 | def parse_file(self, contents): 49 | self.nonces = {"A": {}, "B": {}} 50 | self.found_keys = {"A": {}, "B": {}} 51 | self.bruteforce_distance = [0, 0] 52 | lines = contents.splitlines() 53 | type_string = lines.pop(0) 54 | if "Filetype" not in type_string: 55 | print("[!] No type in", self.filename) 56 | return False 57 | file_type = type_string.split(": ")[1] 58 | if file_type.strip() not in self.FILE_TYPES: 59 | print("[!] Invalid file type in", self.filename) 60 | return False 61 | version_string = lines.pop(0) 62 | if "Version" not in version_string: 63 | print("[!] No version info in", self.filename) 64 | return False 65 | file_version = int(version_string.split(": ")[1]) 66 | if file_version != self.VERSION: 67 | print("[!!!] Invalid version for", self.filename) 68 | print("[!] You should update " + ("app" if file_version < self.VERSION else "recovery script")) 69 | return False 70 | lines.pop(0) # remove note 71 | if file_type == "Flipper Nested Nonce Manifest File": 72 | if "HardNested" in contents: 73 | for line in lines: 74 | values = self.parse_line(line) 75 | sec, key_type = values[-2:] 76 | if sec not in self.nonces[key_type].keys(): 77 | self.nonces[key_type][sec] = [] 78 | file = tempfile.NamedTemporaryFile(delete=False) 79 | nonces_filename = values[1].rsplit("/", 1)[1] 80 | if self.connection: 81 | value = self.connection.file_read(values[1]) 82 | elif os.path.dirname(self.filename) and os.path.isfile( 83 | os.path.dirname(self.filename) + "/" + nonces_filename): 84 | # file in same directory as input file 85 | value = open(os.path.dirname(self.filename) + "/" + nonces_filename, "rb").read() 86 | elif os.path.dirname(self.filename) and os.path.isfile( 87 | os.path.dirname(self.filename) + "/" + self.filename.rsplit(".", 1)[ 88 | 0] + "/" + nonces_filename): 89 | # copied from .nested directory with UID 90 | value = open(os.path.dirname(self.filename) + "/" + self.filename.rsplit(".", 1)[ 91 | 0] + "/" + nonces_filename, "rb").read() 92 | elif os.path.isfile(self.filename.rsplit(".", 1)[ 93 | 0] + "/" + nonces_filename): 94 | # copied from .nested directory with UID, from current directory 95 | value = open(self.filename.rsplit(".", 1)[ 96 | 0] + "/" + nonces_filename, "rb").read() 97 | elif os.path.isfile(nonces_filename): 98 | # file in current directory (--save) 99 | value = open(nonces_filename, "rb").read() 100 | else: 101 | print("[!] Missing {} file and Flipper Zero isn't connected".format(nonces_filename)) 102 | print("[?] If you are trying to recover from Hard Nested offline, you should copy this file") 103 | return False 104 | open(file.name, "wb+").write(b"\n".join(value.split(b"\n")[4:])) 105 | if self.save: 106 | open(nonces_filename, "wb+").write(value) 107 | values[1] = file.name 108 | self.nonces[key_type][sec].append(values) 109 | return len(self.nonces["A"]) + len(self.nonces["B"]) > 0 110 | elif "Nested: " in contents: 111 | if "Nested: Delay" in contents: 112 | print("[!] Nested attack with delay was used, will try more PRNG values (will take more time)") 113 | result = re.search(r"Nested: Delay [0-9]*, distance ([0-9]*)", contents.strip()) 114 | print("[?] Please select depth of check") 115 | print("[1] Fast: +-25 values") 116 | print("[2] Normal: +-50 values") 117 | print("[3] Full: +-100 values [Recommended, ~2Gb RAM usage]") 118 | print("[-] Custom [..any other value..]") 119 | depth = int(input("[1-3/custom] > ")) 120 | distance = int(result.groups()[0]) 121 | if depth < 1: 122 | print("[!] Invalid input, using Normal depth") 123 | depth = 2 124 | if depth < 4: 125 | self.bruteforce_distance = [distance - self.DEPTH_VALUES[depth], 126 | distance + self.DEPTH_VALUES[depth]] 127 | else: 128 | self.bruteforce_distance = [distance - depth, distance + depth] 129 | lines.pop() 130 | for line in lines: 131 | values = self.parse_line(line) 132 | sec, key_type = values[-2:] 133 | if sec not in self.nonces[key_type].keys(): 134 | self.nonces[key_type][sec] = [] 135 | self.nonces[key_type][sec].append(values) 136 | return len(self.nonces["A"]) + len(self.nonces["B"]) > 0 137 | else: 138 | print("[!] No nonces found") 139 | return False 140 | elif file_type == "Flipper Nested Nonces File": 141 | cuid_string = lines.pop(0) 142 | if "cuid 0x" not in cuid_string: 143 | print("[!] No cuid in", self.filename) 144 | return False 145 | file = tempfile.NamedTemporaryFile(delete=False) 146 | values = self.parse_line(cuid_string) 147 | sec, key_type = values[-2:] 148 | if sec not in self.nonces[key_type].keys(): 149 | self.nonces[key_type][sec] = [] 150 | open(file.name, "w+").write("\n".join(lines)) 151 | values.insert(1, file.name) 152 | self.nonces[key_type][sec].append(values) 153 | return len(self.nonces["A"]) + len(self.nonces["B"]) > 0 154 | 155 | def extract_nonces_from_flipper(self): 156 | self.check_legacy_folder() 157 | for file in self.connection.get_files(self.FLIPPER_PATH[:-1]): 158 | if file["name"].endswith(".nonces"): 159 | if self.uid: 160 | if file["name"].split(".")[0] != self.uid.upper(): 161 | continue 162 | self.filename = file["name"] 163 | print("[?] Checking", file["name"]) 164 | contents = self.connection.file_read(self.FLIPPER_PATH + file["name"]).decode() 165 | if not self.parse_file(contents): 166 | print("[!] Failed to parse", file["name"]) 167 | continue 168 | if self.save: 169 | open(file["name"], "w+").write(contents) 170 | print("[?] Saved nonces to", file["name"]) 171 | stop = self.recover_keys() 172 | self.save_keys_to_flipper() 173 | if stop: 174 | break 175 | 176 | def extract_nonces_from_file(self, file): 177 | self.filename = file.name 178 | if not self.parse_file(file.read()): 179 | print("[!] Failed to parse", self.filename) 180 | return 181 | self.recover_keys() 182 | self.save_keys_to_file() 183 | 184 | def check_legacy_folder(self): 185 | files = self.connection.get_files(self.LEGACY_PATH[:-1]) 186 | if len(files): 187 | print("[!!!] Found files in legacy folder", self.LEGACY_PATH) 188 | self.connection.mkdir(self.FLIPPER_PATH[:-1]) 189 | for file in files: 190 | self.connection.file_rename(self.LEGACY_PATH + file["name"], self.FLIPPER_PATH + file["name"]) 191 | print("[!] Moved {} files to new directory".format(len(files))) 192 | print("[!] You MUST update app to version 1.1.0 or you won't be able to check keys") 193 | self.connection.file_delete(self.LEGACY_PATH[:-1]) 194 | 195 | def recover_keys(self): 196 | for key_type in self.nonces.keys(): 197 | for sector in self.nonces[key_type].keys(): 198 | for info in self.nonces[key_type][sector]: 199 | print("Recovering key type", key_type + ", sector", sector) 200 | m = Manager() 201 | q = m.Queue() 202 | value = info[:-2] 203 | value.insert(0, q) 204 | 205 | if len(value) == 3: 206 | p = Process(target=wrapper_hard, args=value) 207 | else: 208 | value.append(self.bruteforce_distance) 209 | value.append(self.progress_bar) 210 | p = Process(target=wrapper, args=value) 211 | 212 | p.start() 213 | 214 | try: 215 | p.join() 216 | except KeyboardInterrupt: 217 | print("Stopping...") 218 | p.kill() 219 | return True 220 | 221 | try: 222 | keys = q.get(timeout=1).split(";") 223 | except _queue.Empty: 224 | print("[!!!] Something went VERY wrong in key recovery.\nYou MUST report this to developer!") 225 | return 226 | keys.pop() 227 | 228 | print(f"Found {str(len(keys))} key(s):", keys) 229 | 230 | if keys: 231 | self.found_keys[key_type][sector] = keys 232 | break 233 | elif info == self.nonces[key_type][sector][-1]: 234 | print("[!] Failed to find keys for this sector, try running Nested attack again") 235 | 236 | def save_keys_to_string(self): 237 | output = "" 238 | for key_type in self.found_keys.keys(): 239 | for sector in self.found_keys[key_type].keys(): 240 | for key in self.found_keys[key_type][sector]: 241 | output += f"Key {key_type} sector {str(sector).zfill(2)}: " + " ".join( 242 | [key.upper()[i:i + 2] for i in range(0, len(key), 2)]) + "\n" 243 | 244 | keys = output.count("Key") 245 | if keys: 246 | print("[+] Found potential {} keys, use \"Check found keys\" in app".format(keys)) 247 | return output.strip() 248 | 249 | def save_keys_to_file(self): 250 | output = self.save_keys_to_string() 251 | if not output: 252 | print("[-] No keys found!") 253 | return 254 | filename = self.filename + ".keys" 255 | open(filename, "w+").write(output) 256 | print("[?] Saved keys to", filename) 257 | 258 | def save_keys_to_flipper(self): 259 | output = self.save_keys_to_string() 260 | if not output: 261 | print("[-] No keys found!") 262 | return 263 | filename = self.filename.replace("nonces", "keys") 264 | if self.save: 265 | open(filename, "w+").write(output) 266 | print("[?] Saved keys to", filename) 267 | try: 268 | self.connection.file_write(self.FLIPPER_PATH + filename, output.encode()) 269 | if not self.preserve: 270 | self.connection.file_delete(self.FLIPPER_PATH + self.filename) 271 | except: 272 | if not self.save: 273 | open(filename, "w+").write(output) 274 | print("[!] Lost connection to Flipper!") 275 | print("[?] Saved keys to", filename) 276 | 277 | @staticmethod 278 | def parse_line(line): 279 | if "HardNested" in line: 280 | result = re.search( 281 | r"HardNested: Key ([A-B]) cuid (0x[0-9a-f]*) file (\S+) sec (\d{1,2})", 282 | line.strip()) 283 | elif "Nested" in line: 284 | result = re.search( 285 | r"Nested: Key ([A-B]) cuid (0x[0-9a-f]*) nt0 (0x[0-9a-f]*) ks0 (0x[0-9a-f]*) par0 ([0-9a-f]*) nt1 (0x[0-9a-f]*) ks1 (0x[0-9a-f]*) par1 ([0-9a-f]*) sec (\d{1,2})", 286 | line.strip()) 287 | else: 288 | result = re.search( 289 | r"Key ([A-B]) cuid (0x[0-9a-f]*) sec (\d{1,2})", 290 | line.strip()) 291 | groups = result.groups() 292 | 293 | key_type, sec = groups[0], int(groups[-1]) 294 | values = list( 295 | map(lambda x: x if x.startswith("/") else (int(x, 16) if x.startswith("0x") else int(x)), groups[1:-1])) 296 | values.append(sec) 297 | values.append(key_type) 298 | return values 299 | 300 | @staticmethod 301 | def calculate_keys(uid, nt0, ks0, par0, nt1, ks1, par1, bruteforce_distance, progress): 302 | import faulthandler 303 | faulthandler.enable() 304 | import nested 305 | if bruteforce_distance != [0, 0]: 306 | run = nested.run_full_nested(uid, nt0, ks0, par0, nt1, ks1, par1, bruteforce_distance[0], 307 | bruteforce_distance[1], progress) 308 | else: 309 | run = nested.run_nested(uid, nt0, ks0, nt1, ks1) 310 | return run 311 | 312 | @staticmethod 313 | def calculate_keys_hard(uid, filename): 314 | import faulthandler 315 | faulthandler.enable() 316 | import hardnested 317 | run = hardnested.run_hardnested(uid, filename) 318 | return run 319 | -------------------------------------------------------------------------------- /FlipperNested/proto/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldip/FlipperNestedRecovery-GUI/79aff2118748f7e7538cbe5b40da467b8266d76b/FlipperNested/proto/__init__.py -------------------------------------------------------------------------------- /FlipperNested/proto/flipper.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | import "storage.proto"; 3 | 4 | package PB; 5 | option java_package = "com.flipperdevices.protobuf"; 6 | 7 | enum CommandStatus { 8 | OK = 0; 9 | 10 | /**< Common Errors */ 11 | ERROR = 1; /**< Unknown error */ 12 | ERROR_DECODE = 2; /**< Command can't be decoded successfully - command_id in response may be wrong! */ 13 | ERROR_NOT_IMPLEMENTED = 3; /**< Command succesfully decoded, but not implemented (deprecated or not yet implemented) */ 14 | ERROR_BUSY = 4; /**< Somebody took global lock, so not all commands are available */ 15 | ERROR_CONTINUOUS_COMMAND_INTERRUPTED = 14; /**< Not received has_next == 0 */ 16 | ERROR_INVALID_PARAMETERS = 15; /**< not provided (or provided invalid) crucial parameters to perform rpc */ 17 | 18 | /**< Storage Errors */ 19 | ERROR_STORAGE_NOT_READY = 5; /**< FS not ready */ 20 | ERROR_STORAGE_EXIST = 6; /**< File/Dir alrady exist */ 21 | ERROR_STORAGE_NOT_EXIST = 7; /**< File/Dir does not exist */ 22 | ERROR_STORAGE_INVALID_PARAMETER = 8; /**< Invalid API parameter */ 23 | ERROR_STORAGE_DENIED = 9; /**< Access denied */ 24 | ERROR_STORAGE_INVALID_NAME = 10; /**< Invalid name/path */ 25 | ERROR_STORAGE_INTERNAL = 11; /**< Internal error */ 26 | ERROR_STORAGE_NOT_IMPLEMENTED = 12; /**< Functon not implemented */ 27 | ERROR_STORAGE_ALREADY_OPEN = 13; /**< File/Dir already opened */ 28 | ERROR_STORAGE_DIR_NOT_EMPTY = 18; /**< Directory, you're going to remove is not empty */ 29 | 30 | /**< Application Errors */ 31 | ERROR_APP_CANT_START = 16; /**< Can't start app - internal error */ 32 | ERROR_APP_SYSTEM_LOCKED = 17; /**< Another app is running */ 33 | ERROR_APP_NOT_RUNNING = 21; /**< App is not running or doesn't support RPC commands */ 34 | ERROR_APP_CMD_ERROR = 22; /**< Command execution error */ 35 | 36 | /**< Virtual Display Errors */ 37 | ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED = 19; /**< Virtual Display session can't be started twice */ 38 | ERROR_VIRTUAL_DISPLAY_NOT_STARTED = 20; /**< Virtual Display session can't be stopped when it's not started */ 39 | 40 | /**< GPIO Errors */ 41 | ERROR_GPIO_MODE_INCORRECT = 58; 42 | ERROR_GPIO_UNKNOWN_PIN_MODE = 59; 43 | } 44 | 45 | /* There are Server commands (e.g. Storage_write), which have no body message 46 | * in response. But 'oneof' obligate to have at least 1 encoded message 47 | * in scope. For this needs Empty message is implemented. 48 | */ 49 | message Empty { 50 | } 51 | 52 | message StopSession { 53 | } 54 | 55 | message Main { 56 | uint32 command_id = 1; 57 | CommandStatus command_status = 2; 58 | bool has_next = 3; 59 | oneof content { 60 | Empty empty = 4; 61 | StopSession stop_session = 19; 62 | .PB_Storage.InfoRequest storage_info_request = 28; 63 | .PB_Storage.InfoResponse storage_info_response = 29; 64 | .PB_Storage.ListRequest storage_list_request = 7; 65 | .PB_Storage.ListResponse storage_list_response = 8; 66 | .PB_Storage.ReadRequest storage_read_request = 9; 67 | .PB_Storage.ReadResponse storage_read_response = 10; 68 | .PB_Storage.WriteRequest storage_write_request = 11; 69 | .PB_Storage.DeleteRequest storage_delete_request = 12; 70 | .PB_Storage.MkdirRequest storage_mkdir_request = 13; 71 | .PB_Storage.StatRequest storage_stat_request = 24; 72 | .PB_Storage.StatResponse storage_stat_response = 25; 73 | .PB_Storage.RenameRequest storage_rename_request = 30; 74 | } 75 | } 76 | 77 | message Region { 78 | message Band { 79 | uint32 start = 1; 80 | uint32 end = 2; 81 | int32 power_limit = 3; 82 | uint32 duty_cycle = 4; 83 | } 84 | 85 | bytes country_code = 1; 86 | repeated Band bands = 2; 87 | } -------------------------------------------------------------------------------- /FlipperNested/proto/flipper_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: flipper.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | import FlipperNested.proto.storage_pb2 as storage__pb2 15 | 16 | 17 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rflipper.proto\x12\x02PB\x1a\rstorage.proto\"\x07\n\x05\x45mpty\"\r\n\x0bStopSession\"\xe7\x06\n\x04Main\x12\x12\n\ncommand_id\x18\x01 \x01(\r\x12)\n\x0e\x63ommand_status\x18\x02 \x01(\x0e\x32\x11.PB.CommandStatus\x12\x10\n\x08has_next\x18\x03 \x01(\x08\x12\x1a\n\x05\x65mpty\x18\x04 \x01(\x0b\x32\t.PB.EmptyH\x00\x12\'\n\x0cstop_session\x18\x13 \x01(\x0b\x32\x0f.PB.StopSessionH\x00\x12\x37\n\x14storage_info_request\x18\x1c \x01(\x0b\x32\x17.PB_Storage.InfoRequestH\x00\x12\x39\n\x15storage_info_response\x18\x1d \x01(\x0b\x32\x18.PB_Storage.InfoResponseH\x00\x12\x37\n\x14storage_list_request\x18\x07 \x01(\x0b\x32\x17.PB_Storage.ListRequestH\x00\x12\x39\n\x15storage_list_response\x18\x08 \x01(\x0b\x32\x18.PB_Storage.ListResponseH\x00\x12\x37\n\x14storage_read_request\x18\t \x01(\x0b\x32\x17.PB_Storage.ReadRequestH\x00\x12\x39\n\x15storage_read_response\x18\n \x01(\x0b\x32\x18.PB_Storage.ReadResponseH\x00\x12\x39\n\x15storage_write_request\x18\x0b \x01(\x0b\x32\x18.PB_Storage.WriteRequestH\x00\x12;\n\x16storage_delete_request\x18\x0c \x01(\x0b\x32\x19.PB_Storage.DeleteRequestH\x00\x12\x39\n\x15storage_mkdir_request\x18\r \x01(\x0b\x32\x18.PB_Storage.MkdirRequestH\x00\x12\x37\n\x14storage_stat_request\x18\x18 \x01(\x0b\x32\x17.PB_Storage.StatRequestH\x00\x12\x39\n\x15storage_stat_response\x18\x19 \x01(\x0b\x32\x18.PB_Storage.StatResponseH\x00\x12;\n\x16storage_rename_request\x18\x1e \x01(\x0b\x32\x19.PB_Storage.RenameRequestH\x00\x42\t\n\x07\x63ontent\"\x8b\x01\n\x06Region\x12\x14\n\x0c\x63ountry_code\x18\x01 \x01(\x0c\x12\x1e\n\x05\x62\x61nds\x18\x02 \x03(\x0b\x32\x0f.PB.Region.Band\x1aK\n\x04\x42\x61nd\x12\r\n\x05start\x18\x01 \x01(\r\x12\x0b\n\x03\x65nd\x18\x02 \x01(\r\x12\x13\n\x0bpower_limit\x18\x03 \x01(\x05\x12\x12\n\nduty_cycle\x18\x04 \x01(\r*\xd6\x05\n\rCommandStatus\x12\x06\n\x02OK\x10\x00\x12\t\n\x05\x45RROR\x10\x01\x12\x10\n\x0c\x45RROR_DECODE\x10\x02\x12\x19\n\x15\x45RROR_NOT_IMPLEMENTED\x10\x03\x12\x0e\n\nERROR_BUSY\x10\x04\x12(\n$ERROR_CONTINUOUS_COMMAND_INTERRUPTED\x10\x0e\x12\x1c\n\x18\x45RROR_INVALID_PARAMETERS\x10\x0f\x12\x1b\n\x17\x45RROR_STORAGE_NOT_READY\x10\x05\x12\x17\n\x13\x45RROR_STORAGE_EXIST\x10\x06\x12\x1b\n\x17\x45RROR_STORAGE_NOT_EXIST\x10\x07\x12#\n\x1f\x45RROR_STORAGE_INVALID_PARAMETER\x10\x08\x12\x18\n\x14\x45RROR_STORAGE_DENIED\x10\t\x12\x1e\n\x1a\x45RROR_STORAGE_INVALID_NAME\x10\n\x12\x1a\n\x16\x45RROR_STORAGE_INTERNAL\x10\x0b\x12!\n\x1d\x45RROR_STORAGE_NOT_IMPLEMENTED\x10\x0c\x12\x1e\n\x1a\x45RROR_STORAGE_ALREADY_OPEN\x10\r\x12\x1f\n\x1b\x45RROR_STORAGE_DIR_NOT_EMPTY\x10\x12\x12\x18\n\x14\x45RROR_APP_CANT_START\x10\x10\x12\x1b\n\x17\x45RROR_APP_SYSTEM_LOCKED\x10\x11\x12\x19\n\x15\x45RROR_APP_NOT_RUNNING\x10\x15\x12\x17\n\x13\x45RROR_APP_CMD_ERROR\x10\x16\x12)\n%ERROR_VIRTUAL_DISPLAY_ALREADY_STARTED\x10\x13\x12%\n!ERROR_VIRTUAL_DISPLAY_NOT_STARTED\x10\x14\x12\x1d\n\x19\x45RROR_GPIO_MODE_INCORRECT\x10:\x12\x1f\n\x1b\x45RROR_GPIO_UNKNOWN_PIN_MODE\x10;B\x1d\n\x1b\x63om.flipperdevices.protobufb\x06proto3') 18 | 19 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 20 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flipper_pb2', globals()) 21 | if _descriptor._USE_C_DESCRIPTORS == False: 22 | 23 | DESCRIPTOR._options = None 24 | DESCRIPTOR._serialized_options = b'\n\033com.flipperdevices.protobuf' 25 | _COMMANDSTATUS._serialized_start=1077 26 | _COMMANDSTATUS._serialized_end=1803 27 | _EMPTY._serialized_start=36 28 | _EMPTY._serialized_end=43 29 | _STOPSESSION._serialized_start=45 30 | _STOPSESSION._serialized_end=58 31 | _MAIN._serialized_start=61 32 | _MAIN._serialized_end=932 33 | _REGION._serialized_start=935 34 | _REGION._serialized_end=1074 35 | _REGION_BAND._serialized_start=999 36 | _REGION_BAND._serialized_end=1074 37 | # @@protoc_insertion_point(module_scope) 38 | -------------------------------------------------------------------------------- /FlipperNested/proto/storage.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package PB_Storage; 4 | option java_package = "com.flipperdevices.protobuf.storage"; 5 | 6 | message File { 7 | enum FileType { 8 | FILE = 0; // default value 9 | DIR = 1; 10 | } 11 | FileType type = 1; 12 | string name = 2; 13 | uint32 size = 3; 14 | bytes data = 4; 15 | } 16 | 17 | message InfoRequest { 18 | string path = 1; 19 | } 20 | 21 | message InfoResponse { 22 | uint64 total_space = 1; 23 | uint64 free_space = 2; 24 | } 25 | 26 | message ListRequest { 27 | string path = 1; 28 | } 29 | 30 | message ListResponse { 31 | repeated File file = 1; 32 | } 33 | 34 | message ReadRequest { 35 | string path = 1; 36 | } 37 | 38 | message ReadResponse { 39 | File file = 1; 40 | } 41 | 42 | message StatRequest { 43 | string path = 1; 44 | } 45 | 46 | message StatResponse { 47 | File file = 1; 48 | } 49 | 50 | message MkdirRequest { 51 | string path = 1; 52 | } 53 | 54 | message RenameRequest { 55 | string old_path = 1; 56 | string new_path = 2; 57 | } 58 | 59 | message WriteRequest { 60 | string path = 1; 61 | File file = 2; 62 | } 63 | 64 | message DeleteRequest { 65 | string path = 1; 66 | bool recursive = 2; 67 | } -------------------------------------------------------------------------------- /FlipperNested/proto/storage_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # source: storage.proto 4 | """Generated protocol buffer code.""" 5 | from google.protobuf.internal import builder as _builder 6 | from google.protobuf import descriptor as _descriptor 7 | from google.protobuf import descriptor_pool as _descriptor_pool 8 | from google.protobuf import symbol_database as _symbol_database 9 | # @@protoc_insertion_point(imports) 10 | 11 | _sym_db = _symbol_database.Default() 12 | 13 | 14 | 15 | 16 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rstorage.proto\x12\nPB_Storage\"x\n\x04\x46ile\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.PB_Storage.File.FileType\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04size\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\"\x1d\n\x08\x46ileType\x12\x08\n\x04\x46ILE\x10\x00\x12\x07\n\x03\x44IR\x10\x01\"\x1b\n\x0bInfoRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"7\n\x0cInfoResponse\x12\x13\n\x0btotal_space\x18\x01 \x01(\x04\x12\x12\n\nfree_space\x18\x02 \x01(\x04\"\x1b\n\x0bListRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\".\n\x0cListResponse\x12\x1e\n\x04\x66ile\x18\x01 \x03(\x0b\x32\x10.PB_Storage.File\"\x1b\n\x0bReadRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\".\n\x0cReadResponse\x12\x1e\n\x04\x66ile\x18\x01 \x01(\x0b\x32\x10.PB_Storage.File\"\x1b\n\x0bStatRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\".\n\x0cStatResponse\x12\x1e\n\x04\x66ile\x18\x01 \x01(\x0b\x32\x10.PB_Storage.File\"\x1c\n\x0cMkdirRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\"3\n\rRenameRequest\x12\x10\n\x08old_path\x18\x01 \x01(\t\x12\x10\n\x08new_path\x18\x02 \x01(\t\"<\n\x0cWriteRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x1e\n\x04\x66ile\x18\x02 \x01(\x0b\x32\x10.PB_Storage.File\"0\n\rDeleteRequest\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x11\n\trecursive\x18\x02 \x01(\x08\x42%\n#com.flipperdevices.protobuf.storageb\x06proto3') 17 | 18 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) 19 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'storage_pb2', globals()) 20 | if _descriptor._USE_C_DESCRIPTORS == False: 21 | 22 | DESCRIPTOR._options = None 23 | DESCRIPTOR._serialized_options = b'\n#com.flipperdevices.protobuf.storage' 24 | _FILE._serialized_start=29 25 | _FILE._serialized_end=149 26 | _FILE_FILETYPE._serialized_start=120 27 | _FILE_FILETYPE._serialized_end=149 28 | _INFOREQUEST._serialized_start=151 29 | _INFOREQUEST._serialized_end=178 30 | _INFORESPONSE._serialized_start=180 31 | _INFORESPONSE._serialized_end=235 32 | _LISTREQUEST._serialized_start=237 33 | _LISTREQUEST._serialized_end=264 34 | _LISTRESPONSE._serialized_start=266 35 | _LISTRESPONSE._serialized_end=312 36 | _READREQUEST._serialized_start=314 37 | _READREQUEST._serialized_end=341 38 | _READRESPONSE._serialized_start=343 39 | _READRESPONSE._serialized_end=389 40 | _STATREQUEST._serialized_start=391 41 | _STATREQUEST._serialized_end=418 42 | _STATRESPONSE._serialized_start=420 43 | _STATRESPONSE._serialized_end=466 44 | _MKDIRREQUEST._serialized_start=468 45 | _MKDIRREQUEST._serialized_end=496 46 | _RENAMEREQUEST._serialized_start=498 47 | _RENAMEREQUEST._serialized_end=549 48 | _WRITEREQUEST._serialized_start=551 49 | _WRITEREQUEST._serialized_end=611 50 | _DELETEREQUEST._serialized_start=613 51 | _DELETEREQUEST._serialized_end=661 52 | # @@protoc_insertion_point(module_scope) 53 | -------------------------------------------------------------------------------- /HardNestedSolver/bucketsort.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #include "bucketsort.h" 17 | 18 | extern void bucket_sort_intersect(uint32_t *const estart, uint32_t *const estop, 19 | uint32_t *const ostart, uint32_t *const ostop, 20 | bucket_info_t *bucket_info, bucket_array_t bucket) { 21 | uint32_t *p1, *p2; 22 | uint32_t *start[2]; 23 | uint32_t *stop[2]; 24 | 25 | start[0] = estart; 26 | stop[0] = estop; 27 | start[1] = ostart; 28 | stop[1] = ostop; 29 | 30 | // init buckets to be empty 31 | for (uint32_t i = 0; i < 2; i++) { 32 | for (uint32_t j = 0x00; j <= 0xff; j++) { 33 | bucket[i][j].bp = bucket[i][j].head; 34 | } 35 | } 36 | 37 | // sort the lists into the buckets based on the MSB (contribution bits) 38 | for (uint32_t i = 0; i < 2; i++) { 39 | for (p1 = start[i]; p1 <= stop[i]; p1++) { 40 | uint32_t bucket_index = (*p1 & 0xff000000) >> 24; 41 | *(bucket[i][bucket_index].bp++) = *p1; 42 | } 43 | } 44 | 45 | // write back intersecting buckets as sorted list. 46 | // fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets. 47 | for (uint32_t i = 0; i < 2; i++) { 48 | p1 = start[i]; 49 | uint32_t nonempty_bucket = 0; 50 | for (uint32_t j = 0x00; j <= 0xff; j++) { 51 | if (bucket[0][j].bp != bucket[0][j].head && bucket[1][j].bp != bucket[1][j].head) { // non-empty intersecting buckets only 52 | bucket_info->bucket_info[i][nonempty_bucket].head = p1; 53 | for (p2 = bucket[i][j].head; p2 < bucket[i][j].bp; *p1++ = *p2++); 54 | bucket_info->bucket_info[i][nonempty_bucket].tail = p1 - 1; 55 | nonempty_bucket++; 56 | } 57 | } 58 | bucket_info->numbuckets = nonempty_bucket; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /HardNestedSolver/bucketsort.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #ifndef BUCKETSORT_H__ 17 | #define BUCKETSORT_H__ 18 | #include 19 | #include 20 | 21 | typedef struct bucket { 22 | uint32_t *head; 23 | uint32_t *bp; 24 | } bucket_t; 25 | 26 | typedef bucket_t bucket_array_t[2][0x100]; 27 | 28 | typedef struct bucket_info { 29 | struct { 30 | uint32_t *head, *tail; 31 | } bucket_info[2][0x100]; 32 | uint32_t numbuckets; 33 | } bucket_info_t; 34 | 35 | void bucket_sort_intersect(uint32_t *const estart, uint32_t *const estop, 36 | uint32_t *const ostart, uint32_t *const ostop, 37 | bucket_info_t *bucket_info, bucket_array_t bucket); 38 | 39 | #endif -------------------------------------------------------------------------------- /HardNestedSolver/cmdhfmfhard.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // hf mf hardnested command 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef CMDHFMFHARD_H__ 20 | #define CMDHFMFHARD_H__ 21 | 22 | #include "pm3/common.h" 23 | 24 | int 25 | mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *trgkey, 26 | bool nonce_file_read, bool nonce_file_write, bool slow, uint64_t *foundkey, char *filename, uint32_t uid, char* path); 27 | void hardnested_print_progress(uint32_t nonces, const char *activity, float brute_force, uint64_t min_diff_print_time); 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /HardNestedSolver/crapto1.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #include "crapto1.h" 18 | 19 | #include "bucketsort.h" 20 | 21 | #include 22 | #include "parity.h" 23 | 24 | /** update_contribution 25 | * helper, calculates the partial linear feedback contributions and puts in MSB 26 | */ 27 | static inline void update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) { 28 | uint32_t p = *item >> 25; 29 | 30 | p = p << 1 | (evenparity32(*item & mask1)); 31 | p = p << 1 | (evenparity32(*item & mask2)); 32 | *item = p << 24 | (*item & 0xffffff); 33 | } 34 | 35 | /** extend_table 36 | * using a bit of the keystream extend the table of possible lfsr states 37 | */ 38 | static inline void extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) { 39 | in <<= 24; 40 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) 41 | if (filter(*tbl) ^ filter(*tbl | 1)) { 42 | *tbl |= filter(*tbl) ^ bit; 43 | update_contribution(tbl, m1, m2); 44 | *tbl ^= in; 45 | } else if (filter(*tbl) == bit) { 46 | *++*end = tbl[1]; 47 | tbl[1] = tbl[0] | 1; 48 | update_contribution(tbl, m1, m2); 49 | *tbl++ ^= in; 50 | update_contribution(tbl, m1, m2); 51 | *tbl ^= in; 52 | } else 53 | *tbl-- = *(*end)--; 54 | } 55 | /** extend_table_simple 56 | * using a bit of the keystream extend the table of possible lfsr states 57 | */ 58 | static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) { 59 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) { 60 | if (filter(*tbl) ^ filter(*tbl | 1)) { // replace 61 | *tbl |= filter(*tbl) ^ bit; 62 | } else if (filter(*tbl) == bit) { // insert 63 | *++*end = *++tbl; 64 | *tbl = tbl[-1] | 1; 65 | } else { // drop 66 | *tbl-- = *(*end)--; 67 | } 68 | } 69 | } 70 | /** recover 71 | * recursively narrow down the search space, 4 bits of keystream at a time 72 | */ 73 | static struct Crypto1State * 74 | recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, 75 | uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, 76 | struct Crypto1State *sl, uint32_t in, bucket_array_t bucket) { 77 | bucket_info_t bucket_info; 78 | 79 | if (rem == -1) { 80 | for (uint32_t *e = e_head; e <= e_tail; ++e) { 81 | *e = *e << 1 ^ (evenparity32(*e & LF_POLY_EVEN)) ^ (!!(in & 4)); 82 | for (uint32_t *o = o_head; o <= o_tail; ++o, ++sl) { 83 | sl->even = *o; 84 | sl->odd = *e ^ (evenparity32(*o & LF_POLY_ODD)); 85 | sl[1].odd = sl[1].even = 0; 86 | } 87 | } 88 | return sl; 89 | } 90 | 91 | for (uint32_t i = 0; i < 4 && rem--; i++) { 92 | oks >>= 1; 93 | eks >>= 1; 94 | in >>= 2; 95 | extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); 96 | if (o_head > o_tail) 97 | return sl; 98 | 99 | extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); 100 | if (e_head > e_tail) 101 | return sl; 102 | } 103 | 104 | bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket); 105 | 106 | for (int i = bucket_info.numbuckets - 1; i >= 0; i--) { 107 | sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks, 108 | bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks, 109 | rem, sl, in, bucket); 110 | } 111 | 112 | return sl; 113 | } 114 | 115 | 116 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() 117 | /** lfsr_recovery 118 | * recover the state of the lfsr given 32 bits of the keystream 119 | * additionally you can use the in parameter to specify the value 120 | * that was fed into the lfsr at the time the keystream was generated 121 | */ 122 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in) { 123 | struct Crypto1State *statelist; 124 | uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; 125 | uint32_t *even_head = 0, *even_tail = 0, eks = 0; 126 | int i; 127 | 128 | // split the keystream into an odd and even part 129 | for (i = 31; i >= 0; i -= 2) 130 | oks = oks << 1 | BEBIT(ks2, i); 131 | for (i = 30; i >= 0; i -= 2) 132 | eks = eks << 1 | BEBIT(ks2, i); 133 | 134 | odd_head = odd_tail = calloc(1, sizeof(uint32_t) << 21); 135 | even_head = even_tail = calloc(1, sizeof(uint32_t) << 21); 136 | statelist = calloc(1, sizeof(struct Crypto1State) << 18); 137 | if (!odd_tail-- || !even_tail-- || !statelist) { 138 | free(statelist); 139 | statelist = 0; 140 | goto out; 141 | } 142 | 143 | statelist->odd = statelist->even = 0; 144 | 145 | // allocate memory for out of place bucket_sort 146 | bucket_array_t bucket; 147 | 148 | for (i = 0; i < 2; i++) { 149 | for (uint32_t j = 0; j <= 0xff; j++) { 150 | bucket[i][j].head = calloc(1, sizeof(uint32_t) << 14); 151 | if (!bucket[i][j].head) { 152 | goto out; 153 | } 154 | } 155 | } 156 | 157 | // initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream 158 | for (i = 1 << 20; i >= 0; --i) { 159 | if (filter(i) == (oks & 1)) 160 | *++odd_tail = i; 161 | if (filter(i) == (eks & 1)) 162 | *++even_tail = i; 163 | } 164 | 165 | // extend the statelists. Look at the next 8 Bits of the keystream (4 Bit each odd and even): 166 | for (i = 0; i < 4; i++) { 167 | extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); 168 | extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); 169 | } 170 | 171 | // the statelists now contain all states which could have generated the last 10 Bits of the keystream. 172 | // 22 bits to go to recover 32 bits in total. From now on, we need to take the "in" 173 | // parameter into account. 174 | in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); // Byte swapping 175 | recover(odd_head, odd_tail, oks, even_head, even_tail, eks, 11, statelist, in << 1, bucket); 176 | 177 | out: 178 | for (i = 0; i < 2; i++) 179 | for (uint32_t j = 0; j <= 0xff; j++) 180 | free(bucket[i][j].head); 181 | free(odd_head); 182 | free(even_head); 183 | return statelist; 184 | } 185 | 186 | static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, 187 | 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 188 | 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA 189 | }; 190 | static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, 191 | 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 192 | 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, 193 | 0x7EC7EE90, 0x7F63F748, 0x79117020 194 | }; 195 | static const uint32_t T1[] = { 196 | 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, 197 | 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, 198 | 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, 199 | 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C 200 | }; 201 | static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, 202 | 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, 203 | 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, 204 | 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, 205 | 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, 206 | 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0 207 | }; 208 | static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; 209 | static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; 210 | /** Reverse 64 bits of keystream into possible cipher states 211 | * Variation mentioned in the paper. Somewhat optimized version 212 | */ 213 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3) { 214 | struct Crypto1State *statelist, *sl; 215 | uint8_t oks[32], eks[32], hi[32]; 216 | uint32_t low = 0, win = 0; 217 | uint32_t *tail, table[1 << 16]; 218 | int i, j; 219 | 220 | sl = statelist = calloc(1, sizeof(struct Crypto1State) << 4); 221 | if (!sl) 222 | return 0; 223 | sl->odd = sl->even = 0; 224 | 225 | for (i = 30; i >= 0; i -= 2) { 226 | oks[i >> 1] = BEBIT(ks2, i); 227 | oks[16 + (i >> 1)] = BEBIT(ks3, i); 228 | } 229 | for (i = 31; i >= 0; i -= 2) { 230 | eks[i >> 1] = BEBIT(ks2, i); 231 | eks[16 + (i >> 1)] = BEBIT(ks3, i); 232 | } 233 | 234 | for (i = 0xfffff; i >= 0; --i) { 235 | if (filter(i) != oks[0]) 236 | continue; 237 | 238 | *(tail = table) = i; 239 | for (j = 1; tail >= table && j < 29; ++j) 240 | extend_table_simple(table, &tail, oks[j]); 241 | 242 | if (tail < table) 243 | continue; 244 | 245 | for (j = 0; j < 19; ++j) 246 | low = low << 1 | (evenparity32(i & S1[j])); 247 | for (j = 0; j < 32; ++j) 248 | hi[j] = evenparity32(i & T1[j]); 249 | 250 | for (; tail >= table; --tail) { 251 | for (j = 0; j < 3; ++j) { 252 | *tail = *tail << 1; 253 | *tail |= evenparity32((i & C1[j]) ^ (*tail & C2[j])); 254 | if (filter(*tail) != oks[29 + j]) 255 | goto continue2; 256 | } 257 | 258 | for (j = 0; j < 19; ++j) 259 | win = win << 1 | (evenparity32(*tail & S2[j])); 260 | 261 | win ^= low; 262 | for (j = 0; j < 32; ++j) { 263 | win = win << 1 ^ hi[j] ^ (evenparity32(*tail & T2[j])); 264 | if (filter(win) != eks[j]) 265 | goto continue2; 266 | } 267 | 268 | *tail = *tail << 1 | (evenparity32(LF_POLY_EVEN & *tail)); 269 | sl->odd = *tail ^ (evenparity32(LF_POLY_ODD & win)); 270 | sl->even = win; 271 | ++sl; 272 | sl->odd = sl->even = 0; 273 | continue2: 274 | ; 275 | } 276 | } 277 | return statelist; 278 | } 279 | #endif 280 | 281 | /** lfsr_rollback_bit 282 | * Rollback the shift register in order to get previous states 283 | */ 284 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) { 285 | int out; 286 | uint8_t ret; 287 | uint32_t t; 288 | 289 | s->odd &= 0xffffff; 290 | t = s->odd, s->odd = s->even, s->even = t; 291 | 292 | out = s->even & 1; 293 | out ^= LF_POLY_EVEN & (s->even >>= 1); 294 | out ^= LF_POLY_ODD & s->odd; 295 | out ^= !!in; 296 | out ^= (ret = filter(s->odd)) & (!!fb); 297 | 298 | s->even |= (evenparity32(out)) << 23; 299 | return ret; 300 | } 301 | /** lfsr_rollback_byte 302 | * Rollback the shift register in order to get previous states 303 | */ 304 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) { 305 | uint8_t ret = 0; 306 | ret |= lfsr_rollback_bit(s, BIT(in, 7), fb) << 7; 307 | ret |= lfsr_rollback_bit(s, BIT(in, 6), fb) << 6; 308 | ret |= lfsr_rollback_bit(s, BIT(in, 5), fb) << 5; 309 | ret |= lfsr_rollback_bit(s, BIT(in, 4), fb) << 4; 310 | ret |= lfsr_rollback_bit(s, BIT(in, 3), fb) << 3; 311 | ret |= lfsr_rollback_bit(s, BIT(in, 2), fb) << 2; 312 | ret |= lfsr_rollback_bit(s, BIT(in, 1), fb) << 1; 313 | ret |= lfsr_rollback_bit(s, BIT(in, 0), fb) << 0; 314 | return ret; 315 | } 316 | /** lfsr_rollback_word 317 | * Rollback the shift register in order to get previous states 318 | */ 319 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) { 320 | 321 | uint32_t ret = 0; 322 | // note: xor args have been swapped because some compilers emit a warning 323 | // for 10^x and 2^x as possible misuses for exponentiation. No comment. 324 | ret |= lfsr_rollback_bit(s, BEBIT(in, 31), fb) << (24 ^ 31); 325 | ret |= lfsr_rollback_bit(s, BEBIT(in, 30), fb) << (24 ^ 30); 326 | ret |= lfsr_rollback_bit(s, BEBIT(in, 29), fb) << (24 ^ 29); 327 | ret |= lfsr_rollback_bit(s, BEBIT(in, 28), fb) << (24 ^ 28); 328 | ret |= lfsr_rollback_bit(s, BEBIT(in, 27), fb) << (24 ^ 27); 329 | ret |= lfsr_rollback_bit(s, BEBIT(in, 26), fb) << (24 ^ 26); 330 | ret |= lfsr_rollback_bit(s, BEBIT(in, 25), fb) << (24 ^ 25); 331 | ret |= lfsr_rollback_bit(s, BEBIT(in, 24), fb) << (24 ^ 24); 332 | 333 | ret |= lfsr_rollback_bit(s, BEBIT(in, 23), fb) << (24 ^ 23); 334 | ret |= lfsr_rollback_bit(s, BEBIT(in, 22), fb) << (24 ^ 22); 335 | ret |= lfsr_rollback_bit(s, BEBIT(in, 21), fb) << (24 ^ 21); 336 | ret |= lfsr_rollback_bit(s, BEBIT(in, 20), fb) << (24 ^ 20); 337 | ret |= lfsr_rollback_bit(s, BEBIT(in, 19), fb) << (24 ^ 19); 338 | ret |= lfsr_rollback_bit(s, BEBIT(in, 18), fb) << (24 ^ 18); 339 | ret |= lfsr_rollback_bit(s, BEBIT(in, 17), fb) << (24 ^ 17); 340 | ret |= lfsr_rollback_bit(s, BEBIT(in, 16), fb) << (24 ^ 16); 341 | 342 | ret |= lfsr_rollback_bit(s, BEBIT(in, 15), fb) << (24 ^ 15); 343 | ret |= lfsr_rollback_bit(s, BEBIT(in, 14), fb) << (24 ^ 14); 344 | ret |= lfsr_rollback_bit(s, BEBIT(in, 13), fb) << (24 ^ 13); 345 | ret |= lfsr_rollback_bit(s, BEBIT(in, 12), fb) << (24 ^ 12); 346 | ret |= lfsr_rollback_bit(s, BEBIT(in, 11), fb) << (24 ^ 11); 347 | ret |= lfsr_rollback_bit(s, BEBIT(in, 10), fb) << (24 ^ 10); 348 | ret |= lfsr_rollback_bit(s, BEBIT(in, 9), fb) << (24 ^ 9); 349 | ret |= lfsr_rollback_bit(s, BEBIT(in, 8), fb) << (24 ^ 8); 350 | 351 | ret |= lfsr_rollback_bit(s, BEBIT(in, 7), fb) << (24 ^ 7); 352 | ret |= lfsr_rollback_bit(s, BEBIT(in, 6), fb) << (24 ^ 6); 353 | ret |= lfsr_rollback_bit(s, BEBIT(in, 5), fb) << (24 ^ 5); 354 | ret |= lfsr_rollback_bit(s, BEBIT(in, 4), fb) << (24 ^ 4); 355 | ret |= lfsr_rollback_bit(s, BEBIT(in, 3), fb) << (24 ^ 3); 356 | ret |= lfsr_rollback_bit(s, BEBIT(in, 2), fb) << (24 ^ 2); 357 | ret |= lfsr_rollback_bit(s, BEBIT(in, 1), fb) << (24 ^ 1); 358 | ret |= lfsr_rollback_bit(s, BEBIT(in, 0), fb) << (24 ^ 0); 359 | return ret; 360 | } 361 | 362 | /** nonce_distance 363 | * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y 364 | */ 365 | static uint16_t *dist = 0; 366 | int nonce_distance(uint32_t from, uint32_t to) { 367 | if (!dist) { 368 | // allocation 2bytes * 0xFFFF times. 369 | dist = calloc(2 << 16, sizeof(uint8_t)); 370 | if (!dist) 371 | return -1; 372 | uint16_t x = 1; 373 | for (uint16_t i = 1; i; ++i) { 374 | dist[(x & 0xff) << 8 | x >> 8] = i; 375 | x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; 376 | } 377 | } 378 | return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; 379 | } 380 | 381 | /** validate_prng_nonce 382 | * Determine if nonce is deterministic. ie: Suspectable to Darkside attack. 383 | * returns 384 | * true = weak prng 385 | * false = hardend prng 386 | */ 387 | bool validate_prng_nonce(uint32_t nonce) { 388 | // init prng table: 389 | if (nonce_distance(nonce, nonce) == -1) 390 | return false; 391 | return ((65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535) == 16; 392 | } 393 | 394 | static uint32_t fastfwd[2][8] = { 395 | { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, 396 | { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980} 397 | }; 398 | 399 | /** lfsr_prefix_ks 400 | * 401 | * Is an exported helper function from the common prefix attack 402 | * Described in the "dark side" paper. It returns an -1 terminated array 403 | * of possible partial(21 bit) secret state. 404 | * The required keystream(ks) needs to contain the keystream that was used to 405 | * encrypt the NACK which is observed when varying only the 3 last bits of Nr 406 | * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 407 | */ 408 | uint32_t *lfsr_prefix_ks(const uint8_t ks[8], int isodd) { 409 | uint32_t *candidates = calloc(4 << 10, sizeof(uint8_t)); 410 | if (!candidates) return 0; 411 | 412 | int size = 0; 413 | 414 | for (int i = 0; i < 1 << 21; ++i) { 415 | int good = 1; 416 | for (uint32_t c = 0; good && c < 8; ++c) { 417 | uint32_t entry = i ^ fastfwd[isodd][c]; 418 | good &= (BIT(ks[c], isodd) == filter(entry >> 1)); 419 | good &= (BIT(ks[c], isodd + 2) == filter(entry)); 420 | } 421 | if (good) 422 | candidates[size++] = i; 423 | } 424 | 425 | candidates[size] = -1; 426 | 427 | return candidates; 428 | } 429 | 430 | /** check_pfx_parity 431 | * helper function which eliminates possible secret states using parity bits 432 | */ 433 | static struct Crypto1State *check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], uint32_t odd, uint32_t even, struct Crypto1State *sl, uint32_t no_par) { 434 | uint32_t good = 1; 435 | 436 | for (uint32_t c = 0; good && c < 8; ++c) { 437 | sl->odd = odd ^ fastfwd[1][c]; 438 | sl->even = even ^ fastfwd[0][c]; 439 | 440 | lfsr_rollback_bit(sl, 0, 0); 441 | lfsr_rollback_bit(sl, 0, 0); 442 | 443 | uint32_t ks3 = lfsr_rollback_bit(sl, 0, 0); 444 | uint32_t ks2 = lfsr_rollback_word(sl, 0, 0); 445 | uint32_t ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); 446 | 447 | if (no_par) 448 | break; 449 | 450 | uint32_t nr = ks1 ^ (prefix | c << 5); 451 | uint32_t rr = ks2 ^ rresp; 452 | 453 | good &= evenparity32(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); 454 | good &= evenparity32(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); 455 | good &= evenparity32(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); 456 | good &= evenparity32(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); 457 | good &= evenparity32(rr & 0x000000ff) ^ parities[c][7] ^ ks3; 458 | } 459 | 460 | return sl + good; 461 | } 462 | 463 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() 464 | /** lfsr_common_prefix 465 | * Implementation of the common prefix attack. 466 | * Requires the 28 bit constant prefix used as reader nonce (pfx) 467 | * The reader response used (rr) 468 | * The keystream used to encrypt the observed NACK's (ks) 469 | * The parity bits (par) 470 | * It returns a zero terminated list of possible cipher states after the 471 | * tag nonce was fed in 472 | */ 473 | 474 | struct Crypto1State *lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par) { 475 | struct Crypto1State *statelist, *s; 476 | uint32_t *odd, *even, *o, *e, top; 477 | 478 | odd = lfsr_prefix_ks(ks, 1); 479 | even = lfsr_prefix_ks(ks, 0); 480 | 481 | s = statelist = calloc(1, (sizeof * statelist) << 24); // was << 20. Need more for no_par special attack. Enough??? 482 | if (!s || !odd || !even) { 483 | free(statelist); 484 | statelist = 0; 485 | goto out; 486 | } 487 | 488 | for (o = odd; *o + 1; ++o) 489 | for (e = even; *e + 1; ++e) 490 | for (top = 0; top < 64; ++top) { 491 | *o += 1 << 21; 492 | *e += (!(top & 7) + 1) << 21; 493 | s = check_pfx_parity(pfx, rr, par, *o, *e, s, no_par); 494 | } 495 | 496 | s->odd = s->even = 0; 497 | out: 498 | free(odd); 499 | free(even); 500 | return statelist; 501 | } 502 | #endif 503 | -------------------------------------------------------------------------------- /HardNestedSolver/crapto1.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #ifndef crypto01_INCLUDED 18 | #define crypto01_INCLUDED 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | struct Crypto1State {uint32_t odd, even;}; 25 | void crypto1_init(struct Crypto1State *state, uint64_t key); 26 | void crypto1_deinit(struct Crypto1State *); 27 | struct Crypto1State *crypto1_create(uint64_t key); 28 | void crypto1_destroy(struct Crypto1State *); 29 | void crypto1_get_lfsr(struct Crypto1State *, uint64_t *); 30 | uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int); 31 | uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int); 32 | uint32_t crypto1_word(struct Crypto1State *, uint32_t, int); 33 | uint32_t prng_successor(uint32_t x, uint32_t n); 34 | 35 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in); 36 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3); 37 | struct Crypto1State * 38 | lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par); 39 | uint32_t *lfsr_prefix_ks(const uint8_t ks[8], int isodd); 40 | 41 | 42 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb); 43 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb); 44 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb); 45 | int nonce_distance(uint32_t from, uint32_t to); 46 | bool validate_prng_nonce(uint32_t nonce); 47 | #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\ 48 | uint32_t __n = 0,__M = 0, N = 0;\ 49 | int __i;\ 50 | for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ 51 | for(__i = FSIZE - 1; __i >= 0; __i--)\ 52 | if(BIT(FILTER, __i) ^ evenparity32(__M & 0xFF01))\ 53 | break;\ 54 | else if(__i)\ 55 | __M = prng_successor(__M, (__i == 7) ? 48 : 8);\ 56 | else 57 | 58 | #define LF_POLY_ODD (0x29CE5C) 59 | #define LF_POLY_EVEN (0x870804) 60 | #define BIT(x, n) ((x) >> (n) & 1) 61 | #define BEBIT(x, n) BIT(x, (n) ^ 24) 62 | static inline int filter(uint32_t const x) { 63 | uint32_t f; 64 | 65 | f = 0xf22c0 >> (x & 0xf) & 16; 66 | f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; 67 | f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; 68 | f |= 0x1e458 >> (x >> 12 & 0xf) & 2; 69 | f |= 0x0d938 >> (x >> 16 & 0xf) & 1; 70 | return BIT(0xEC57E80A, f); 71 | } 72 | #endif -------------------------------------------------------------------------------- /HardNestedSolver/crypto1.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #include 18 | #include "crapto1.h" 19 | #include "parity.h" 20 | 21 | #ifdef __OPTIMIZE_SIZE__ 22 | int filter(uint32_t const x) { 23 | uint32_t f; 24 | 25 | f = 0xf22c0 >> (x & 0xf) & 16; 26 | f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; 27 | f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; 28 | f |= 0x1e458 >> (x >> 12 & 0xf) & 2; 29 | f |= 0x0d938 >> (x >> 16 & 0xf) & 1; 30 | return BIT(0xEC57E80A, f); 31 | } 32 | #endif 33 | 34 | #define SWAPENDIAN(x)\ 35 | (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) 36 | 37 | void crypto1_init(struct Crypto1State *state, uint64_t key) { 38 | if (state == NULL) 39 | return; 40 | state->odd = 0; 41 | state->even = 0; 42 | for (int i = 47; i > 0; i -= 2) { 43 | state->odd = state->odd << 1 | BIT(key, (i - 1) ^ 7); 44 | state->even = state->even << 1 | BIT(key, i ^ 7); 45 | } 46 | } 47 | 48 | void crypto1_deinit(struct Crypto1State *state) { 49 | state->odd = 0; 50 | state->even = 0; 51 | } 52 | 53 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks calloc()/free() 54 | 55 | struct Crypto1State *crypto1_create(uint64_t key) { 56 | struct Crypto1State *state = calloc(sizeof(*state), sizeof(uint8_t)); 57 | if (!state) return NULL; 58 | crypto1_init(state, key); 59 | return state; 60 | } 61 | 62 | void crypto1_destroy(struct Crypto1State *state) { 63 | free(state); 64 | } 65 | 66 | #endif 67 | 68 | void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) { 69 | int i; 70 | for (*lfsr = 0, i = 23; i >= 0; --i) { 71 | *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); 72 | *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); 73 | } 74 | } 75 | 76 | uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) { 77 | uint32_t feedin, t; 78 | uint8_t ret = filter(s->odd); 79 | 80 | feedin = ret & (!!is_encrypted); 81 | feedin ^= !!in; 82 | feedin ^= LF_POLY_ODD & s->odd; 83 | feedin ^= LF_POLY_EVEN & s->even; 84 | s->even = s->even << 1 | (evenparity32(feedin)); 85 | 86 | t = s->odd; 87 | s->odd = s->even; 88 | s->even = t; 89 | 90 | return ret; 91 | } 92 | 93 | uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) { 94 | uint8_t ret = 0; 95 | ret |= crypto1_bit(s, BIT(in, 0), is_encrypted) << 0; 96 | ret |= crypto1_bit(s, BIT(in, 1), is_encrypted) << 1; 97 | ret |= crypto1_bit(s, BIT(in, 2), is_encrypted) << 2; 98 | ret |= crypto1_bit(s, BIT(in, 3), is_encrypted) << 3; 99 | ret |= crypto1_bit(s, BIT(in, 4), is_encrypted) << 4; 100 | ret |= crypto1_bit(s, BIT(in, 5), is_encrypted) << 5; 101 | ret |= crypto1_bit(s, BIT(in, 6), is_encrypted) << 6; 102 | ret |= crypto1_bit(s, BIT(in, 7), is_encrypted) << 7; 103 | return ret; 104 | } 105 | 106 | uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) { 107 | uint32_t ret = 0; 108 | // note: xor args have been swapped because some compilers emit a warning 109 | // for 10^x and 2^x as possible misuses for exponentiation. No comment. 110 | ret |= crypto1_bit(s, BEBIT(in, 0), is_encrypted) << (24 ^ 0); 111 | ret |= crypto1_bit(s, BEBIT(in, 1), is_encrypted) << (24 ^ 1); 112 | ret |= crypto1_bit(s, BEBIT(in, 2), is_encrypted) << (24 ^ 2); 113 | ret |= crypto1_bit(s, BEBIT(in, 3), is_encrypted) << (24 ^ 3); 114 | ret |= crypto1_bit(s, BEBIT(in, 4), is_encrypted) << (24 ^ 4); 115 | ret |= crypto1_bit(s, BEBIT(in, 5), is_encrypted) << (24 ^ 5); 116 | ret |= crypto1_bit(s, BEBIT(in, 6), is_encrypted) << (24 ^ 6); 117 | ret |= crypto1_bit(s, BEBIT(in, 7), is_encrypted) << (24 ^ 7); 118 | 119 | ret |= crypto1_bit(s, BEBIT(in, 8), is_encrypted) << (24 ^ 8); 120 | ret |= crypto1_bit(s, BEBIT(in, 9), is_encrypted) << (24 ^ 9); 121 | ret |= crypto1_bit(s, BEBIT(in, 10), is_encrypted) << (24 ^ 10); 122 | ret |= crypto1_bit(s, BEBIT(in, 11), is_encrypted) << (24 ^ 11); 123 | ret |= crypto1_bit(s, BEBIT(in, 12), is_encrypted) << (24 ^ 12); 124 | ret |= crypto1_bit(s, BEBIT(in, 13), is_encrypted) << (24 ^ 13); 125 | ret |= crypto1_bit(s, BEBIT(in, 14), is_encrypted) << (24 ^ 14); 126 | ret |= crypto1_bit(s, BEBIT(in, 15), is_encrypted) << (24 ^ 15); 127 | 128 | ret |= crypto1_bit(s, BEBIT(in, 16), is_encrypted) << (24 ^ 16); 129 | ret |= crypto1_bit(s, BEBIT(in, 17), is_encrypted) << (24 ^ 17); 130 | ret |= crypto1_bit(s, BEBIT(in, 18), is_encrypted) << (24 ^ 18); 131 | ret |= crypto1_bit(s, BEBIT(in, 19), is_encrypted) << (24 ^ 19); 132 | ret |= crypto1_bit(s, BEBIT(in, 20), is_encrypted) << (24 ^ 20); 133 | ret |= crypto1_bit(s, BEBIT(in, 21), is_encrypted) << (24 ^ 21); 134 | ret |= crypto1_bit(s, BEBIT(in, 22), is_encrypted) << (24 ^ 22); 135 | ret |= crypto1_bit(s, BEBIT(in, 23), is_encrypted) << (24 ^ 23); 136 | 137 | ret |= crypto1_bit(s, BEBIT(in, 24), is_encrypted) << (24 ^ 24); 138 | ret |= crypto1_bit(s, BEBIT(in, 25), is_encrypted) << (24 ^ 25); 139 | ret |= crypto1_bit(s, BEBIT(in, 26), is_encrypted) << (24 ^ 26); 140 | ret |= crypto1_bit(s, BEBIT(in, 27), is_encrypted) << (24 ^ 27); 141 | ret |= crypto1_bit(s, BEBIT(in, 28), is_encrypted) << (24 ^ 28); 142 | ret |= crypto1_bit(s, BEBIT(in, 29), is_encrypted) << (24 ^ 29); 143 | ret |= crypto1_bit(s, BEBIT(in, 30), is_encrypted) << (24 ^ 30); 144 | ret |= crypto1_bit(s, BEBIT(in, 31), is_encrypted) << (24 ^ 31); 145 | return ret; 146 | } 147 | 148 | /* prng_successor 149 | * helper used to obscure the keystream during authentication 150 | */ 151 | uint32_t prng_successor(uint32_t x, uint32_t n) { 152 | SWAPENDIAN(x); 153 | while (n--) 154 | x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; 155 | 156 | return SWAPENDIAN(x); 157 | } 158 | 159 | int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, const uint8_t *parity) { 160 | return ( 161 | (oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \ 162 | (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \ 163 | (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0))) 164 | ) ? 1 : 0; 165 | } -------------------------------------------------------------------------------- /HardNestedSolver/hardnested/hardnested_bf_core.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2016, 2017 by piwi 3 | // 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, 5 | // at your option, any later version. See the LICENSE.txt file for the text of 6 | // the license. 7 | //----------------------------------------------------------------------------- 8 | // Implements a card only attack based on crypto text (encrypted nonces 9 | // received during a nested authentication) only. Unlike other card only 10 | // attacks this doesn't rely on implementation errors but only on the 11 | // inherent weaknesses of the crypto1 cypher. Described in 12 | // Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened 13 | // Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on 14 | // Computer and Communications Security, 2015 15 | //----------------------------------------------------------------------------- 16 | // 17 | // brute forcing is based on @aczids bitsliced brute forcer 18 | // https://github.com/aczid/crypto1_bs with some modifications. Mainly: 19 | // - don't rollback. Start with 2nd byte of nonce instead 20 | // - reuse results of filter subfunctions 21 | // - reuse results of previous nonces if some first bits are identical 22 | // 23 | //----------------------------------------------------------------------------- 24 | // aczid's Copyright notice: 25 | // 26 | // Bit-sliced Crypto-1 brute-forcing implementation 27 | // Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid) 28 | /* 29 | Copyright (c) 2015-2016 Aram Verstegen 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | */ 49 | 50 | #ifndef HARDNESTED_BF_CORE_H__ 51 | #define HARDNESTED_BF_CORE_H__ 52 | 53 | #include "hardnested_bruteforce.h" // statelist_t 54 | 55 | #if ( defined (__i386__) || defined (__x86_64__) ) && \ 56 | ( !defined(__APPLE__) || \ 57 | (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1)) ) 58 | # define COMPILER_HAS_SIMD_X86 59 | # if defined(COMPILER_HAS_SIMD_X86) && ((__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)) 60 | # define COMPILER_HAS_SIMD_AVX512 61 | # endif 62 | #endif 63 | 64 | // ARM64 mandates implementation of NEON 65 | #if defined(__arm64__) || defined(__aarch64__) 66 | #define COMPILER_HAS_SIMD_NEON 67 | #define arm_has_neon() (true) 68 | // ARMv7 or older, NEON is optional and autodetection is difficult 69 | #elif defined(__ARM_NEON) 70 | #define COMPILER_HAS_SIMD_NEON 71 | #define arm_has_neon() (false) 72 | #endif 73 | 74 | typedef enum { 75 | SIMD_AUTO, 76 | #if defined(COMPILER_HAS_SIMD_AVX512) 77 | SIMD_AVX512, 78 | #endif 79 | #if defined(COMPILER_HAS_SIMD_X86) 80 | SIMD_AVX2, 81 | SIMD_AVX, 82 | SIMD_SSE2, 83 | SIMD_MMX, 84 | #endif 85 | #if defined(COMPILER_HAS_SIMD_NEON) 86 | SIMD_NEON, 87 | #endif 88 | SIMD_NONE, 89 | } SIMDExecInstr; 90 | void SetSIMDInstr(SIMDExecInstr instr); 91 | SIMDExecInstr GetSIMDInstrAuto(void); 92 | 93 | uint64_t crack_states_bitsliced(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces); 94 | void bitslice_test_nonces(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /HardNestedSolver/hardnested/hardnested_bitarray_core.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2016, 2017 by piwi 3 | // 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, 5 | // at your option, any later version. See the LICENSE.txt file for the text of 6 | // the license. 7 | //----------------------------------------------------------------------------- 8 | // Implements a card only attack based on crypto text (encrypted nonces 9 | // received during a nested authentication) only. Unlike other card only 10 | // attacks this doesn't rely on implementation errors but only on the 11 | // inherent weaknesses of the crypto1 cypher. Described in 12 | // Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened 13 | // Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on 14 | // Computer and Communications Security, 2015 15 | //----------------------------------------------------------------------------- 16 | // 17 | // brute forcing is based on @aczids bitsliced brute forcer 18 | // https://github.com/aczid/crypto1_bs with some modifications. Mainly: 19 | // - don't rollback. Start with 2nd byte of nonce instead 20 | // - reuse results of filter subfunctions 21 | // - reuse results of previous nonces if some first bits are identical 22 | // 23 | //----------------------------------------------------------------------------- 24 | // aczid's Copyright notice: 25 | // 26 | // Bit-sliced Crypto-1 brute-forcing implementation 27 | // Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid) 28 | /* 29 | Copyright (c) 2015-2016 Aram Verstegen 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | */ 49 | 50 | #ifndef HARDNESTED_BITARRAY_CORE_H__ 51 | #define HARDNESTED_BITARRAY_CORE_H__ 52 | 53 | #include 54 | 55 | uint32_t *malloc_bitarray(uint32_t x); 56 | void free_bitarray(uint32_t *x); 57 | uint32_t bitcount(uint32_t a); 58 | uint32_t count_states(uint32_t *A); 59 | void bitarray_AND(uint32_t *A, uint32_t *B); 60 | void bitarray_low20_AND(uint32_t *A, uint32_t *B); 61 | uint32_t count_bitarray_AND(uint32_t *A, uint32_t *B); 62 | uint32_t count_bitarray_low20_AND(uint32_t *A, uint32_t *B); 63 | void bitarray_AND4(uint32_t *A, uint32_t *B, uint32_t *C, uint32_t *D); 64 | void bitarray_OR(uint32_t *A, uint32_t *B); 65 | uint32_t count_bitarray_AND2(uint32_t *A, uint32_t *B); 66 | uint32_t count_bitarray_AND3(uint32_t *A, uint32_t *B, uint32_t *C); 67 | uint32_t count_bitarray_AND4(uint32_t *A, uint32_t *B, uint32_t *C, uint32_t *D); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /HardNestedSolver/hardnested/hardnested_bruteforce.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2016, 2017 by piwi 3 | // 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, 5 | // at your option, any later version. See the LICENSE.txt file for the text of 6 | // the license. 7 | //----------------------------------------------------------------------------- 8 | // Implements a card only attack based on crypto text (encrypted nonces 9 | // received during a nested authentication) only. Unlike other card only 10 | // attacks this doesn't rely on implementation errors but only on the 11 | // inherent weaknesses of the crypto1 cypher. Described in 12 | // Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened 13 | // Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on 14 | // Computer and Communications Security, 2015 15 | //----------------------------------------------------------------------------- 16 | 17 | #ifndef HARDNESTED_BRUTEFORCE_H__ 18 | #define HARDNESTED_BRUTEFORCE_H__ 19 | 20 | #include 21 | #include 22 | 23 | #define NUM_SUMS 19 // number of possible sum property values 24 | 25 | typedef struct guess_sum_a8 { 26 | float prob; 27 | uint64_t num_states; 28 | uint16_t sum_a8_idx; 29 | } guess_sum_a8_t; 30 | 31 | typedef struct noncelistentry { 32 | uint32_t nonce_enc; 33 | uint8_t par_enc; 34 | void *next; 35 | } noncelistentry_t; 36 | 37 | typedef struct noncelist { 38 | uint16_t num; 39 | uint16_t Sum; 40 | guess_sum_a8_t sum_a8_guess[NUM_SUMS]; 41 | bool sum_a8_guess_dirty; 42 | float expected_num_brute_force; 43 | uint16_t BitFlips[0x400]; 44 | uint32_t *states_bitarray[2]; 45 | uint32_t num_states_bitarray[2]; 46 | bool all_bitflips_dirty[2]; 47 | noncelistentry_t *first; 48 | } noncelist_t; 49 | 50 | typedef struct { 51 | uint32_t *states[2]; 52 | uint32_t len[2]; 53 | void *next; 54 | } statelist_t; 55 | 56 | void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte); 57 | bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint64_t *found_key); 58 | float brute_force_benchmark(void); 59 | uint8_t trailing_zeros(uint8_t byte); 60 | bool verify_key(uint32_t cuid, noncelist_t *nonces, const uint8_t *best_first_bytes, uint32_t odd, uint32_t even); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /HardNestedSolver/hardnested/tables.h: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | 7 | /* 8 | * File: tables.h 9 | * Author: vk496 10 | * 11 | * Created on 15 de noviembre de 2018, 17:42 12 | */ 13 | 14 | #ifndef TABLES_H 15 | #define TABLES_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "../cmdhfmfhard.h" 26 | 27 | typedef struct bitflip_info { 28 | uint32_t len; 29 | uint8_t *input_buffer; 30 | } bitflip_info; 31 | 32 | typedef enum { 33 | EVEN_STATE = 0, 34 | ODD_STATE = 1 35 | } odd_even_t; 36 | 37 | 38 | bitflip_info get_bitflip(odd_even_t odd_num, uint16_t id); 39 | bool decompress(lzma_stream* strm); 40 | void lzma_init_inflate(lzma_stream *strm, uint8_t *inbuf, uint32_t inbuf_len, uint8_t *outbuf, uint32_t outbuf_len); 41 | void lzma_init_decoder(lzma_stream *strm); 42 | 43 | #endif /* TABLES_H */ 44 | 45 | -------------------------------------------------------------------------------- /HardNestedSolver/library.c: -------------------------------------------------------------------------------- 1 | #include "cmdhfmfhard.h" 2 | #include 3 | #include 4 | #include 5 | 6 | char* run_hardnested(uint32_t uid, char* path) { 7 | uint64_t foundkey = 0; 8 | if (mfnestedhard(0, 0, NULL, 0, 0, NULL, false, false, false, &foundkey, NULL, uid, path) == 1) { 9 | char* keystr = malloc(14); 10 | snprintf(keystr, 14, "%012" PRIx64 ";", foundkey); 11 | return keystr; 12 | } else { 13 | return calloc(1, 1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /HardNestedSolver/library.h: -------------------------------------------------------------------------------- 1 | #ifndef HARDNESTED_LIBRARY_H 2 | #define HARDNESTED_LIBRARY_H 3 | 4 | #include 5 | 6 | char* run_hardnested(uint32_t uid, char* path); 7 | 8 | #endif //HARDNESTED_LIBRARY_H 9 | -------------------------------------------------------------------------------- /HardNestedSolver/parity.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // Parity functions 17 | //----------------------------------------------------------------------------- 18 | 19 | // all functions defined in header file by purpose. Allows compiler optimizations. 20 | #include 21 | #ifndef __PARITY_H 22 | #define __PARITY_H 23 | #define _CRT_NONSTDC_NO_WARNINGS 24 | #define _CRT_SECURE_NO_WARNINGS 25 | #define _CRT_NON_CONFORMING_SWPRINTFS 26 | 27 | #define restrict __restrict 28 | #define inline __inline 29 | #include 30 | #include 31 | 32 | static const uint8_t g_odd_byte_parity[256] = { 33 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 34 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 35 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 36 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 37 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 38 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 39 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 40 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 41 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 42 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 43 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 44 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 45 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 46 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 47 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 48 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 49 | }; 50 | 51 | #define ODD_PARITY8(x) (g_odd_byte_parity[x]) 52 | #define EVEN_PARITY8(x) (!g_odd_byte_parity[x]) 53 | 54 | static inline uint8_t oddparity8(const uint8_t x) { 55 | return g_odd_byte_parity[x]; 56 | } 57 | 58 | static inline uint8_t evenparity8(const uint8_t x) { 59 | return !g_odd_byte_parity[x]; 60 | } 61 | 62 | static inline uint8_t evenparity16(uint16_t x) { 63 | #if !defined __GNUC__ 64 | x ^= x >> 8; 65 | return EVEN_PARITY8(x); 66 | #else 67 | return (__builtin_parity(x) & 0xFF); 68 | #endif 69 | } 70 | 71 | static inline uint8_t oddparity16(uint16_t x) { 72 | #if !defined __GNUC__ 73 | x ^= x >> 8; 74 | return ODD_PARITY8(x); 75 | #else 76 | return !__builtin_parity(x); 77 | #endif 78 | } 79 | 80 | static inline uint8_t evenparity32(uint32_t x) { 81 | #if _MSC_VER 82 | x ^= x >> 16; 83 | x ^= x >> 8; 84 | x ^= x >> 4; 85 | x &= 0xf; 86 | return (0x6996 >> x) & 1; 87 | #elif !defined __GNUC__ 88 | x ^= x >> 16; 89 | x ^= x >> 8; 90 | return EVEN_PARITY8(x); 91 | #else 92 | return (__builtin_parity(x) & 0xFF); 93 | #endif 94 | } 95 | 96 | static inline uint8_t oddparity32(uint32_t x) { 97 | #if _MSC_VER 98 | x ^= x >> 16; 99 | x ^= x >> 8; 100 | x ^= x >> 4; 101 | x &= 0xf; 102 | return ((0x6996 >> x) & 1) ^ 1; 103 | #elif !defined __GNUC__ 104 | x ^= x >> 16; 105 | x ^= x >> 8; 106 | return ODD_PARITY8(x); 107 | #else 108 | return !__builtin_parity(x); 109 | #endif 110 | } 111 | 112 | #endif /* __PARITY_H */ -------------------------------------------------------------------------------- /HardNestedSolver/pm3/ansi.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #ifndef __ANSI_H 17 | #define __ANSI_H 18 | 19 | // Not ANSI but dirty trick to specify we don't want a \n 20 | #define NOLF "\xff" 21 | 22 | #define AEND "\x1b[0m" 23 | 24 | #define _RED_(s) "\x1b[31m" s AEND 25 | #define _GREEN_(s) "\x1b[32m" s AEND 26 | #define _YELLOW_(s) "\x1b[33m" s AEND 27 | #define _BLUE_(s) "\x1b[34m" s AEND 28 | #define _CYAN_(s) "\x1b[36m" s AEND 29 | 30 | #if defined(HAVE_READLINE) 31 | // https://wiki.hackzine.org/development/misc/readline-color-prompt.html 32 | // Applications may indicate that the prompt contains 33 | // characters that take up no physical screen space when displayed by 34 | // bracketing a sequence of such characters with the special markers 35 | // RL_PROMPT_START_IGNORE = '\001' and RL_PROMPT_END_IGNORE = '\002' 36 | #define RL_ESC(a) "\001" a "\002" 37 | #else 38 | #define RL_ESC(a) a 39 | #endif // HAVE_READLINE 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/common.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // Interlib Definitions 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef __COMMON_H 20 | #define __COMMON_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include "util.h" // FILE_PATH_SIZE 26 | 27 | #ifdef _WIN32 28 | #define ABOVE "../" 29 | #define PATHSEP "/" 30 | #else 31 | #define ABOVE "../" 32 | #define PATHSEP "/" 33 | #endif 34 | 35 | #ifndef MIN 36 | # define MIN(a, b) (((a) < (b)) ? (a) : (b)) 37 | #endif 38 | 39 | #ifndef MAX 40 | # define MAX(a, b) (((a) > (b)) ? (a) : (b)) 41 | #endif 42 | 43 | #ifndef ABS 44 | # define ABS(a) ( ((a)<0) ? -(a) : (a) ) 45 | #endif 46 | 47 | #ifndef ROTR 48 | # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) 49 | #endif 50 | 51 | #ifndef PM3_ROTL 52 | # define PM3_ROTL(x,n) (((uintmax_t)(x) << (n)) | ((uintmax_t)(x) >> ((sizeof(x) * 8) - (n)))) 53 | #endif 54 | 55 | // endian change for 64bit 56 | #ifdef __GNUC__ 57 | #ifndef BSWAP_64 58 | #define BSWAP_64(x) __builtin_bswap64(x) 59 | #endif 60 | #else 61 | #ifdef _MSC_VER 62 | #ifndef BSWAP_64 63 | #define BSWAP_64(x) _byteswap_uint64(x) 64 | #endif 65 | #else 66 | #ifndef BSWAP_64 67 | #define BSWAP_64(x) \ 68 | (((uint64_t)(x) << 56) | \ 69 | (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ 70 | (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ 71 | (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ 72 | (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ 73 | (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ 74 | (((uint64_t)(x) >> 40) & 0xff00ULL) | \ 75 | ((uint64_t)(x) >> 56)) 76 | #endif 77 | #endif 78 | #endif 79 | 80 | // endian change for 32bit 81 | #ifdef __GNUC__ 82 | #ifndef BSWAP_32 83 | #define BSWAP_32(x) __builtin_bswap32(x) 84 | #endif 85 | #else 86 | #ifdef _MSC_VER 87 | #ifndef BSWAP_32 88 | #define BSWAP_32(x) _byteswap_ulong(x) 89 | #endif 90 | #else 91 | #ifndef BSWAP_32 92 | # define BSWAP_32(x) \ 93 | ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ 94 | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) 95 | #endif 96 | #endif 97 | #endif 98 | 99 | // convert 2 bytes to U16 in little endian 100 | #ifndef BYTES2UINT16 101 | # define BYTES2UINT16(x) ((x[1] << 8) | (x[0])) 102 | #endif 103 | // convert 4 bytes to U32 in little endian 104 | #ifndef BYTES2UINT32 105 | # define BYTES2UINT32(x) ((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0])) 106 | #endif 107 | 108 | // convert 4 bytes to U32 in big endian 109 | #ifndef BYTES2UINT32_BE 110 | # define BYTES2UINT32_BE(x) ((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])) 111 | #endif 112 | 113 | 114 | #define EVEN 0 115 | #define ODD 1 116 | 117 | // Nibble logic 118 | #ifndef NIBBLE_HIGH 119 | # define NIBBLE_HIGH(b) ( ((b) & 0xF0) >> 4 ) 120 | #endif 121 | 122 | #ifndef NIBBLE_LOW 123 | # define NIBBLE_LOW(b) ((b) & 0x0F ) 124 | #endif 125 | 126 | #ifndef CRUMB 127 | # define CRUMB(b,p) (((b & (0x3 << p) ) >> p ) & 0xF) 128 | #endif 129 | 130 | #ifndef SWAP_NIBBLE 131 | # define SWAP_NIBBLE(b) ( (NIBBLE_LOW(b)<< 4) | NIBBLE_HIGH(b)) 132 | #endif 133 | #endif 134 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/commonutil.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // Utility functions used in many places, not specific to any piece of code. 17 | //----------------------------------------------------------------------------- 18 | #include "commonutil.h" 19 | 20 | uint64_t bytes_to_num(uint8_t *src, size_t len) { 21 | uint64_t num = 0; 22 | while (len--) { 23 | num = (num << 8) | (*src); 24 | src++; 25 | } 26 | return num; 27 | } -------------------------------------------------------------------------------- /HardNestedSolver/pm3/commonutil.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // Utility functions used in many places, not specific to any piece of code. 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef __COMMONUTIL_H 20 | #define __COMMONUTIL_H 21 | 22 | #include "common.h" 23 | 24 | // endian change for 16bit 25 | #ifdef __GNUC__ 26 | #ifndef BSWAP_16 27 | #define BSWAP_16(x) __builtin_bswap16(x) 28 | #endif 29 | #else 30 | #ifdef _MSC_VER 31 | #ifndef BSWAP_16 32 | #define BSWAP_16(x) _byteswap_ushort(x) 33 | #endif 34 | #else 35 | #ifndef BSWAP_16 36 | # define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8))) 37 | #endif 38 | #endif 39 | #endif 40 | 41 | #ifndef BITMASK 42 | # define BITMASK(X) (1 << (X)) 43 | #endif 44 | #ifndef ARRAYLEN 45 | # define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) 46 | #endif 47 | 48 | #ifndef NTIME 49 | # define NTIME(n) for (int _index = 0; _index < n; _index++) 50 | #endif 51 | 52 | uint64_t bytes_to_num(uint8_t *src, size_t len); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/emojis_alt.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #ifndef EMOJIS_ALT_H__ 17 | #define EMOJIS_ALT_H__ 18 | 19 | typedef struct emoji_alt_s { 20 | const char *alias; 21 | const char *alttext; 22 | } emoji_alt_t; 23 | // emoji_alt_t array are expected to be NULL terminated 24 | 25 | static emoji_alt_t EmojiAltTable[] = { 26 | {":wink:", ";)"}, 27 | {NULL, NULL} 28 | }; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/ui.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // UI utilities 17 | //----------------------------------------------------------------------------- 18 | 19 | /* Ensure strtok_r is available even with -std=c99; must be included before 20 | */ 21 | 22 | #include "ui.h" 23 | #include "commonutil.h" // ARRAYLEN 24 | #include // for Mingw readline 25 | #include 26 | #include 27 | 28 | #if defined(HAVE_READLINE) 29 | //Load readline after stdio.h 30 | #include 31 | #endif 32 | 33 | #include "util.h" 34 | 35 | #if defined(_WIN32) || defined(_WIN64) 36 | # include // _mkdir 37 | #endif 38 | 39 | #include "emojis.h" 40 | #include "emojis_alt.h" 41 | #include 42 | 43 | session_arg_t g_session; 44 | 45 | static bool flushAfterWrite = true; 46 | static void fPrintAndLog(FILE *stream, const char *fmt, ...); 47 | 48 | #if defined(_WIN32) || defined(_WIN64) 49 | #define MKDIR_CHK _mkdir(path) 50 | #define STRTOK strtok_s 51 | #else 52 | #define MKDIR_CHK mkdir(path, 0700) 53 | #define STRTOK strtok_r 54 | #endif 55 | 56 | static uint8_t PrintAndLogEx_spinidx = 0; 57 | 58 | void PrintAndLogEx(logLevel_t level, const char *fmt, ...) { 59 | 60 | // skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG -0' 61 | if (g_debugMode == 0 && level == DEBUG) 62 | return; 63 | 64 | // skip HINT messages if client has hints turned off i.e. 'HINT 0' 65 | if (g_session.show_hints == false && level == HINT) 66 | return; 67 | 68 | char prefix[40] = {0}; 69 | char buffer[MAX_PRINT_BUFFER] = {0}; 70 | char buffer2[MAX_PRINT_BUFFER + sizeof(prefix)] = {0}; 71 | char *token = NULL; 72 | char *tmp_ptr = NULL; 73 | FILE *stream = stdout; 74 | const char *spinner[] = {_YELLOW_("[\\]"), _YELLOW_("[|]"), _YELLOW_("[/]"), _YELLOW_("[-]")}; 75 | const char *spinner_emoji[] = {" :clock1: ", " :clock2: ", " :clock3: ", " :clock4: ", " :clock5: ", " :clock6: ", 76 | " :clock7: ", " :clock8: ", " :clock9: ", " :clock10: ", " :clock11: ", 77 | " :clock12: "}; 78 | switch (level) { 79 | case ERR: 80 | if (g_session.emoji_mode == EMO_EMOJI) 81 | strncpy(prefix, "[" _RED_("!!") "] :rotating_light: ", sizeof(prefix) - 1); 82 | else 83 | strncpy(prefix, "[" _RED_("!!") "] ", sizeof(prefix) - 1); 84 | stream = stderr; 85 | break; 86 | case FAILED: 87 | if (g_session.emoji_mode == EMO_EMOJI) 88 | strncpy(prefix, "[" _RED_("-") "] :no_entry: ", sizeof(prefix) - 1); 89 | else 90 | strncpy(prefix, "[" _RED_("-") "] ", sizeof(prefix) - 1); 91 | break; 92 | case DEBUG: 93 | strncpy(prefix, "[" _BLUE_("#") "] ", sizeof(prefix) - 1); 94 | break; 95 | case HINT: 96 | strncpy(prefix, "[" _YELLOW_("?") "] ", sizeof(prefix) - 1); 97 | break; 98 | case SUCCESS: 99 | strncpy(prefix, "[" _GREEN_("+") "] ", sizeof(prefix) - 1); 100 | break; 101 | case WARNING: 102 | if (g_session.emoji_mode == EMO_EMOJI) 103 | strncpy(prefix, "[" _CYAN_("!") "] :warning: ", sizeof(prefix) - 1); 104 | else 105 | strncpy(prefix, "[" _CYAN_("!") "] ", sizeof(prefix) - 1); 106 | break; 107 | case INFO: 108 | strncpy(prefix, "[" _YELLOW_("=") "] ", sizeof(prefix) - 1); 109 | break; 110 | case INPLACE: 111 | if (g_session.emoji_mode == EMO_EMOJI) { 112 | strncpy(prefix, spinner_emoji[PrintAndLogEx_spinidx], sizeof(prefix) - 1); 113 | PrintAndLogEx_spinidx++; 114 | if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner_emoji)) 115 | PrintAndLogEx_spinidx = 0; 116 | } else { 117 | strncpy(prefix, spinner[PrintAndLogEx_spinidx], sizeof(prefix) - 1); 118 | PrintAndLogEx_spinidx++; 119 | if (PrintAndLogEx_spinidx >= ARRAYLEN(spinner)) 120 | PrintAndLogEx_spinidx = 0; 121 | } 122 | break; 123 | case NORMAL: 124 | // no prefixes for normal 125 | break; 126 | } 127 | 128 | va_list args; 129 | va_start(args, fmt); 130 | vsnprintf(buffer, sizeof(buffer), fmt, args); 131 | va_end(args); 132 | 133 | // no prefixes for normal & inplace 134 | if (level == NORMAL) { 135 | fPrintAndLog(stream, "%s", buffer); 136 | return; 137 | } 138 | 139 | if (strchr(buffer, '\n')) { 140 | 141 | const char delim[2] = "\n"; 142 | 143 | // line starts with newline 144 | if (buffer[0] == '\n') 145 | fPrintAndLog(stream, ""); 146 | 147 | token = STRTOK(buffer, delim, &tmp_ptr); 148 | 149 | while (token != NULL) { 150 | 151 | size_t size = strlen(buffer2); 152 | 153 | if (strlen(token)) 154 | snprintf(buffer2 + size, sizeof(buffer2) - size, "%s%s\n", prefix, token); 155 | else 156 | snprintf(buffer2 + size, sizeof(buffer2) - size, "\n"); 157 | 158 | token = STRTOK(NULL, delim, &tmp_ptr); 159 | } 160 | fPrintAndLog(stream, "%s", buffer2); 161 | } else { 162 | snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); 163 | if (level == INPLACE) { 164 | char buffer3[sizeof(buffer2)] = {0}; 165 | char buffer4[sizeof(buffer2)] = {0}; 166 | memcpy_filter_ansi(buffer3, buffer2, sizeof(buffer2), !g_session.supports_colors); 167 | memcpy_filter_emoji(buffer4, buffer3, sizeof(buffer3), g_session.emoji_mode); 168 | fprintf(stream, "\r%s", buffer4); 169 | fflush(stream); 170 | } else { 171 | fPrintAndLog(stream, "%s", buffer2); 172 | } 173 | } 174 | } 175 | 176 | static void fPrintAndLog(FILE *stream, const char *fmt, ...) { 177 | va_list argptr; 178 | static FILE *logfile = NULL; 179 | static int logging = 1; 180 | char buffer[MAX_PRINT_BUFFER] = {0}; 181 | char buffer2[MAX_PRINT_BUFFER] = {0}; 182 | char buffer3[MAX_PRINT_BUFFER] = {0}; 183 | // lock this section to avoid interlacing prints from different threads 184 | bool linefeed = true; 185 | 186 | logging = 0; 187 | 188 | 189 | // If there is an incoming message from the hardware (eg: lf hid read) in 190 | // the background (while the prompt is displayed and accepting user input), 191 | // stash the prompt and bring it back later. 192 | #ifdef RL_STATE_READCMD 193 | // We are using GNU readline. libedit (OSX) doesn't support this flag. 194 | int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0; 195 | char *saved_line; 196 | int saved_point; 197 | 198 | if (need_hack) { 199 | saved_point = rl_point; 200 | saved_line = rl_copy_text(0, rl_end); 201 | rl_save_prompt(); 202 | rl_replace_line("", 0); 203 | rl_redisplay(); 204 | } 205 | #endif 206 | 207 | va_start(argptr, fmt); 208 | vsnprintf(buffer, sizeof(buffer), fmt, argptr); 209 | va_end(argptr); 210 | if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == NOLF[0]) { 211 | linefeed = false; 212 | buffer[strlen(buffer) - 1] = 0; 213 | } 214 | bool filter_ansi = !g_session.supports_colors; 215 | memcpy_filter_ansi(buffer2, buffer, sizeof(buffer), filter_ansi); 216 | if (g_printAndLog & PRINTANDLOG_PRINT) { 217 | memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), g_session.emoji_mode); 218 | fprintf(stream, "%s", buffer3); 219 | if (linefeed) 220 | fprintf(stream, "\n"); 221 | } 222 | 223 | #ifdef RL_STATE_READCMD 224 | // We are using GNU readline. libedit (OSX) doesn't support this flag. 225 | if (need_hack) { 226 | rl_restore_prompt(); 227 | rl_replace_line(saved_line, 0); 228 | rl_point = saved_point; 229 | rl_redisplay(); 230 | free(saved_line); 231 | } 232 | #endif 233 | 234 | if ((g_printAndLog & PRINTANDLOG_LOG) && logging && logfile) { 235 | memcpy_filter_emoji(buffer3, buffer2, sizeof(buffer2), EMO_ALTTEXT); 236 | if (filter_ansi) { // already done 237 | fprintf(logfile, "%s", buffer3); 238 | } else { 239 | memcpy_filter_ansi(buffer, buffer3, sizeof(buffer3), true); 240 | fprintf(logfile, "%s", buffer); 241 | } 242 | if (linefeed) 243 | fprintf(logfile, "\n"); 244 | fflush(logfile); 245 | } 246 | 247 | if (flushAfterWrite) 248 | fflush(stdout); 249 | } 250 | 251 | void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter) { 252 | if (filter) { 253 | // Filter out ANSI sequences on these OS 254 | uint8_t *rdest = (uint8_t *) dest; 255 | uint8_t *rsrc = (uint8_t *) src; 256 | uint16_t si = 0; 257 | for (size_t i = 0; i < n; i++) { 258 | if ((i < n - 1) && (rsrc[i] == '\x1b') && (rsrc[i + 1] >= 0x40) && 259 | (rsrc[i + 1] <= 0x5F)) { // entering ANSI sequence 260 | 261 | i++; 262 | if ((i < n - 1) && (rsrc[i] == '[')) { // entering CSI sequence 263 | i++; 264 | 265 | while ((i < n - 1) && (rsrc[i] >= 0x30) && (rsrc[i] <= 0x3F)) { // parameter bytes 266 | i++; 267 | } 268 | 269 | while ((i < n - 1) && (rsrc[i] >= 0x20) && (rsrc[i] <= 0x2F)) { // intermediate bytes 270 | i++; 271 | } 272 | 273 | if ((rsrc[i] >= 0x40) && (rsrc[i] <= 0x7F)) { // final byte 274 | continue; 275 | } 276 | } else { 277 | continue; 278 | } 279 | } 280 | rdest[si++] = rsrc[i]; 281 | } 282 | } else { 283 | memcpy(dest, src, n); 284 | } 285 | } 286 | 287 | static bool 288 | emojify_token(const char *token, uint8_t token_length, const char **emojified_token, uint8_t *emojified_token_length, 289 | emojiMode_t mode) { 290 | int i = 0; 291 | while (EmojiTable[i].alias && EmojiTable[i].emoji) { 292 | if ((strlen(EmojiTable[i].alias) == token_length) && (0 == memcmp(EmojiTable[i].alias, token, token_length))) { 293 | switch (mode) { 294 | case EMO_EMOJI: { 295 | *emojified_token = EmojiTable[i].emoji; 296 | *emojified_token_length = strlen(EmojiTable[i].emoji); 297 | break; 298 | } 299 | case EMO_ALTTEXT: { 300 | int j = 0; 301 | *emojified_token_length = 0; 302 | while (EmojiAltTable[j].alias && EmojiAltTable[j].alttext) { 303 | if ((strlen(EmojiAltTable[j].alias) == token_length) && 304 | (0 == memcmp(EmojiAltTable[j].alias, token, token_length))) { 305 | *emojified_token = EmojiAltTable[j].alttext; 306 | *emojified_token_length = strlen(EmojiAltTable[j].alttext); 307 | break; 308 | } 309 | ++j; 310 | } 311 | break; 312 | } 313 | case EMO_NONE: { 314 | *emojified_token_length = 0; 315 | break; 316 | } 317 | case EMO_ALIAS: { // should never happen 318 | return false; 319 | } 320 | } 321 | return true; 322 | } 323 | ++i; 324 | } 325 | return false; 326 | } 327 | 328 | static bool token_charset(uint8_t c) { 329 | if ((c >= '0') && (c <= '9')) return true; 330 | if ((c >= 'a') && (c <= 'z')) return true; 331 | if ((c >= 'A') && (c <= 'Z')) return true; 332 | if ((c == '_') || (c == '+') || (c == '-')) return true; 333 | return false; 334 | } 335 | 336 | void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode) { 337 | if (mode == EMO_ALIAS) { 338 | memcpy(dest, src, n); 339 | } else { 340 | // tokenize emoji 341 | const char *emojified_token = NULL; 342 | uint8_t emojified_token_length = 0; 343 | char *current_token = NULL; 344 | uint8_t current_token_length = 0; 345 | char *rdest = (char *) dest; 346 | char *rsrc = (char *) src; 347 | uint16_t si = 0; 348 | for (size_t i = 0; i < n; i++) { 349 | char current_char = rsrc[i]; 350 | 351 | if (current_token_length == 0) { 352 | // starting a new token. 353 | if (current_char == ':') { 354 | current_token = rsrc + i; 355 | current_token_length = 1; 356 | } else { // not starting a new token. 357 | rdest[si++] = current_char; 358 | } 359 | } else { 360 | // finishing the current token. 361 | if (current_char == ':') { 362 | // nothing changed? we still need the ending ':' as it might serve for an upcoming emoji 363 | if (!emojify_token(current_token, current_token_length + 1, &emojified_token, 364 | &emojified_token_length, mode)) { 365 | memcpy(rdest + si, current_token, current_token_length); 366 | si += current_token_length; 367 | current_token = rsrc + i; 368 | current_token_length = 1; 369 | } else { 370 | memcpy(rdest + si, emojified_token, emojified_token_length); 371 | si += emojified_token_length; 372 | current_token_length = 0; 373 | } 374 | } else if (token_charset(current_char)) { // continuing the current token. 375 | current_token_length++; 376 | } else { // dropping the current token. 377 | current_token_length++; 378 | memcpy(rdest + si, current_token, current_token_length); 379 | si += current_token_length; 380 | current_token_length = 0; 381 | } 382 | } 383 | } 384 | if (current_token_length > 0) { 385 | memcpy(rdest + si, current_token, current_token_length); 386 | } 387 | } 388 | } -------------------------------------------------------------------------------- /HardNestedSolver/pm3/ui.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // UI utilities 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef UI_H__ 20 | #define UI_H__ 21 | 22 | #include "common.h" 23 | #include "../pm3/ansi.h" 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #define _USE_MATH_DEFINES 30 | 31 | typedef enum {STYLE_BAR, STYLE_MIXED, STYLE_VALUE} barMode_t; 32 | typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG, INPLACE, HINT} logLevel_t; 33 | typedef enum emojiMode {EMO_ALIAS, EMO_EMOJI, EMO_ALTTEXT, EMO_NONE} emojiMode_t; 34 | typedef enum clientdebugLevel {cdbOFF, cdbSIMPLE, cdbFULL} clientdebugLevel_t; 35 | // typedef enum devicedebugLevel {ddbOFF, ddbERROR, ddbINFO, ddbDEBUG, ddbEXTENDED} devicedebugLevel_t; 36 | 37 | // last item spItemCount used to auto map to number of files 38 | typedef enum savePaths {spDefault, spDump, spTrace, spItemCount} savePaths_t; 39 | typedef struct {int x; int y; int h; int w;} qtWindow_t; 40 | 41 | typedef struct { 42 | bool preferences_loaded; 43 | bool stdinOnTTY; 44 | bool stdoutOnTTY; 45 | bool supports_colors; 46 | emojiMode_t emoji_mode; 47 | bool pm3_present; 48 | bool help_dump_mode; 49 | bool show_hints; 50 | bool dense_output; 51 | bool window_changed; // track if plot/overlay pos/size changed to save on exit 52 | qtWindow_t plot; 53 | qtWindow_t overlay; 54 | bool overlay_sliders; 55 | bool incognito; 56 | char *defaultPaths[spItemCount]; // Array should allow loop searching for files 57 | clientdebugLevel_t client_debug_level; 58 | barMode_t bar_mode; 59 | // uint8_t device_debug_level; 60 | uint16_t client_exe_delay; 61 | char *history_path; 62 | } session_arg_t; 63 | 64 | extern session_arg_t g_session; 65 | #ifndef M_PI 66 | #define M_PI 3.14159265358979323846264338327 67 | #endif 68 | #define MAX_PRINT_BUFFER 2048 69 | 70 | void PrintAndLogEx(logLevel_t level, const char *fmt, ...); 71 | void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter); 72 | void memcpy_filter_emoji(void *dest, const void *src, size_t n, emojiMode_t mode); 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | #endif 78 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/util.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // utilities 17 | //----------------------------------------------------------------------------- 18 | 19 | #include "util.h" 20 | 21 | // global client debug variable 22 | uint8_t g_debugMode = 0; 23 | // global client disable logging variable 24 | uint8_t g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; 25 | // global client tell if a pending prompt is present 26 | 27 | #ifdef _WIN32 28 | #include 29 | #else 30 | #include 31 | #endif 32 | 33 | // determine number of logical CPU cores (use for multithreaded functions) 34 | int num_CPUs(void) { 35 | #if defined(_WIN32) 36 | #include 37 | SYSTEM_INFO sysinfo; 38 | GetSystemInfo(&sysinfo); 39 | return sysinfo.dwNumberOfProcessors; 40 | #else 41 | int count = sysconf(_SC_NPROCESSORS_ONLN); 42 | if (count <= 0) 43 | count = 1; 44 | return count; 45 | #endif 46 | } 47 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/util.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // utilities 17 | //----------------------------------------------------------------------------- 18 | #ifndef __UTIL_H_ 19 | #define __UTIL_H_ 20 | 21 | #include "common.h" 22 | 23 | #ifdef ANDROID 24 | #include 25 | #endif 26 | 27 | // used for save/load files 28 | #ifndef FILE_PATH_SIZE 29 | # define FILE_PATH_SIZE 1000 30 | #endif 31 | 32 | extern uint8_t g_debugMode; 33 | extern uint8_t g_printAndLog; 34 | 35 | #define PRINTANDLOG_PRINT 1 36 | #define PRINTANDLOG_LOG 2 37 | 38 | int num_CPUs(void); // number of logical CPUs 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/util_posix.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // utilities requiring Posix library functions 17 | //----------------------------------------------------------------------------- 18 | 19 | // ensure availability even with -std=c99; must be included before 20 | #if !defined(_WIN32) 21 | //#define _POSIX_C_SOURCE 199309L // need nanosleep() 22 | #define _POSIX_C_SOURCE 200112L // need localtime_r() 23 | #else 24 | #include 25 | #endif 26 | 27 | #include "util_posix.h" 28 | #include 29 | #include 30 | 31 | 32 | // Timer functions 33 | #if !defined (_WIN32) 34 | #include 35 | 36 | static void nsleep(uint64_t n) { 37 | struct timespec timeout; 38 | timeout.tv_sec = n / 1000000000; 39 | timeout.tv_nsec = n % 1000000000; 40 | while (nanosleep(&timeout, &timeout) && errno == EINTR); 41 | } 42 | 43 | void msleep(uint32_t n) { 44 | nsleep(1000000 * (uint64_t)n); 45 | } 46 | #endif // _WIN32 47 | 48 | #ifdef __APPLE__ 49 | 50 | #ifndef CLOCK_MONOTONIC 51 | #define CLOCK_MONOTONIC (1) 52 | #endif 53 | #ifndef CLOCK_REALTIME 54 | #define CLOCK_REALTIME (2) 55 | #endif 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | 62 | /* clock_gettime is not implemented on OSX prior to 10.12 */ 63 | int _civet_clock_gettime(int clk_id, struct timespec *t); 64 | 65 | int _civet_clock_gettime(int clk_id, struct timespec *t) { 66 | memset(t, 0, sizeof(*t)); 67 | if (clk_id == CLOCK_REALTIME) { 68 | struct timeval now; 69 | int rv = gettimeofday(&now, NULL); 70 | if (rv) { 71 | return rv; 72 | } 73 | t->tv_sec = now.tv_sec; 74 | t->tv_nsec = now.tv_usec * 1000; 75 | return 0; 76 | 77 | } else if (clk_id == CLOCK_MONOTONIC) { 78 | static uint64_t clock_start_time = 0; 79 | static mach_timebase_info_data_t timebase_info = {0, 0}; 80 | 81 | uint64_t now = mach_absolute_time(); 82 | 83 | if (clock_start_time == 0) { 84 | 85 | mach_timebase_info(&timebase_info); 86 | clock_start_time = now; 87 | } 88 | 89 | now = (uint64_t)((double)(now - clock_start_time) 90 | * (double)timebase_info.numer 91 | / (double)timebase_info.denom); 92 | 93 | t->tv_sec = now / 1000000000; 94 | t->tv_nsec = now % 1000000000; 95 | return 0; 96 | } 97 | return -1; // EINVAL - Clock ID is unknown 98 | } 99 | 100 | /* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */ 101 | #ifdef __CLOCK_AVAILABILITY 102 | /* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared 103 | * but it may be NULL at runtime. So we need to check before using it. */ 104 | int _civet_safe_clock_gettime(int clk_id, struct timespec *t); 105 | 106 | int _civet_safe_clock_gettime(int clk_id, struct timespec *t) { 107 | if (clock_gettime) { 108 | return clock_gettime(clk_id, t); 109 | } 110 | return _civet_clock_gettime(clk_id, t); 111 | } 112 | #define clock_gettime _civet_safe_clock_gettime 113 | #else 114 | #define clock_gettime _civet_clock_gettime 115 | #endif 116 | 117 | #endif 118 | 119 | 120 | // a milliseconds timer for performance measurement 121 | uint64_t msclock(void) { 122 | #if defined(_WIN32) 123 | LARGE_INTEGER count, frequency; 124 | if (!QueryPerformanceFrequency(&frequency)) { 125 | // Handle error 126 | return 0; 127 | } 128 | if (!QueryPerformanceCounter(&count)) { 129 | // Handle error 130 | return 0; 131 | } 132 | return (count.QuadPart * 1000) / frequency.QuadPart; 133 | #else 134 | struct timespec t; 135 | clock_gettime(CLOCK_MONOTONIC, &t); 136 | return (1000 * (uint64_t)t.tv_sec + t.tv_nsec / 1000000); 137 | #endif 138 | } 139 | 140 | -------------------------------------------------------------------------------- /HardNestedSolver/pm3/util_posix.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // utilities requiring Posix library functions 17 | //----------------------------------------------------------------------------- 18 | 19 | #ifndef UTIL_POSIX_H__ 20 | #define UTIL_POSIX_H__ 21 | 22 | #include "common.h" 23 | 24 | #ifdef _WIN32 25 | # include 26 | # define sleep(n) Sleep(1000 *(n)) 27 | # define msleep(n) Sleep((n)) 28 | #else 29 | void msleep(uint32_t n); // sleep n milliseconds 30 | #endif // _WIN32 31 | 32 | uint64_t msclock(void); // a milliseconds clock 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /HardNestedSolver/python.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "library.h" 3 | 4 | static PyObject *run_hardnested_python(PyObject *self, PyObject *args) { 5 | uint64_t uid; 6 | char* path; 7 | if (!PyArg_ParseTuple(args, "ks", &uid, &path)) { 8 | return NULL; 9 | } 10 | 11 | char *output = run_hardnested(uid, path); 12 | 13 | return Py_BuildValue("s", output); 14 | } 15 | 16 | static PyMethodDef hardnested_methods[] = {{"run_hardnested", run_hardnested_python, METH_VARARGS, "Run hardnested"}, 17 | {NULL, NULL, 0, NULL} /* Sentinel */ 18 | }; 19 | 20 | static struct PyModuleDef hardnested_module = {PyModuleDef_HEAD_INIT, "hardnested", NULL, -1, hardnested_methods}; 21 | 22 | PyMODINIT_FUNC PyInit_hardnested(void) { 23 | return PyModule_Create(&hardnested_module); 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft NestedSolver 2 | graft HardNestedSolver -------------------------------------------------------------------------------- /NestedSolver/bucketsort.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #include "bucketsort.h" 17 | 18 | extern void bucket_sort_intersect(uint32_t *const estart, uint32_t *const estop, 19 | uint32_t *const ostart, uint32_t *const ostop, 20 | bucket_info_t *bucket_info, bucket_array_t bucket) { 21 | uint32_t *p1, *p2; 22 | uint32_t *start[2]; 23 | uint32_t *stop[2]; 24 | 25 | start[0] = estart; 26 | stop[0] = estop; 27 | start[1] = ostart; 28 | stop[1] = ostop; 29 | 30 | // init buckets to be empty 31 | for (uint32_t i = 0; i < 2; i++) { 32 | for (uint32_t j = 0x00; j <= 0xff; j++) { 33 | bucket[i][j].bp = bucket[i][j].head; 34 | } 35 | } 36 | 37 | // sort the lists into the buckets based on the MSB (contribution bits) 38 | for (uint32_t i = 0; i < 2; i++) { 39 | for (p1 = start[i]; p1 <= stop[i]; p1++) { 40 | uint32_t bucket_index = (*p1 & 0xff000000) >> 24; 41 | *(bucket[i][bucket_index].bp++) = *p1; 42 | } 43 | } 44 | 45 | // write back intersecting buckets as sorted list. 46 | // fill in bucket_info with head and tail of the bucket contents in the list and number of non-empty buckets. 47 | for (uint32_t i = 0; i < 2; i++) { 48 | p1 = start[i]; 49 | uint32_t nonempty_bucket = 0; 50 | for (uint32_t j = 0x00; j <= 0xff; j++) { 51 | if (bucket[0][j].bp != bucket[0][j].head && bucket[1][j].bp != bucket[1][j].head) { // non-empty intersecting buckets only 52 | bucket_info->bucket_info[i][nonempty_bucket].head = p1; 53 | for (p2 = bucket[i][j].head; p2 < bucket[i][j].bp; *p1++ = *p2++); 54 | bucket_info->bucket_info[i][nonempty_bucket].tail = p1 - 1; 55 | nonempty_bucket++; 56 | } 57 | } 58 | bucket_info->numbuckets = nonempty_bucket; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /NestedSolver/bucketsort.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | #ifndef BUCKETSORT_H__ 17 | #define BUCKETSORT_H__ 18 | #include 19 | #include 20 | 21 | typedef struct bucket { 22 | uint32_t *head; 23 | uint32_t *bp; 24 | } bucket_t; 25 | 26 | typedef bucket_t bucket_array_t[2][0x100]; 27 | 28 | typedef struct bucket_info { 29 | struct { 30 | uint32_t *head, *tail; 31 | } bucket_info[2][0x100]; 32 | uint32_t numbuckets; 33 | } bucket_info_t; 34 | 35 | void bucket_sort_intersect(uint32_t *const estart, uint32_t *const estop, 36 | uint32_t *const ostart, uint32_t *const ostop, 37 | bucket_info_t *bucket_info, bucket_array_t bucket); 38 | 39 | #endif -------------------------------------------------------------------------------- /NestedSolver/crapto1.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #include "crapto1.h" 18 | 19 | #include "bucketsort.h" 20 | 21 | #include 22 | #include "parity.h" 23 | 24 | /** update_contribution 25 | * helper, calculates the partial linear feedback contributions and puts in MSB 26 | */ 27 | static inline void update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) { 28 | uint32_t p = *item >> 25; 29 | 30 | p = p << 1 | (evenparity32(*item & mask1)); 31 | p = p << 1 | (evenparity32(*item & mask2)); 32 | *item = p << 24 | (*item & 0xffffff); 33 | } 34 | 35 | /** extend_table 36 | * using a bit of the keystream extend the table of possible lfsr states 37 | */ 38 | static inline void extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) { 39 | in <<= 24; 40 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) 41 | if (filter(*tbl) ^ filter(*tbl | 1)) { 42 | *tbl |= filter(*tbl) ^ bit; 43 | update_contribution(tbl, m1, m2); 44 | *tbl ^= in; 45 | } else if (filter(*tbl) == bit) { 46 | *++*end = tbl[1]; 47 | tbl[1] = tbl[0] | 1; 48 | update_contribution(tbl, m1, m2); 49 | *tbl++ ^= in; 50 | update_contribution(tbl, m1, m2); 51 | *tbl ^= in; 52 | } else 53 | *tbl-- = *(*end)--; 54 | } 55 | /** extend_table_simple 56 | * using a bit of the keystream extend the table of possible lfsr states 57 | */ 58 | static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) { 59 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) { 60 | if (filter(*tbl) ^ filter(*tbl | 1)) { // replace 61 | *tbl |= filter(*tbl) ^ bit; 62 | } else if (filter(*tbl) == bit) { // insert 63 | *++*end = *++tbl; 64 | *tbl = tbl[-1] | 1; 65 | } else { // drop 66 | *tbl-- = *(*end)--; 67 | } 68 | } 69 | } 70 | /** recover 71 | * recursively narrow down the search space, 4 bits of keystream at a time 72 | */ 73 | static struct Crypto1State * 74 | recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, 75 | uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, 76 | struct Crypto1State *sl, uint32_t in, bucket_array_t bucket) { 77 | bucket_info_t bucket_info; 78 | 79 | if (rem == -1) { 80 | for (uint32_t *e = e_head; e <= e_tail; ++e) { 81 | *e = *e << 1 ^ (evenparity32(*e & LF_POLY_EVEN)) ^ (!!(in & 4)); 82 | for (uint32_t *o = o_head; o <= o_tail; ++o, ++sl) { 83 | sl->even = *o; 84 | sl->odd = *e ^ (evenparity32(*o & LF_POLY_ODD)); 85 | sl[1].odd = sl[1].even = 0; 86 | } 87 | } 88 | return sl; 89 | } 90 | 91 | for (uint32_t i = 0; i < 4 && rem--; i++) { 92 | oks >>= 1; 93 | eks >>= 1; 94 | in >>= 2; 95 | extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); 96 | if (o_head > o_tail) 97 | return sl; 98 | 99 | extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, in & 3); 100 | if (e_head > e_tail) 101 | return sl; 102 | } 103 | 104 | bucket_sort_intersect(e_head, e_tail, o_head, o_tail, &bucket_info, bucket); 105 | 106 | for (int i = bucket_info.numbuckets - 1; i >= 0; i--) { 107 | sl = recover(bucket_info.bucket_info[1][i].head, bucket_info.bucket_info[1][i].tail, oks, 108 | bucket_info.bucket_info[0][i].head, bucket_info.bucket_info[0][i].tail, eks, 109 | rem, sl, in, bucket); 110 | } 111 | 112 | return sl; 113 | } 114 | 115 | 116 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() 117 | /** lfsr_recovery 118 | * recover the state of the lfsr given 32 bits of the keystream 119 | * additionally you can use the in parameter to specify the value 120 | * that was fed into the lfsr at the time the keystream was generated 121 | */ 122 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in) { 123 | struct Crypto1State *statelist; 124 | uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; 125 | uint32_t *even_head = 0, *even_tail = 0, eks = 0; 126 | int i; 127 | 128 | // split the keystream into an odd and even part 129 | for (i = 31; i >= 0; i -= 2) 130 | oks = oks << 1 | BEBIT(ks2, i); 131 | for (i = 30; i >= 0; i -= 2) 132 | eks = eks << 1 | BEBIT(ks2, i); 133 | 134 | odd_head = odd_tail = calloc(1, sizeof(uint32_t) << 21); 135 | even_head = even_tail = calloc(1, sizeof(uint32_t) << 21); 136 | statelist = calloc(1, sizeof(struct Crypto1State) << 18); 137 | if (!odd_tail-- || !even_tail-- || !statelist) { 138 | free(statelist); 139 | statelist = 0; 140 | goto out; 141 | } 142 | 143 | statelist->odd = statelist->even = 0; 144 | 145 | // allocate memory for out of place bucket_sort 146 | bucket_array_t bucket; 147 | 148 | for (i = 0; i < 2; i++) { 149 | for (uint32_t j = 0; j <= 0xff; j++) { 150 | bucket[i][j].head = calloc(1, sizeof(uint32_t) << 14); 151 | if (!bucket[i][j].head) { 152 | goto out; 153 | } 154 | } 155 | } 156 | 157 | // initialize statelists: add all possible states which would result into the rightmost 2 bits of the keystream 158 | for (i = 1 << 20; i >= 0; --i) { 159 | if (filter(i) == (oks & 1)) 160 | *++odd_tail = i; 161 | if (filter(i) == (eks & 1)) 162 | *++even_tail = i; 163 | } 164 | 165 | // extend the statelists. Look at the next 8 Bits of the keystream (4 Bit each odd and even): 166 | for (i = 0; i < 4; i++) { 167 | extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); 168 | extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); 169 | } 170 | 171 | // the statelists now contain all states which could have generated the last 10 Bits of the keystream. 172 | // 22 bits to go to recover 32 bits in total. From now on, we need to take the "in" 173 | // parameter into account. 174 | in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); // Byte swapping 175 | recover(odd_head, odd_tail, oks, even_head, even_tail, eks, 11, statelist, in << 1, bucket); 176 | 177 | out: 178 | for (i = 0; i < 2; i++) 179 | for (uint32_t j = 0; j <= 0xff; j++) 180 | free(bucket[i][j].head); 181 | free(odd_head); 182 | free(even_head); 183 | return statelist; 184 | } 185 | 186 | static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, 187 | 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 188 | 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA 189 | }; 190 | static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, 191 | 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 192 | 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, 193 | 0x7EC7EE90, 0x7F63F748, 0x79117020 194 | }; 195 | static const uint32_t T1[] = { 196 | 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, 197 | 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, 198 | 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, 199 | 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C 200 | }; 201 | static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, 202 | 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, 203 | 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, 204 | 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, 205 | 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, 206 | 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0 207 | }; 208 | static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; 209 | static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; 210 | /** Reverse 64 bits of keystream into possible cipher states 211 | * Variation mentioned in the paper. Somewhat optimized version 212 | */ 213 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3) { 214 | struct Crypto1State *statelist, *sl; 215 | uint8_t oks[32], eks[32], hi[32]; 216 | uint32_t low = 0, win = 0; 217 | uint32_t *tail, table[1 << 16]; 218 | int i, j; 219 | 220 | sl = statelist = calloc(1, sizeof(struct Crypto1State) << 4); 221 | if (!sl) 222 | return 0; 223 | sl->odd = sl->even = 0; 224 | 225 | for (i = 30; i >= 0; i -= 2) { 226 | oks[i >> 1] = BEBIT(ks2, i); 227 | oks[16 + (i >> 1)] = BEBIT(ks3, i); 228 | } 229 | for (i = 31; i >= 0; i -= 2) { 230 | eks[i >> 1] = BEBIT(ks2, i); 231 | eks[16 + (i >> 1)] = BEBIT(ks3, i); 232 | } 233 | 234 | for (i = 0xfffff; i >= 0; --i) { 235 | if (filter(i) != oks[0]) 236 | continue; 237 | 238 | *(tail = table) = i; 239 | for (j = 1; tail >= table && j < 29; ++j) 240 | extend_table_simple(table, &tail, oks[j]); 241 | 242 | if (tail < table) 243 | continue; 244 | 245 | for (j = 0; j < 19; ++j) 246 | low = low << 1 | (evenparity32(i & S1[j])); 247 | for (j = 0; j < 32; ++j) 248 | hi[j] = evenparity32(i & T1[j]); 249 | 250 | for (; tail >= table; --tail) { 251 | for (j = 0; j < 3; ++j) { 252 | *tail = *tail << 1; 253 | *tail |= evenparity32((i & C1[j]) ^ (*tail & C2[j])); 254 | if (filter(*tail) != oks[29 + j]) 255 | goto continue2; 256 | } 257 | 258 | for (j = 0; j < 19; ++j) 259 | win = win << 1 | (evenparity32(*tail & S2[j])); 260 | 261 | win ^= low; 262 | for (j = 0; j < 32; ++j) { 263 | win = win << 1 ^ hi[j] ^ (evenparity32(*tail & T2[j])); 264 | if (filter(win) != eks[j]) 265 | goto continue2; 266 | } 267 | 268 | *tail = *tail << 1 | (evenparity32(LF_POLY_EVEN & *tail)); 269 | sl->odd = *tail ^ (evenparity32(LF_POLY_ODD & win)); 270 | sl->even = win; 271 | ++sl; 272 | sl->odd = sl->even = 0; 273 | continue2: 274 | ; 275 | } 276 | } 277 | return statelist; 278 | } 279 | #endif 280 | 281 | /** lfsr_rollback_bit 282 | * Rollback the shift register in order to get previous states 283 | */ 284 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) { 285 | int out; 286 | uint8_t ret; 287 | uint32_t t; 288 | 289 | s->odd &= 0xffffff; 290 | t = s->odd, s->odd = s->even, s->even = t; 291 | 292 | out = s->even & 1; 293 | out ^= LF_POLY_EVEN & (s->even >>= 1); 294 | out ^= LF_POLY_ODD & s->odd; 295 | out ^= !!in; 296 | out ^= (ret = filter(s->odd)) & (!!fb); 297 | 298 | s->even |= (evenparity32(out)) << 23; 299 | return ret; 300 | } 301 | /** lfsr_rollback_byte 302 | * Rollback the shift register in order to get previous states 303 | */ 304 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) { 305 | uint8_t ret = 0; 306 | ret |= lfsr_rollback_bit(s, BIT(in, 7), fb) << 7; 307 | ret |= lfsr_rollback_bit(s, BIT(in, 6), fb) << 6; 308 | ret |= lfsr_rollback_bit(s, BIT(in, 5), fb) << 5; 309 | ret |= lfsr_rollback_bit(s, BIT(in, 4), fb) << 4; 310 | ret |= lfsr_rollback_bit(s, BIT(in, 3), fb) << 3; 311 | ret |= lfsr_rollback_bit(s, BIT(in, 2), fb) << 2; 312 | ret |= lfsr_rollback_bit(s, BIT(in, 1), fb) << 1; 313 | ret |= lfsr_rollback_bit(s, BIT(in, 0), fb) << 0; 314 | return ret; 315 | } 316 | /** lfsr_rollback_word 317 | * Rollback the shift register in order to get previous states 318 | */ 319 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) { 320 | 321 | uint32_t ret = 0; 322 | // note: xor args have been swapped because some compilers emit a warning 323 | // for 10^x and 2^x as possible misuses for exponentiation. No comment. 324 | ret |= lfsr_rollback_bit(s, BEBIT(in, 31), fb) << (24 ^ 31); 325 | ret |= lfsr_rollback_bit(s, BEBIT(in, 30), fb) << (24 ^ 30); 326 | ret |= lfsr_rollback_bit(s, BEBIT(in, 29), fb) << (24 ^ 29); 327 | ret |= lfsr_rollback_bit(s, BEBIT(in, 28), fb) << (24 ^ 28); 328 | ret |= lfsr_rollback_bit(s, BEBIT(in, 27), fb) << (24 ^ 27); 329 | ret |= lfsr_rollback_bit(s, BEBIT(in, 26), fb) << (24 ^ 26); 330 | ret |= lfsr_rollback_bit(s, BEBIT(in, 25), fb) << (24 ^ 25); 331 | ret |= lfsr_rollback_bit(s, BEBIT(in, 24), fb) << (24 ^ 24); 332 | 333 | ret |= lfsr_rollback_bit(s, BEBIT(in, 23), fb) << (24 ^ 23); 334 | ret |= lfsr_rollback_bit(s, BEBIT(in, 22), fb) << (24 ^ 22); 335 | ret |= lfsr_rollback_bit(s, BEBIT(in, 21), fb) << (24 ^ 21); 336 | ret |= lfsr_rollback_bit(s, BEBIT(in, 20), fb) << (24 ^ 20); 337 | ret |= lfsr_rollback_bit(s, BEBIT(in, 19), fb) << (24 ^ 19); 338 | ret |= lfsr_rollback_bit(s, BEBIT(in, 18), fb) << (24 ^ 18); 339 | ret |= lfsr_rollback_bit(s, BEBIT(in, 17), fb) << (24 ^ 17); 340 | ret |= lfsr_rollback_bit(s, BEBIT(in, 16), fb) << (24 ^ 16); 341 | 342 | ret |= lfsr_rollback_bit(s, BEBIT(in, 15), fb) << (24 ^ 15); 343 | ret |= lfsr_rollback_bit(s, BEBIT(in, 14), fb) << (24 ^ 14); 344 | ret |= lfsr_rollback_bit(s, BEBIT(in, 13), fb) << (24 ^ 13); 345 | ret |= lfsr_rollback_bit(s, BEBIT(in, 12), fb) << (24 ^ 12); 346 | ret |= lfsr_rollback_bit(s, BEBIT(in, 11), fb) << (24 ^ 11); 347 | ret |= lfsr_rollback_bit(s, BEBIT(in, 10), fb) << (24 ^ 10); 348 | ret |= lfsr_rollback_bit(s, BEBIT(in, 9), fb) << (24 ^ 9); 349 | ret |= lfsr_rollback_bit(s, BEBIT(in, 8), fb) << (24 ^ 8); 350 | 351 | ret |= lfsr_rollback_bit(s, BEBIT(in, 7), fb) << (24 ^ 7); 352 | ret |= lfsr_rollback_bit(s, BEBIT(in, 6), fb) << (24 ^ 6); 353 | ret |= lfsr_rollback_bit(s, BEBIT(in, 5), fb) << (24 ^ 5); 354 | ret |= lfsr_rollback_bit(s, BEBIT(in, 4), fb) << (24 ^ 4); 355 | ret |= lfsr_rollback_bit(s, BEBIT(in, 3), fb) << (24 ^ 3); 356 | ret |= lfsr_rollback_bit(s, BEBIT(in, 2), fb) << (24 ^ 2); 357 | ret |= lfsr_rollback_bit(s, BEBIT(in, 1), fb) << (24 ^ 1); 358 | ret |= lfsr_rollback_bit(s, BEBIT(in, 0), fb) << (24 ^ 0); 359 | return ret; 360 | } 361 | 362 | /** nonce_distance 363 | * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y 364 | */ 365 | static uint16_t *dist = 0; 366 | int nonce_distance(uint32_t from, uint32_t to) { 367 | if (!dist) { 368 | // allocation 2bytes * 0xFFFF times. 369 | dist = calloc(2 << 16, sizeof(uint8_t)); 370 | if (!dist) 371 | return -1; 372 | uint16_t x = 1; 373 | for (uint16_t i = 1; i; ++i) { 374 | dist[(x & 0xff) << 8 | x >> 8] = i; 375 | x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; 376 | } 377 | } 378 | return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; 379 | } 380 | 381 | /** validate_prng_nonce 382 | * Determine if nonce is deterministic. ie: Suspectable to Darkside attack. 383 | * returns 384 | * true = weak prng 385 | * false = hardend prng 386 | */ 387 | bool validate_prng_nonce(uint32_t nonce) { 388 | // init prng table: 389 | if (nonce_distance(nonce, nonce) == -1) 390 | return false; 391 | return ((65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535) == 16; 392 | } 393 | 394 | static uint32_t fastfwd[2][8] = { 395 | { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, 396 | { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980} 397 | }; 398 | 399 | /** lfsr_prefix_ks 400 | * 401 | * Is an exported helper function from the common prefix attack 402 | * Described in the "dark side" paper. It returns an -1 terminated array 403 | * of possible partial(21 bit) secret state. 404 | * The required keystream(ks) needs to contain the keystream that was used to 405 | * encrypt the NACK which is observed when varying only the 3 last bits of Nr 406 | * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 407 | */ 408 | uint32_t *lfsr_prefix_ks(const uint8_t ks[8], int isodd) { 409 | uint32_t *candidates = calloc(4 << 10, sizeof(uint8_t)); 410 | if (!candidates) return 0; 411 | 412 | int size = 0; 413 | 414 | for (int i = 0; i < 1 << 21; ++i) { 415 | int good = 1; 416 | for (uint32_t c = 0; good && c < 8; ++c) { 417 | uint32_t entry = i ^ fastfwd[isodd][c]; 418 | good &= (BIT(ks[c], isodd) == filter(entry >> 1)); 419 | good &= (BIT(ks[c], isodd + 2) == filter(entry)); 420 | } 421 | if (good) 422 | candidates[size++] = i; 423 | } 424 | 425 | candidates[size] = -1; 426 | 427 | return candidates; 428 | } 429 | 430 | /** check_pfx_parity 431 | * helper function which eliminates possible secret states using parity bits 432 | */ 433 | static struct Crypto1State *check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], uint32_t odd, uint32_t even, struct Crypto1State *sl, uint32_t no_par) { 434 | uint32_t good = 1; 435 | 436 | for (uint32_t c = 0; good && c < 8; ++c) { 437 | sl->odd = odd ^ fastfwd[1][c]; 438 | sl->even = even ^ fastfwd[0][c]; 439 | 440 | lfsr_rollback_bit(sl, 0, 0); 441 | lfsr_rollback_bit(sl, 0, 0); 442 | 443 | uint32_t ks3 = lfsr_rollback_bit(sl, 0, 0); 444 | uint32_t ks2 = lfsr_rollback_word(sl, 0, 0); 445 | uint32_t ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); 446 | 447 | if (no_par) 448 | break; 449 | 450 | uint32_t nr = ks1 ^ (prefix | c << 5); 451 | uint32_t rr = ks2 ^ rresp; 452 | 453 | good &= evenparity32(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); 454 | good &= evenparity32(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); 455 | good &= evenparity32(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); 456 | good &= evenparity32(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); 457 | good &= evenparity32(rr & 0x000000ff) ^ parities[c][7] ^ ks3; 458 | } 459 | 460 | return sl + good; 461 | } 462 | 463 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() 464 | /** lfsr_common_prefix 465 | * Implementation of the common prefix attack. 466 | * Requires the 28 bit constant prefix used as reader nonce (pfx) 467 | * The reader response used (rr) 468 | * The keystream used to encrypt the observed NACK's (ks) 469 | * The parity bits (par) 470 | * It returns a zero terminated list of possible cipher states after the 471 | * tag nonce was fed in 472 | */ 473 | 474 | struct Crypto1State *lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par) { 475 | struct Crypto1State *statelist, *s; 476 | uint32_t *odd, *even, *o, *e, top; 477 | 478 | odd = lfsr_prefix_ks(ks, 1); 479 | even = lfsr_prefix_ks(ks, 0); 480 | 481 | s = statelist = calloc(1, (sizeof * statelist) << 24); // was << 20. Need more for no_par special attack. Enough??? 482 | if (!s || !odd || !even) { 483 | free(statelist); 484 | statelist = 0; 485 | goto out; 486 | } 487 | 488 | for (o = odd; *o + 1; ++o) 489 | for (e = even; *e + 1; ++e) 490 | for (top = 0; top < 64; ++top) { 491 | *o += 1 << 21; 492 | *e += (!(top & 7) + 1) << 21; 493 | s = check_pfx_parity(pfx, rr, par, *o, *e, s, no_par); 494 | } 495 | 496 | s->odd = s->even = 0; 497 | out: 498 | free(odd); 499 | free(even); 500 | return statelist; 501 | } 502 | #endif 503 | -------------------------------------------------------------------------------- /NestedSolver/crapto1.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #ifndef crypto01_INCLUDED 18 | #define crypto01_INCLUDED 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | struct Crypto1State {uint32_t odd, even;}; 25 | void crypto1_init(struct Crypto1State *state, uint64_t key); 26 | void crypto1_deinit(struct Crypto1State *); 27 | struct Crypto1State *crypto1_create(uint64_t key); 28 | void crypto1_destroy(struct Crypto1State *); 29 | void crypto1_get_lfsr(struct Crypto1State *, uint64_t *); 30 | uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int); 31 | uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int); 32 | uint32_t crypto1_word(struct Crypto1State *, uint32_t, int); 33 | uint32_t prng_successor(uint32_t x, uint32_t n); 34 | 35 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in); 36 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3); 37 | struct Crypto1State * 38 | lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par); 39 | uint32_t *lfsr_prefix_ks(const uint8_t ks[8], int isodd); 40 | 41 | 42 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb); 43 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb); 44 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb); 45 | int nonce_distance(uint32_t from, uint32_t to); 46 | bool validate_prng_nonce(uint32_t nonce); 47 | #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\ 48 | uint32_t __n = 0,__M = 0, N = 0;\ 49 | int __i;\ 50 | for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ 51 | for(__i = FSIZE - 1; __i >= 0; __i--)\ 52 | if(BIT(FILTER, __i) ^ evenparity32(__M & 0xFF01))\ 53 | break;\ 54 | else if(__i)\ 55 | __M = prng_successor(__M, (__i == 7) ? 48 : 8);\ 56 | else 57 | 58 | #define LF_POLY_ODD (0x29CE5C) 59 | #define LF_POLY_EVEN (0x870804) 60 | #define BIT(x, n) ((x) >> (n) & 1) 61 | #define BEBIT(x, n) BIT(x, (n) ^ 24) 62 | static inline int filter(uint32_t const x) { 63 | uint32_t f; 64 | 65 | f = 0xf22c0 >> (x & 0xf) & 16; 66 | f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; 67 | f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; 68 | f |= 0x1e458 >> (x >> 12 & 0xf) & 2; 69 | f |= 0x0d938 >> (x >> 16 & 0xf) & 1; 70 | return BIT(0xEC57E80A, f); 71 | } 72 | #endif -------------------------------------------------------------------------------- /NestedSolver/crypto1.c: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) 2008-2014 bla 3 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 4 | // 5 | // This program is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // See LICENSE.txt for the text of the license. 16 | //----------------------------------------------------------------------------- 17 | #include 18 | #include "crapto1.h" 19 | #include "parity.h" 20 | 21 | #ifdef __OPTIMIZE_SIZE__ 22 | int filter(uint32_t const x) { 23 | uint32_t f; 24 | 25 | f = 0xf22c0 >> (x & 0xf) & 16; 26 | f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; 27 | f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; 28 | f |= 0x1e458 >> (x >> 12 & 0xf) & 2; 29 | f |= 0x0d938 >> (x >> 16 & 0xf) & 1; 30 | return BIT(0xEC57E80A, f); 31 | } 32 | #endif 33 | 34 | #define SWAPENDIAN(x)\ 35 | (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) 36 | 37 | void crypto1_init(struct Crypto1State *state, uint64_t key) { 38 | if (state == NULL) 39 | return; 40 | state->odd = 0; 41 | state->even = 0; 42 | for (int i = 47; i > 0; i -= 2) { 43 | state->odd = state->odd << 1 | BIT(key, (i - 1) ^ 7); 44 | state->even = state->even << 1 | BIT(key, i ^ 7); 45 | } 46 | } 47 | 48 | void crypto1_deinit(struct Crypto1State *state) { 49 | state->odd = 0; 50 | state->even = 0; 51 | } 52 | 53 | #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks calloc()/free() 54 | 55 | struct Crypto1State *crypto1_create(uint64_t key) { 56 | struct Crypto1State *state = calloc(sizeof(*state), sizeof(uint8_t)); 57 | if (!state) return NULL; 58 | crypto1_init(state, key); 59 | return state; 60 | } 61 | 62 | void crypto1_destroy(struct Crypto1State *state) { 63 | free(state); 64 | } 65 | 66 | #endif 67 | 68 | void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) { 69 | int i; 70 | for (*lfsr = 0, i = 23; i >= 0; --i) { 71 | *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); 72 | *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); 73 | } 74 | } 75 | 76 | uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) { 77 | uint32_t feedin, t; 78 | uint8_t ret = filter(s->odd); 79 | 80 | feedin = ret & (!!is_encrypted); 81 | feedin ^= !!in; 82 | feedin ^= LF_POLY_ODD & s->odd; 83 | feedin ^= LF_POLY_EVEN & s->even; 84 | s->even = s->even << 1 | (evenparity32(feedin)); 85 | 86 | t = s->odd; 87 | s->odd = s->even; 88 | s->even = t; 89 | 90 | return ret; 91 | } 92 | 93 | uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) { 94 | uint8_t ret = 0; 95 | ret |= crypto1_bit(s, BIT(in, 0), is_encrypted) << 0; 96 | ret |= crypto1_bit(s, BIT(in, 1), is_encrypted) << 1; 97 | ret |= crypto1_bit(s, BIT(in, 2), is_encrypted) << 2; 98 | ret |= crypto1_bit(s, BIT(in, 3), is_encrypted) << 3; 99 | ret |= crypto1_bit(s, BIT(in, 4), is_encrypted) << 4; 100 | ret |= crypto1_bit(s, BIT(in, 5), is_encrypted) << 5; 101 | ret |= crypto1_bit(s, BIT(in, 6), is_encrypted) << 6; 102 | ret |= crypto1_bit(s, BIT(in, 7), is_encrypted) << 7; 103 | return ret; 104 | } 105 | 106 | uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) { 107 | uint32_t ret = 0; 108 | // note: xor args have been swapped because some compilers emit a warning 109 | // for 10^x and 2^x as possible misuses for exponentiation. No comment. 110 | ret |= crypto1_bit(s, BEBIT(in, 0), is_encrypted) << (24 ^ 0); 111 | ret |= crypto1_bit(s, BEBIT(in, 1), is_encrypted) << (24 ^ 1); 112 | ret |= crypto1_bit(s, BEBIT(in, 2), is_encrypted) << (24 ^ 2); 113 | ret |= crypto1_bit(s, BEBIT(in, 3), is_encrypted) << (24 ^ 3); 114 | ret |= crypto1_bit(s, BEBIT(in, 4), is_encrypted) << (24 ^ 4); 115 | ret |= crypto1_bit(s, BEBIT(in, 5), is_encrypted) << (24 ^ 5); 116 | ret |= crypto1_bit(s, BEBIT(in, 6), is_encrypted) << (24 ^ 6); 117 | ret |= crypto1_bit(s, BEBIT(in, 7), is_encrypted) << (24 ^ 7); 118 | 119 | ret |= crypto1_bit(s, BEBIT(in, 8), is_encrypted) << (24 ^ 8); 120 | ret |= crypto1_bit(s, BEBIT(in, 9), is_encrypted) << (24 ^ 9); 121 | ret |= crypto1_bit(s, BEBIT(in, 10), is_encrypted) << (24 ^ 10); 122 | ret |= crypto1_bit(s, BEBIT(in, 11), is_encrypted) << (24 ^ 11); 123 | ret |= crypto1_bit(s, BEBIT(in, 12), is_encrypted) << (24 ^ 12); 124 | ret |= crypto1_bit(s, BEBIT(in, 13), is_encrypted) << (24 ^ 13); 125 | ret |= crypto1_bit(s, BEBIT(in, 14), is_encrypted) << (24 ^ 14); 126 | ret |= crypto1_bit(s, BEBIT(in, 15), is_encrypted) << (24 ^ 15); 127 | 128 | ret |= crypto1_bit(s, BEBIT(in, 16), is_encrypted) << (24 ^ 16); 129 | ret |= crypto1_bit(s, BEBIT(in, 17), is_encrypted) << (24 ^ 17); 130 | ret |= crypto1_bit(s, BEBIT(in, 18), is_encrypted) << (24 ^ 18); 131 | ret |= crypto1_bit(s, BEBIT(in, 19), is_encrypted) << (24 ^ 19); 132 | ret |= crypto1_bit(s, BEBIT(in, 20), is_encrypted) << (24 ^ 20); 133 | ret |= crypto1_bit(s, BEBIT(in, 21), is_encrypted) << (24 ^ 21); 134 | ret |= crypto1_bit(s, BEBIT(in, 22), is_encrypted) << (24 ^ 22); 135 | ret |= crypto1_bit(s, BEBIT(in, 23), is_encrypted) << (24 ^ 23); 136 | 137 | ret |= crypto1_bit(s, BEBIT(in, 24), is_encrypted) << (24 ^ 24); 138 | ret |= crypto1_bit(s, BEBIT(in, 25), is_encrypted) << (24 ^ 25); 139 | ret |= crypto1_bit(s, BEBIT(in, 26), is_encrypted) << (24 ^ 26); 140 | ret |= crypto1_bit(s, BEBIT(in, 27), is_encrypted) << (24 ^ 27); 141 | ret |= crypto1_bit(s, BEBIT(in, 28), is_encrypted) << (24 ^ 28); 142 | ret |= crypto1_bit(s, BEBIT(in, 29), is_encrypted) << (24 ^ 29); 143 | ret |= crypto1_bit(s, BEBIT(in, 30), is_encrypted) << (24 ^ 30); 144 | ret |= crypto1_bit(s, BEBIT(in, 31), is_encrypted) << (24 ^ 31); 145 | return ret; 146 | } 147 | 148 | /* prng_successor 149 | * helper used to obscure the keystream during authentication 150 | */ 151 | uint32_t prng_successor(uint32_t x, uint32_t n) { 152 | SWAPENDIAN(x); 153 | while (n--) 154 | x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; 155 | 156 | return SWAPENDIAN(x); 157 | } 158 | 159 | int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, const uint8_t *parity) { 160 | return ( 161 | (oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \ 162 | (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \ 163 | (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0))) 164 | ) ? 1 : 0; 165 | } -------------------------------------------------------------------------------- /NestedSolver/library.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "library.h" 7 | #include "crapto1.h" 8 | #include "parity.h" 9 | #include "progress.h" 10 | 11 | static int compare_uint64(const void *a, const void *b) { 12 | if (*(uint64_t *) b == *(uint64_t *) a) return 0; 13 | if (*(uint64_t *) b < *(uint64_t *) a) return 1; 14 | return -1; 15 | } 16 | 17 | // create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned. 18 | static uint32_t intersection(uint64_t *listA, uint64_t *listB) { 19 | if (listA == NULL || listB == NULL) 20 | return 0; 21 | 22 | uint64_t *p1, *p2, *p3; 23 | p1 = p3 = listA; 24 | p2 = listB; 25 | 26 | while (*p1 != UINT64_MAX && *p2 != UINT64_MAX) { 27 | if (compare_uint64(p1, p2) == 0) { 28 | *p3++ = *p1++; 29 | p2++; 30 | } else { 31 | while (compare_uint64(p1, p2) < 0) ++p1; 32 | while (compare_uint64(p1, p2) > 0) ++p2; 33 | } 34 | } 35 | *p3 = UINT64_MAX; 36 | return p3 - listA; 37 | } 38 | 39 | static int compare_16bits(const void *a, const void *b) { 40 | if ((*(uint64_t *) b & 0x00ff000000ff0000) == (*(uint64_t *) a & 0x00ff000000ff0000)) return 0; 41 | if ((*(uint64_t *) b & 0x00ff000000ff0000) > (*(uint64_t *) a & 0x00ff000000ff0000)) return 1; 42 | return -1; 43 | } 44 | 45 | static int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, const uint8_t *parity) { 46 | return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \ 47 | (oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \ 48 | (oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0)))) ? 1 : 0; 49 | } 50 | 51 | static uint32_t pow_calc(uint32_t num, uint32_t deg) { 52 | uint32_t result = 1; 53 | 54 | for (long i = 0; i < deg; i++) { 55 | result *= num; 56 | } 57 | 58 | return result; 59 | } 60 | 61 | static uint8_t *decode_parity(uint32_t parity) { 62 | uint8_t *par_array = malloc(sizeof(uint8_t) * 4); 63 | 64 | for (int j = 3; j >= 0; j--) { 65 | if (j) { 66 | par_array[3 - j] = (parity / pow_calc(10, j)); 67 | } else { 68 | par_array[3 - j] = parity; 69 | } 70 | 71 | parity -= (parity / pow_calc(10, j)) * pow_calc(10, j); 72 | } 73 | 74 | return par_array; 75 | } 76 | 77 | static bool nested_calculate(InfoList_t *arg) { 78 | InfoList_t *info = arg; 79 | struct Crypto1State *p1, *p2, *p3, *p4; 80 | StateList_t statelists[2]; 81 | 82 | for (uint8_t i = 0; i < 2; i++) { 83 | statelists[i].uid = info->uid; 84 | } 85 | 86 | statelists[0].nt_enc = info->nt0; 87 | statelists[0].ks1 = info->ks0; 88 | 89 | statelists[1].nt_enc = info->nt1; 90 | statelists[1].ks1 = info->ks1; 91 | 92 | // create and run worker threads 93 | statelists[0].head.slhead = lfsr_recovery32(statelists[0].ks1, statelists[0].nt_enc ^ statelists[0].uid); 94 | statelists[1].head.slhead = lfsr_recovery32(statelists[1].ks1, statelists[1].nt_enc ^ statelists[1].uid); 95 | 96 | for (p1 = statelists[0].head.slhead; p1->odd | p1->even; p1++) {} 97 | for (p2 = statelists[1].head.slhead; p2->odd | p2->even; p2++) {} 98 | 99 | statelists[0].len = p1 - statelists[0].head.slhead; 100 | statelists[0].tail.sltail = --p1; 101 | 102 | statelists[1].len = p2 - statelists[1].head.slhead; 103 | statelists[1].tail.sltail = --p2; 104 | 105 | qsort(statelists[0].head.slhead, statelists[0].len, sizeof(uint64_t), compare_16bits); 106 | qsort(statelists[1].head.slhead, statelists[1].len, sizeof(uint64_t), compare_16bits); 107 | 108 | p1 = p3 = statelists[0].head.slhead; 109 | p2 = p4 = statelists[1].head.slhead; 110 | 111 | while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { 112 | if (compare_16bits(p1, p2) == 0) { 113 | 114 | struct Crypto1State savestate; 115 | savestate = *p1; 116 | while (compare_16bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { 117 | *p3 = *p1; 118 | lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); 119 | p3++; 120 | p1++; 121 | } 122 | savestate = *p2; 123 | while (compare_16bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) { 124 | *p4 = *p2; 125 | lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0); 126 | p4++; 127 | p2++; 128 | } 129 | } else { 130 | while (compare_16bits(p1, p2) == -1) p1++; 131 | while (compare_16bits(p1, p2) == 1) p2++; 132 | } 133 | } 134 | 135 | p3->odd = -1; 136 | p3->even = -1; 137 | p4->odd = -1; 138 | p4->even = -1; 139 | statelists[0].len = p3 - statelists[0].head.slhead; 140 | statelists[1].len = p4 - statelists[1].head.slhead; 141 | statelists[0].tail.sltail = --p3; 142 | statelists[1].tail.sltail = --p4; 143 | 144 | qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); 145 | qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); 146 | // Create the intersection 147 | statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); 148 | 149 | if (!info->free) { 150 | for (uint32_t i = 0; i < statelists[0].len; i++) { 151 | char *ch = malloc(14); 152 | uint64_t key64 = 0; 153 | 154 | crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); 155 | snprintf(ch, 14, "%012" PRIx64 ";", key64); 156 | for (uint32_t j = 0; j < 14; j++) { 157 | strncat(info->keys, &ch[j], 1); 158 | } 159 | free(ch); 160 | } 161 | } 162 | 163 | free(statelists[0].head.slhead); 164 | free(statelists[1].head.slhead); 165 | 166 | if (statelists[0].len) { 167 | return true; 168 | } else { 169 | return false; 170 | } 171 | } 172 | 173 | static void *nested_wrapper(void *arg) { 174 | bool run = nested_calculate(arg); 175 | free(arg); 176 | if (run) { 177 | return (void *) 1; 178 | } else { 179 | return 0; 180 | } 181 | } 182 | 183 | char *run_nested(uint32_t uid, uint32_t nt0, uint32_t ks0, uint32_t nt1, uint32_t ks1) { 184 | InfoList_t *info = malloc(sizeof(InfoList_t)); 185 | info->uid = uid; 186 | info->nt0 = nt0; 187 | info->ks0 = ks0; 188 | info->nt1 = nt1; 189 | info->ks1 = ks1; 190 | info->keys = calloc(256, sizeof(char) * 14); 191 | info->free = false; 192 | nested_calculate(info); 193 | return info->keys; 194 | } 195 | 196 | char * 197 | run_full_nested(uint32_t uid, uint32_t nt0, uint32_t ks0, uint32_t par0, uint32_t nt1, uint32_t ks1, uint32_t par1, 198 | int from, int to, bool progress) { 199 | #if _MSC_VER 200 | pthread_t thread_id[16384]; 201 | uint32_t found_second_array[16384]; 202 | #else 203 | pthread_t thread_id[to]; 204 | uint32_t found_second_array[to]; 205 | #endif 206 | uint32_t found_first, found_second; 207 | bool found = false; 208 | uint32_t i; 209 | 210 | for (int first = from; first < to; first++) { 211 | if (progress) print_progress(first - from, to - from); 212 | i = 0; 213 | void *status = NULL; 214 | 215 | for (int second = from; second < to; second++) { 216 | uint8_t *par0_decoded = decode_parity(par0); 217 | uint8_t *par1_decoded = decode_parity(par1); 218 | if (!valid_nonce(prng_successor(nt0, first), ks0, ks0 ^ prng_successor(nt0, first), par0_decoded) || 219 | !valid_nonce(prng_successor(nt1, second), ks1, ks1 ^ prng_successor(nt1, second), par1_decoded)) { 220 | free(par0_decoded); 221 | free(par1_decoded); 222 | continue; 223 | } 224 | 225 | free(par0_decoded); 226 | free(par1_decoded); 227 | 228 | InfoList_t *info = malloc(sizeof(InfoList_t)); 229 | info->uid = uid; 230 | info->nt0 = prng_successor(nt0, first); 231 | info->ks0 = ks0 ^ info->nt0; 232 | info->nt1 = prng_successor(nt1, second); 233 | info->ks1 = ks1 ^ info->nt1; 234 | info->free = true; 235 | 236 | found_second_array[i] = second; 237 | pthread_create(&thread_id[i], NULL, nested_wrapper, info); 238 | i++; 239 | } 240 | 241 | for (uint32_t j = 0; j < i; j++) { 242 | pthread_join(thread_id[j], &status); 243 | if (status != 0) { 244 | found_first = first; 245 | found_second = found_second_array[j]; 246 | found = true; 247 | } 248 | } 249 | 250 | if (found) { 251 | InfoList_t *found_info = malloc(sizeof(InfoList_t)); 252 | found_info->uid = uid; 253 | found_info->nt0 = prng_successor(nt0, found_first); 254 | found_info->ks0 = ks0 ^ found_info->nt0; 255 | found_info->nt1 = prng_successor(nt1, found_second); 256 | found_info->ks1 = ks1 ^ found_info->nt1; 257 | found_info->keys = calloc(256, sizeof(char) * 14); 258 | found_info->free = false; 259 | nested_calculate(found_info); 260 | if (progress) exit_progress(); 261 | return found_info->keys; 262 | } 263 | } 264 | 265 | if (progress) exit_progress(); 266 | return calloc(1, 1); 267 | } -------------------------------------------------------------------------------- /NestedSolver/library.h: -------------------------------------------------------------------------------- 1 | #ifndef MIFARE_LIB_LIBRARY_H 2 | #define MIFARE_LIB_LIBRARY_H 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | union { 9 | struct Crypto1State *slhead; 10 | uint64_t *keyhead; 11 | } head; 12 | union { 13 | struct Crypto1State *sltail; 14 | uint64_t *keytail; 15 | } tail; 16 | uint32_t len; 17 | uint32_t uid; 18 | uint32_t nt_enc; 19 | uint32_t ks1; 20 | } StateList_t; 21 | 22 | typedef struct { 23 | uint32_t uid; 24 | uint32_t nt0; 25 | uint32_t ks0; 26 | uint32_t nt1; 27 | uint32_t ks1; 28 | char *keys; 29 | bool free; 30 | } InfoList_t; 31 | 32 | char* run_nested(uint32_t uid, uint32_t nt0, uint32_t ks0, uint32_t nt1, uint32_t ks1); 33 | 34 | char* run_full_nested(uint32_t uid, uint32_t nt0, uint32_t ks0, uint32_t par0, uint32_t nt1, uint32_t ks1, uint32_t par1, int from, int to, bool progress); 35 | 36 | #endif //MIFARE_LIB_LIBRARY_H 37 | -------------------------------------------------------------------------------- /NestedSolver/parity.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // See LICENSE.txt for the text of the license. 15 | //----------------------------------------------------------------------------- 16 | // Parity functions 17 | //----------------------------------------------------------------------------- 18 | 19 | // all functions defined in header file by purpose. Allows compiler optimizations. 20 | 21 | #ifndef __PARITY_H 22 | #define __PARITY_H 23 | #define _CRT_NONSTDC_NO_WARNINGS 24 | #define _CRT_SECURE_NO_WARNINGS 25 | #define _CRT_NON_CONFORMING_SWPRINTFS 26 | 27 | #define restrict __restrict 28 | #define inline __inline 29 | #include 30 | #include 31 | 32 | static const uint8_t g_odd_byte_parity[256] = { 33 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 34 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 35 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 36 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 37 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 38 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 39 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 40 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 41 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 42 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 43 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 44 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 45 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 46 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 47 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 48 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 49 | }; 50 | 51 | #define ODD_PARITY8(x) (g_odd_byte_parity[x]) 52 | #define EVEN_PARITY8(x) (!g_odd_byte_parity[x]) 53 | 54 | static inline uint8_t oddparity8(const uint8_t x) { 55 | return g_odd_byte_parity[x]; 56 | } 57 | 58 | static inline uint8_t evenparity8(const uint8_t x) { 59 | return !g_odd_byte_parity[x]; 60 | } 61 | 62 | static inline uint8_t evenparity16(uint16_t x) { 63 | #if !defined __GNUC__ 64 | x ^= x >> 8; 65 | return EVEN_PARITY8(x); 66 | #else 67 | return (__builtin_parity(x) & 0xFF); 68 | #endif 69 | } 70 | 71 | static inline uint8_t oddparity16(uint16_t x) { 72 | #if !defined __GNUC__ 73 | x ^= x >> 8; 74 | return ODD_PARITY8(x); 75 | #else 76 | return !__builtin_parity(x); 77 | #endif 78 | } 79 | 80 | static inline uint8_t evenparity32(uint32_t x) { 81 | #if _MSC_VER 82 | x ^= x >> 16; 83 | x ^= x >> 8; 84 | x ^= x >> 4; 85 | x &= 0xf; 86 | return (0x6996 >> x) & 1; 87 | #elif !defined __GNUC__ 88 | x ^= x >> 16; 89 | x ^= x >> 8; 90 | return EVEN_PARITY8(x); 91 | #else 92 | return (__builtin_parity(x) & 0xFF); 93 | #endif 94 | } 95 | 96 | static inline uint8_t oddparity32(uint32_t x) { 97 | #if _MSC_VER 98 | x ^= x >> 16; 99 | x ^= x >> 8; 100 | x ^= x >> 4; 101 | x &= 0xf; 102 | return ((0x6996 >> x) & 1) ^ 1; 103 | #elif !defined __GNUC__ 104 | x ^= x >> 16; 105 | x ^= x >> 8; 106 | return ODD_PARITY8(x); 107 | #else 108 | return !__builtin_parity(x); 109 | #endif 110 | } 111 | 112 | #endif /* __PARITY_H */ -------------------------------------------------------------------------------- /NestedSolver/progress.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "progress.h" 4 | #define PERCENTAGE(V, T) (100 - (((T - V) * 100) / T)) 5 | #ifdef _WIN32 6 | #include 7 | #else 8 | #include 9 | #include 10 | #endif 11 | 12 | void print_progress(uint32_t count, uint32_t max) { 13 | uint32_t i = 0; 14 | const char prefix[] = "Key recovery: ["; 15 | const char suffix[] = "]"; 16 | const size_t prefix_length = sizeof(prefix) - 1; 17 | const size_t suffix_length = sizeof(suffix) - 1; 18 | char *buffer; 19 | size_t bar_width, terminal_width; 20 | #ifdef _WIN32 21 | CONSOLE_SCREEN_BUFFER_INFO csbi; 22 | GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 23 | // terminal_width = csbi.dwSize.X; 24 | terminal_width = 100; 25 | #else 26 | struct winsize w; 27 | ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 28 | // terminal_width = w.ws_col; 29 | terminal_width = 100; 30 | #endif 31 | 32 | if (terminal_width < prefix_length + suffix_length + 8) { 33 | printf("\r[%u/%u]", count, max); 34 | return; 35 | } 36 | 37 | bar_width = terminal_width - prefix_length - suffix_length - 8; 38 | buffer = calloc(bar_width + 1, 1); 39 | 40 | for (; i < bar_width; ++i) { 41 | buffer[i] = i < PERCENTAGE(count, max) * bar_width / 100 ? '#' : ' '; 42 | } 43 | 44 | printf("\r%s%s%s (%u%%)", prefix, buffer, suffix, PERCENTAGE(count, max)); 45 | fflush(stdout); 46 | 47 | free(buffer); 48 | } 49 | 50 | void exit_progress() { 51 | #ifdef _WIN32 52 | CONSOLE_SCREEN_BUFFER_INFO csbi; 53 | GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 54 | DWORD written; 55 | COORD cursor = {0, csbi.dwCursorPosition.Y}; 56 | FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ' ', csbi.dwSize.X, cursor, &written); 57 | SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursor); 58 | #else 59 | printf("\r\033[2K"); 60 | #endif 61 | fflush(stdout); 62 | } -------------------------------------------------------------------------------- /NestedSolver/progress.h: -------------------------------------------------------------------------------- 1 | #ifndef MIFARE_LIB_PROGRESS_H 2 | #define MIFARE_LIB_PROGRESS_H 3 | #include 4 | 5 | void print_progress(uint32_t count, uint32_t max); 6 | 7 | void exit_progress(); 8 | 9 | #endif //MIFARE_LIB_PROGRESS_H 10 | -------------------------------------------------------------------------------- /NestedSolver/python.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "library.h" 3 | 4 | static PyObject *run_nested_python(PyObject *self, PyObject *args) { 5 | uint64_t uid, nt0, ks0, nt1, ks1; 6 | if (!PyArg_ParseTuple(args, "kkkkk", &uid, &nt0, &ks0, &nt1, &ks1)) { 7 | return NULL; 8 | } 9 | 10 | char *output = run_nested((uint32_t) uid, (uint32_t) nt0, (uint32_t) ks0, (uint32_t) nt1, (uint32_t) ks1); 11 | 12 | return Py_BuildValue("s", output); 13 | } 14 | 15 | static PyObject *run_full_nested_python(PyObject *self, PyObject *args) { 16 | uint64_t uid, nt0, ks0, par0, nt1, ks1, par1; 17 | int from, to, progress; 18 | if (!PyArg_ParseTuple(args, "kkkkkkkiip", &uid, &nt0, &ks0, &par0, &nt1, &ks1, &par1, &from, &to, &progress)) { 19 | return NULL; 20 | } 21 | 22 | char *output = run_full_nested((uint32_t) uid, (uint32_t) nt0, (uint32_t) ks0, (uint32_t) par0, (uint32_t) nt1, 23 | (uint32_t) ks1, (uint32_t) par1, from, to, progress); 24 | 25 | return Py_BuildValue("s", output); 26 | } 27 | 28 | static PyMethodDef nested_methods[] = {{"run_nested", run_nested_python, METH_VARARGS, "Run nested"}, 29 | {"run_full_nested", run_full_nested_python, METH_VARARGS, "Run full nested"}, 30 | {NULL, NULL, 0, NULL} /* Sentinel */ 31 | }; 32 | 33 | static struct PyModuleDef nested_module = {PyModuleDef_HEAD_INIT, "nested", NULL, -1, nested_methods}; 34 | 35 | PyMODINIT_FUNC PyInit_nested(void) { 36 | return PyModule_Create(&nested_module); 37 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlipperNestedRecovery GUI 2 | 3 | [繁體中文](README_TW.md) | [简体中文](README_CN.md) 4 | 5 | ## Changelog 6 | 7 | ### Version 2.0 8 | - **Real-time Progress Display**: The progress of operations is now displayed in real-time, allowing users to monitor the current status. 9 | - **Bug Fixes**: Addressed known issues, including unexpected behavior in debug mode under certain conditions. 10 | 11 | ### Version 1.0 12 | - Initial release, including basic operations for FlipperNestedRecovery. 13 | 14 | --- 15 | 16 | FlipperNestedRecovery GUI is a graphical user interface (GUI) for executing the FlipperNestedRecovery tool, simplifying the operation process so users can easily run FlipperNestedRecovery through the GUI. This software is designed for users who are not familiar with Python, command-line operations, or those who encounter installation issues. 17 | 18 | ## Features 19 | 20 | - **Run FlipperNestedRecovery**: Operate the FlipperNestedRecovery tool through a graphical interface. 21 | - **Specify UID and Port**: Users can input the target card's UID and the communication port of the Flipper device via the interface. 22 | - **Real-time Progress Display**: The progress of operations can now be displayed in real-time, allowing users to monitor the current status. 23 | - **Debug Mode and Save Nonces**: Enable debug mode and choose whether to save the Nonces file. 24 | - **Multi-language Support**: Supports Simplified Chinese, Traditional Chinese, and English interfaces. 25 | 26 | ## User Guide 27 | 28 | ### 1. Download and Install 29 | 30 | 1. Download the latest version of FlipperNestedRecovery GUI 2.0. 31 | 2. Double-click `FlipperNestedRecovery GUI 2.0.exe` or `FlipperNestedRecovery GUI 2.0.app` to run the program. 32 | 3. That's it! No complex steps. 33 | 34 | ### 2. Interface Introduction 35 | 36 | - **UID**: Enter the unique identifier of the card you want to analyze. Leave it blank to analyze all cards. 37 | - **Port**: Specify the communication port of the Flipper device. Leave it blank to use the default port. 38 | - **Show Progress**: Displays the progress of the operation in real-time, allowing you to see the current status. 39 | - **Enable Debug Mode**: Check this option to enable debug mode, displaying more debugging information. 40 | - **Save Nonces**: Check this option to save Nonces and key files. 41 | - **Preserve Nonces**: Check this option to keep the Nonces on Flipper Zero after key recovery. 42 | - **Nonces File**: Select a `.nonces` file to recover keys from. 43 | - **Run**: Click this button to start executing the FlipperNestedRecovery operation. 44 | - **Stop**: Click this button during the operation to terminate the process. 45 | - **About**: View information about this program. 46 | 47 | ### 3. Run and Terminate 48 | 49 | - **Run the Program**: After entering the necessary parameters, click the `Run` button. The program will start executing the FlipperNestedRecovery tool. The operation progress will be displayed in real-time, and all results will be shown upon completion. 50 | - **Terminate Operation**: If you need to stop the operation, click the `Stop` button. The program will attempt to terminate all related processes. Users can click the `Stop` button at any time to terminate the current operation, and the program will safely close all related processes. 51 | 52 | ### 4. Notes 53 | 54 | - **Connect Flipper Zero**: Ensure Flipper Zero is connected via USB and is not occupied by any other software (e.g., `./fbt log`, `qFlipper`, `lab.flipper.net`). 55 | - **Check Flipper Device**: Before use, ensure that Flipper Zero is properly connected and in standby mode. 56 | 57 | ## Special Thanks 58 | 59 | Special thanks to the following individuals and projects for their support and contributions: 60 | 61 | - **ZhaiRenGaiZaoJia**: Thank you for providing the nonces file and assisting with testing, helping me identify some bugs in the software. 62 | - **AloneLiberty**: Thank you for developing the original [FlipperNestedRecovery](https://github.com/AloneLiberty/FlipperNestedRecovery) tool, on which this project is based. 63 | 64 | Special thanks to all users who provided feedback and suggestions during the development of the project. Your support is our motivation for continuous improvement. 65 | 66 | ## Disclaimer 67 | 68 | This software may contain defects or errors, and the author makes no express or implied warranties regarding the performance or effects of this software, including but not limited to merchantability, fitness for a particular purpose, and non-infringement. The author shall not be liable for any damages, losses, or other liabilities arising from the use or inability to use this software, whether in contract, tort, or other legal actions. -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # FlipperNestedRecovery GUI 2 | 3 | [English Version](README.md) | [繁體中文](README_TW.md) 4 | 5 | ## 更新日志 6 | 7 | ### 2.0 版本 8 | - **实时显示操作进度**:现在操作过程中可以实时显示进度,用户可以随时查看当前状态。 9 | - **修复了一些已知问题**:包括在某些情况下调试模式下的非预期行为。 10 | 11 | ### 1.0 版本 12 | - 初始发布版本,包含基本的 FlipperNestedRecovery 操作功能。 13 | 14 | --- 15 | 16 | FlipperNestedRecovery GUI 是一个用于执行 FlipperNestedRecovery 工具的图形用户界面(GUI),简化了操作流程,使用户可以轻松地通过 GUI 运行 FlipperNestedRecovery。该软件适用于不熟悉 Python、不熟悉命令行操作或遇到安装问题的用户。 17 | 18 | ## 特性 19 | 20 | - **运行 FlipperNestedRecovery**:通过图形界面操作 FlipperNestedRecovery 工具。 21 | - **指定 UID 和端口**:用户可以通过界面输入目标卡片的 UID 和 Flipper 设备的通信端口。 22 | - **实时显示操作进度**:现在可以实时显示操作的当前进度,让用户随时了解操作状态。 23 | - **调试模式和保存 Nonces**:启用调试模式,并选择是否保存 Nonces 文件。 24 | - **多语言支持**:支持简体中文、繁体中文和英文界面。 25 | 26 | ## 使用指南 27 | 28 | ### 1. 下载与安装 29 | 30 | 1. 下载最新版本的 FlipperNestedRecovery GUI 2.0。 31 | 2. 双击 `FlipperNestedRecovery GUI 2.0.exe` 或者 `FlipperNestedRecovery GUI 2.0.app` 运行程序。 32 | 3. 没啦,还想要多复杂? 33 | 34 | ### 2. 界面介绍 35 | 36 | - **UID**: 请输入需要分析的卡片的唯一标识符,留空则分析所有卡片。 37 | - **端口**: 指定 Flipper 设备的通信端口,留空则使用默认端口。 38 | - **显示进度**: 在操作过程中实时显示进度。用户可以随时查看当前操作状态。 39 | - **启用调试模式**: 勾选此选项以启用调试模式,显示更多调试信息。 40 | - **保存 Nonces**: 勾选此选项以保存 Nonces 和密钥文件。 41 | - **保留 Nonces**: 勾选此选项以在恢复密钥后保留 Flipper Zero 上的 Nonces。 42 | - **Nonces 文件**: 选择一个 `.nonces` 文件来从中恢复密钥。 43 | - **运行**: 点击此按钮开始执行 FlipperNestedRecovery 的操作。 44 | - **停止**: 在操作过程中可以点击此按钮终止操作。 45 | - **关于**: 查看关于本程序的信息。 46 | 47 | ### 3. 运行与终止 48 | 49 | - **运行程序**: 输入必要的参数后,点击 `运行` 按钮,程序将开始执行 FlipperNestedRecovery 工具。由于当前的限制,操作进度无法实时显示,所有结果将在执行完成后显示。 50 | - **终止操作**: 如果需要中止操作,点击 `停止` 按钮,程序将尝试终止所有相关进程。用户在任何时候都可以通过点击 `停止` 按钮来终止当前操作,程序会安全地关闭所有相关进程。 51 | 52 | ### 4. 注意事项 53 | 54 | - **连接 Flipper Zero**: 请确保 Flipper Zero 通过 USB 线连接,并且没有被任何其他软件(例如 `./fbt log`、`qFlipper`、`lab.flipper.net`)占用。 55 | - **检查 Flipper 设备**:使用前,请确保 Flipper Zero 已正确连接,且处于待机状态。 56 | 57 | ## 特别鸣谢 58 | 59 | 在此特别感谢以下个人和项目的支持与贡献: 60 | 61 | - **宅人改造家**:感谢他提供nonces文件并协助测试,帮助我找出了软件中的一些bug。 62 | - **AloneLiberty**:感谢他开发了原始的[FlipperNestedRecovery](https://github.com/AloneLiberty/FlipperNestedRecovery)工具,本项目基于其工作进行开发。 63 | 64 | 特别感谢所有在项目开发过程中提供反馈和建议的用户,你们的支持是我们持续改进的动力。 65 | 66 | ## 免责声明 67 | 68 | 本软件可能包含缺陷或错误,作者不对本软件的性能或效果作出任何明示或暗示的保证,包括但不限于适销性、特定用途适用性和非侵权性。无论是在合同诉讼、侵权诉讼或其他法律诉讼中,作者均不对因使用或无法使用本软件而导致的任何损害、损失或其他责任负责。 -------------------------------------------------------------------------------- /README_TW.md: -------------------------------------------------------------------------------- 1 | # FlipperNestedRecovery GUI 2 | 3 | [English Version](README.md) | [简体中文](README_CN.md) 4 | 5 | ## 更新日誌 6 | 7 | ### 2.0 版本 8 | - **實時顯示操作進度**:現在操作過程中可以實時顯示進度,用戶可以隨時查看當前狀態。 9 | - **修復了一些已知問題**:包括在某些情況下調試模式下的非預期行為。 10 | 11 | ### 1.0 版本 12 | - 初始發佈版本,包含基本的 FlipperNestedRecovery 操作功能。 13 | 14 | --- 15 | 16 | FlipperNestedRecovery GUI 是一個用於執行 FlipperNestedRecovery 工具的圖形用戶界面(GUI),簡化了操作流程,使用戶可以輕鬆地通過 GUI 運行 FlipperNestedRecovery。該軟體適用於不熟悉 Python、不熟悉命令行操作或遇到安裝問題的用戶。 17 | 18 | ## 特性 19 | 20 | - **運行 FlipperNestedRecovery**:通過圖形界面操作 FlipperNestedRecovery 工具。 21 | - **指定 UID 和端口**:用戶可以通過界面輸入目標卡片的 UID 和 Flipper 設備的通信端口。 22 | - **實時顯示操作進度**:現在可以實時顯示操作的當前進度,讓用戶隨時了解操作狀態。 23 | - **調試模式和保存 Nonces**:啟用調試模式,並選擇是否保存 Nonces 文件。 24 | - **多語言支持**:支持簡體中文、繁體中文和英文界面。 25 | 26 | ## 使用指南 27 | 28 | ### 1. 下載與安裝 29 | 30 | 1. 下載最新版本的 FlipperNestedRecovery GUI 2.0。 31 | 2. 雙擊 `FlipperNestedRecovery GUI 2.0.exe` 或者 `FlipperNestedRecovery GUI 2.0.app` 運行程序。 32 | 3. 沒啦,還想要多複雜? 33 | 34 | ### 2. 界面介紹 35 | 36 | - **UID**: 請輸入需要分析的卡片的唯一標識符,留空則分析所有卡片。 37 | - **端口**: 指定 Flipper 設備的通信端口,留空則使用默認端口。 38 | - **顯示進度**: 在操作過程中實時顯示進度。用戶可以隨時查看當前操作狀態。 39 | - **啟用調試模式**: 勾選此選項以啟用調試模式,顯示更多調試信息。 40 | - **保存 Nonces**: 勾選此選項以保存 Nonces 和密鑰文件。 41 | - **保留 Nonces**: 勾選此選項以在恢復密鑰後保留 Flipper Zero 上的 Nonces。 42 | - **Nonces 文件**: 選擇一個 `.nonces` 文件來從中恢復密鑰。 43 | - **運行**: 點擊此按鈕開始執行 FlipperNestedRecovery 的操作。 44 | - **停止**: 在操作過程中可以點擊此按鈕終止操作。 45 | - **關於**: 查看關於本程序的信息。 46 | 47 | ### 3. 運行與終止 48 | 49 | - **運行程序**: 輸入必要的參數後,點擊 `運行` 按鈕,程序將開始執行 FlipperNestedRecovery 工具。操作過程中實時顯示進度,所有結果將在執行完成後顯示。 50 | - **終止操作**: 如果需要中止操作,點擊 `停止` 按鈕,程序將嘗試終止所有相關進程。用戶在任何時候都可以通過點擊 `停止` 按鈕來終止當前操作,程序會安全地關閉所有相關進程。 51 | 52 | ### 4. 注意事項 53 | 54 | - **連接 Flipper Zero**: 請確保 Flipper Zero 通過 USB 線連接,並且沒有被任何其他軟體(例如 `./fbt log`、`qFlipper`、`lab.flipper.net`)佔用。 55 | - **檢查 Flipper 設備**:使用前,請確保 Flipper Zero 已正確連接,且處於待機狀態。 56 | 57 | ## 特別鳴謝 58 | 59 | 在此特別感謝以下個人和項目的支持與貢獻: 60 | 61 | - **宅人改造家**:感謝他提供nonces文件並協助測試,幫助我找出了軟體中的一些bug。 62 | - **AloneLiberty**:感謝他開發了原始的[FlipperNestedRecovery](https://github.com/AloneLiberty/FlipperNestedRecovery)工具,本項目基於其工作進行開發。 63 | 64 | 特別感謝所有在項目開發過程中提供反饋和建議的用戶,你們的支持是我們持續改進的動力。 65 | 66 | ## 免責聲明 67 | 68 | 本軟體可能包含缺陷或錯誤,作者不對本軟體的性能或效果作出任何明示或暗示的保證,包括但不限於適銷性、特定用途適用性和非侵權性。無論是在合同訴訟、侵權訴訟或其他法律訴訟中,作者均不對因使用或無法使用本軟體而導致的任何損害、損失或其他責任負責。 -------------------------------------------------------------------------------- /hacker.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldip/FlipperNestedRecovery-GUI/79aff2118748f7e7538cbe5b40da467b8266d76b/hacker.icns -------------------------------------------------------------------------------- /hacker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oldip/FlipperNestedRecovery-GUI/79aff2118748f7e7538cbe5b40da467b8266d76b/hacker.ico -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | from distutils.core import Extension 3 | import sys 4 | import setuptools 5 | 6 | include_dirs = [] 7 | library_dirs = [] 8 | extra_compile_args = [] 9 | extra_link_args = [] 10 | libraries = ["lzma"] 11 | 12 | if os.name == "nt": 13 | include_dirs = ["build\\pthreads", "build\\lzma"] 14 | extra_compile_args = ["/D_CRT_SECURE_NO_WARNINGS", "-DNEED_FTIME"] 15 | libraries.extend(["pthreadVC2", "Ws2_32"]) 16 | elif sys.platform == "darwin": 17 | # 获取 Homebrew 前缀 18 | homebrew_prefix = os.popen('brew --prefix').read().strip() 19 | include_dirs.append(os.path.join(homebrew_prefix, 'include')) 20 | library_dirs.append(os.path.join(homebrew_prefix, 'lib')) 21 | extra_compile_args.append('-I' + os.path.join(homebrew_prefix, 'include')) 22 | extra_link_args.append('-L' + os.path.join(homebrew_prefix, 'lib')) 23 | 24 | nested_solver = Extension("nested", 25 | sources=["NestedSolver/python.c", "NestedSolver/crapto1.c", "NestedSolver/library.c", 26 | "NestedSolver/bucketsort.c", "NestedSolver/crypto1.c", "NestedSolver/progress.c"], 27 | include_dirs=include_dirs, library_dirs=include_dirs, extra_compile_args=extra_compile_args, 28 | libraries=libraries) 29 | 30 | hardnested_solver = Extension("hardnested", sources=["HardNestedSolver/pm3/ui.c", "HardNestedSolver/pm3/util.c", 31 | "HardNestedSolver/cmdhfmfhard.c", "HardNestedSolver/library.c", 32 | "HardNestedSolver/pm3/commonutil.c", "HardNestedSolver/crapto1.c", 33 | "HardNestedSolver/bucketsort.c", "HardNestedSolver/crypto1.c", 34 | "HardNestedSolver/hardnested/hardnested_bf_core.c", 35 | "HardNestedSolver/hardnested/hardnested_bruteforce.c", 36 | "HardNestedSolver/hardnested/hardnested_bitarray_core.c", 37 | "HardNestedSolver/hardnested/tables.c", 38 | "HardNestedSolver/pm3/util_posix.c", 39 | "HardNestedSolver/python.c"], include_dirs=include_dirs, 40 | library_dirs=include_dirs, extra_compile_args=extra_compile_args, libraries=libraries) 41 | 42 | with open("README.md", "r", encoding="utf-8") as fh: 43 | long_description = fh.read() 44 | 45 | setuptools.setup(name="FlipperNested", version="2.3.5", author="AloneLiberty", maintainer="oldip", 46 | description="Recover keys from collected nonces", long_description=long_description, 47 | long_description_content_type="text/markdown", 48 | url="https://github.com/AloneLiberty/FlipperNestedRecovery", 49 | entry_points={"console_scripts": ["FlipperNested = FlipperNested.cli:main"]}, 50 | install_requires=["protobuf>4", "pyserial"], ext_modules=[nested_solver, hardnested_solver], 51 | packages=["FlipperNested", "FlipperNested.proto"], python_requires=">=3.8", 52 | classifiers=["Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", 53 | "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", 54 | "Programming Language :: Python :: 3.12", 55 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 56 | "Operating System :: MacOS", "Operating System :: POSIX :: Linux", 57 | "Operating System :: Microsoft :: Windows"], 58 | headers=["NestedSolver/library.h", "NestedSolver/parity.h", 59 | "NestedSolver/crapto1.h", "NestedSolver/bucketsort.h", 60 | "NestedSolver/progress.h", "HardNestedSolver/pm3/util.h", "HardNestedSolver/pm3/ui.h", 61 | "HardNestedSolver/pm3/common.h", 62 | "HardNestedSolver/pm3/util_posix.h", "HardNestedSolver/pm3/ansi.h", 63 | "HardNestedSolver/pm3/commonutil.h", "HardNestedSolver/pm3/emojis_alt.h", 64 | "HardNestedSolver/pm3/emojis.h", "HardNestedSolver/bucketsort.h", 65 | "HardNestedSolver/crapto1.h", "HardNestedSolver/parity.h", 66 | "HardNestedSolver/hardnested/hardnested_benchmark_data.h", 67 | "HardNestedSolver/hardnested/hardnested_bf_core.h", 68 | "HardNestedSolver/hardnested/hardnested_bitarray_core.h", 69 | "HardNestedSolver/hardnested/hardnested_bruteforce.h", "HardNestedSolver/hardnested/tables.h", 70 | "HardNestedSolver/library.h", "HardNestedSolver/cmdhfmfhard.h"]) 71 | -------------------------------------------------------------------------------- /tests/test_calculate.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import pathlib 3 | from FlipperNested.main import FlipperNested 4 | 5 | 6 | def test_calculate(): 7 | keys = FlipperNested.calculate_keys(0x29c6824a, 0x292daf7a, 0xff3f91be, 1111, 0x48f9f977, 0xffbf94fd, 1100, [0, 0], 8 | False) 9 | assert keys == "ffffffffffff;" 10 | 11 | 12 | def test_calculate_full(): 13 | keys = FlipperNested.calculate_keys(0x9a22bf95, 0x60011fd9, 0x21098875, 1111, 0xd274da74, 0x6a12a32f, 1111, 14 | [805, 810], False) 15 | assert keys == "20b9f1ebffff;9088dcfc2ffe;45baf6bffeff;15f9fefeaffe;ffffffffffff;" 16 | 17 | 18 | def test_calculate_hard(): 19 | file = str(pathlib.Path(__file__).parent.resolve()) + "/.clean_nonces" 20 | if os.path.isfile(file): 21 | keys = FlipperNested.calculate_keys_hard(0x773D6B86, file) 22 | assert keys == "89eca97f8c2a;" 23 | -------------------------------------------------------------------------------- /tests/test_import.py: -------------------------------------------------------------------------------- 1 | def test_import(): 2 | from FlipperNested.main import FlipperNested 3 | flipper = FlipperNested() 4 | assert flipper.__class__.__name__ == "FlipperNested" -------------------------------------------------------------------------------- /tests/test_parse.py: -------------------------------------------------------------------------------- 1 | from FlipperNested.main import FlipperNested 2 | 3 | 4 | def test_parse(): 5 | values = FlipperNested.parse_line( 6 | "Nested: Key B cuid 0x9a22bf95 nt0 0x60011fd9 ks0 0x21098875 par0 1111 nt1 0xd274da74 ks1 0x6a12a32f par1 " 7 | "1111 sec 15") 8 | assert values == [0x9a22bf95, 0x60011fd9, 0x21098875, 1111, 0xd274da74, 0x6a12a32f, 1111, 15, 'B'] 9 | --------------------------------------------------------------------------------