398 lines
13 KiB
Python
398 lines
13 KiB
Python
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() |