maze_python/mylock.py

398 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import json
import random
from Lock import PasswordLock
method1_logs = []
method2_logs = []
method3_logs = []
def is_prime(n):
"""判断一个数字是否是素数"""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
def satisfies_prime_unique_condition(digits):
"""检查是否满足[-1, -1]条件:每位密码为素数且不重复"""
return all(is_prime(d) for d in digits) and len(set(digits)) == 3
def crack_method1(conditions, stored_hash):
"""从高位到低位回溯(第一位→第二位→第三位)"""
tries = 1
found_password = None
found = False
lock = PasswordLock()
# 根据线索生成每位的合法数字范围
digit_options = [[] for _ in range(3)]
for i in range(3):
for d in range(10):
valid = True
for cond in conditions:
if cond == [-1, -1]:
if not is_prime(d):
valid = False
break
elif len(cond) == 2:
a, t = cond
a = abs(a)
if a - 1 == i and ((t == 0 and d % 2 != 0) or (t == 1 and d % 2 != 1)):
valid = False
break
elif len(cond) == 3:
if cond[i] != -1 and d != cond[i]:
valid = False
break
if valid:
digit_options[i].append(d)
for i in range(3):
random.shuffle(digit_options[i])
def backtrack(index, current_digits):
nonlocal tries, found, found_password
if found:
return
if index == 3:
password = "".join(map(str, current_digits))
calculated_hash = lock.hash_password(password)
method1_logs.append(password)
if calculated_hash == stored_hash:
found_password = password
found = True
return
tries += 1
return
for digit in digit_options[index]:
current_digits.append(digit)
backtrack(index + 1, current_digits)
current_digits.pop()
if found:
return
backtrack(0, [])
return [found_password] if found_password else [], tries
def crack_method2(conditions, stored_hash):
"""按条件优先级排序的回溯方法:先处理约束最多的位置"""
tries = 1
found_password = None
found = False
lock = PasswordLock()
digit_options = [[] for _ in range(3)]
for i in range(3):
for d in range(10):
valid = True
for cond in conditions:
if cond == [-1, -1]:
if not is_prime(d):
valid = False
break
elif len(cond) == 2:
a, t = cond
a = abs(a)
if a - 1 == i and ((t == 0 and d % 2 != 0) or (t == 1 and d % 2 != 1)):
valid = False
break
elif len(cond) == 3:
if cond[i] != -1 and d != cond[i]:
valid = False
break
if valid:
digit_options[i].append(d)
for i in range(3):
random.shuffle(digit_options[i])
sorted_indices = sorted(range(3), key=lambda x: len(digit_options[x]))
def backtrack(index, current_digits):
nonlocal tries, found, found_password
if found:
return
if index == 3:
reordered = [0, 0, 0]
for i, pos in enumerate(sorted_indices):
reordered[pos] = current_digits[i]
password = "".join(map(str, reordered))
calculated_hash = lock.hash_password(password)
method2_logs.append(password)
if calculated_hash == stored_hash:
found_password = password
found = True
return
tries += 1
return
current_index = sorted_indices[index]
for digit in digit_options[current_index]:
current_digits.append(digit)
backtrack(index + 1, current_digits)
current_digits.pop()
if found:
return
backtrack(0, [])
return [found_password] if found_password else [], tries
def crack_method3(conditions, stored_hash):
"""双向回溯:从左右两侧同时构建密码"""
tries = 1
found_password = None
found = False
lock = PasswordLock()
digit_options = [[] for _ in range(3)]
for i in range(3):
for d in range(10):
valid = True
for cond in conditions:
if cond == [-1, -1]:
if not is_prime(d):
valid = False
break
elif len(cond) == 2:
a, t = cond
a = abs(a)
if a - 1 == i and ((t == 0 and d % 2 != 0) or (t == 1 and d % 2 != 1)):
valid = False
break
elif len(cond) == 3:
if cond[i] != -1 and d != cond[i]:
valid = False
break
if valid:
digit_options[i].append(d)
for i in range(3):
random.shuffle(digit_options[i])
def backtrack(left_pos, right_pos, current_digits):
nonlocal tries, found, found_password
if found:
return
if len(current_digits) == 3:
password = "".join(map(str, current_digits))
calculated_hash = lock.hash_password(password)
method3_logs.append(password)
if calculated_hash == stored_hash:
found_password = password
found = True
return
tries += 1
return
# 根据当前方向选择位置
if left_pos <= right_pos:
for digit in digit_options[left_pos]:
current_digits.append(digit)
backtrack(left_pos + 1, right_pos, current_digits)
current_digits.pop()
if found:
return
else:
for digit in digit_options[right_pos]:
current_digits.insert(0, digit)
backtrack(left_pos, right_pos - 1, current_digits)
current_digits.pop(0)
if found:
return
backtrack(2, 0, [])
return [found_password] if found_password else [], tries
def format_json(data):
"""自定义 JSON 格式化函数"""
lines = ['{']
# 格式化 C 线索部分
if "C" in data:
lines.append(' "C": [')
for i, item in enumerate(data["C"]):
lines.append(f" {json.dumps(item, ensure_ascii=False)}{',' if i < len(data['C']) - 1 else ''}")
lines.append(' ],')
# 格式化 L 哈希值
if "L" in data:
lines.append(f' "L": {json.dumps(data["L"], ensure_ascii=False)},')
# 格式化 password
if "password" in data:
lines.append(f' "password": {json.dumps(data["password"], ensure_ascii=False)},')
# 格式化 results
if "results" in data:
lines.append(' "results": {')
result_items = data["results"]
method_names = list(result_items.keys())
for i, method in enumerate(method_names):
method_data = result_items[method]
lines.append(f' "{method}": {{')
# 格式化 tries
if "tries" in method_data:
lines.append(f' "tries": {method_data["tries"]},')
# 格式化 password
if "password" in method_data:
lines.append(f' "password": {json.dumps(method_data["password"], ensure_ascii=False)},')
# 格式化 logs
if "logs" in method_data:
lines.append(' "logs": [')
logs = method_data["logs"]
for j, log in enumerate(logs):
lines.append(f' "{log}"{"," if j < len(logs) - 1 else ""}')
lines.append(' ]')
lines.append(f' }}{"," if i < len(method_names) - 1 else ""}')
lines.append(' }')
lines.append('}')
return "\n".join(lines)
def main():
# 输入和输出路径
input_dir = r"password_test"
output_dir = r"password_output"
# 如果输出目录不存在,则创建
os.makedirs(output_dir, exist_ok=True)
# 遍历输入目录下所有 .json 文件
for filename in os.listdir(input_dir):
if filename.endswith(".json"):
input_file_path = os.path.join(input_dir, filename)
output_file_path = os.path.join(output_dir, filename)
with open(input_file_path, 'r', encoding='utf-8') as f:
try:
# 读取原始 JSON 文本内容(字符串)
original_content = f.read()
# 解析为字典用于处理
sample_data = json.loads(original_content)
except json.JSONDecodeError:
print(f"跳过无效的 JSON 文件: {filename}")
continue
conditions = sample_data.get("C", [])
stored_hash = sample_data.get("L", "")
print(f"\n正在处理文件: {filename}")
# 清空之前的尝试记录
global method1_logs, method2_logs, method3_logs
method1_logs.clear()
method2_logs.clear()
method3_logs.clear()
# 调用三种方法破解密码
pwd1, tries1 = crack_method1(conditions, stored_hash)
pwd2, tries2 = crack_method2(conditions, stored_hash)
pwd3, tries3 = crack_method3(conditions, stored_hash)
# 找到第一个非空结果作为最终密码
matched_passwords = []
if pwd1:
matched_passwords.append(pwd1[0])
if pwd2:
matched_passwords.append(pwd2[0])
if pwd3:
matched_passwords.append(pwd3[0])
first_match = matched_passwords[0] if matched_passwords else ""
# 打印每个方法的尝试次数
print(f"方法1尝试次数: {tries1}")
print(f"方法2尝试次数: {tries2}")
print(f"方法3尝试次数: {tries3}")
# 计算并打印平均尝试次数
avg_tries = (tries1 + tries2 + tries3) / 3
print(f"平均尝试次数: {avg_tries:.1f}")
# 更新 JSON 内容中的结果部分
result_update = {
"password": first_match,
"results": {
"method1": {
"tries": tries1,
"password": list(map(int, first_match)) if first_match else [],
"logs": method1_logs.copy()
},
"method2": {
"tries": tries2,
"password": list(map(int, first_match)) if first_match else [],
"logs": method2_logs.copy()
},
"method3": {
"tries": tries3,
"password": list(map(int, first_match)) if first_match else [],
"logs": method3_logs.copy()
}
},
}
# 加载原始内容为 dict 并更新关键字段
data = json.loads(original_content)
data.update(result_update)
# 使用自定义格式化函数生成 JSON 字符串
formatted_json = format_json(data)
# 写入文件
with open(output_file_path, 'w', encoding='utf-8') as f:
f.write(formatted_json)
print(f"结果已保存至: {output_file_path}")
# 新增:比较写入内容是否与原始内容一致(忽略 results 字段中的 tries
with open(output_file_path, 'r', encoding='utf-8') as f:
written_content = f.read()
# 解析原始和写入后的内容为 dict
original_dict = json.loads(original_content)
written_dict = json.loads(written_content)
# 删除 results 字段用于比较
original_dict.pop("results", None)
written_dict.pop("results", None)
# 重新序列化为字符串进行比较
if json.dumps(original_dict, sort_keys=True) == json.dumps(written_dict, sort_keys=True):
print("输出内容(除 results 外)与原始内容一致")
else:
print("输出内容(除 results 外)与原始内容不一致")
if __name__ == "__main__":
main()