密码学第一次实验挑战 1Convert hex to base64本题的核心步骤是实现底层数据格式的正确解码与再编码。首先需要调用环境内置的十六进制处理函数将输入的十六进制字符串转化为计算机底层的原始字节流从而彻底摆脱字符串层面操作带来的编码干扰。接着将这一串原始字节作为输入传递给标准 Base64 编码模块进行编码计算最后将生成的 Base64 字节流解码为标准的 ASCII 字符串输出。此步骤的核心要义在于理解密码学算法的操作对象始终是底层的二进制字节流而非表层的文本字符串。importbase64defhex_to_b64(hex_str):# 十六进制字符串转换为原始字节串raw_bytesbytes.fromhex(hex_str)# 字节串转换为 base64 编码并解码为普通字符串输出b64_bytesbase64.b64encode(raw_bytes)returnb64_bytes.decode(ascii)# 测试用例hex_input49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6dexpected_outputSSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29tprint(hex_to_b64(hex_input))asserthex_to_b64(hex_input)expected_outputprint([] 挑战 1 通过)挑战 2Fixed XOR本题的步骤是实现两组等长数据的按位异或。首先接收两个等长的十六进制字符串并分别将它们解码为对应的二进制字节流数组。随后利用循环结构或迭代器将这两个字节数组在相同索引位置上的字节进行一一配对。针对每一对字节执行 Python 的按位异或运算符^将运算产生的全新字节顺序组合成一个新的字节数组。最后将这个异或后产生的原始字节数组重新格式化为十六进制字符串形式输出。deffixed_xor(hex_str1,hex_str2):bytes1bytes.fromhex(hex_str1)bytes2bytes.fromhex(hex_str2)# 两个字节串逐字节异或xor_bytesbytes([b1^b2forb1,b2inzip(bytes1,bytes2)])returnxor_bytes.hex()hex11c0111001f010100061a024b53535009181chex2686974207468652062756c6c277320657965expected_result746865206b696420646f6e277420706c6179print(fixed_xor(hex1,hex2))assertfixed_xor(hex1,hex2)expected_resultprint([] 挑战 2 通过)挑战 3Single-byte XOR cipher由于单字节的密钥空间极小仅包含 0 到 255 共 256 种可能性因此本题的破解步骤采用完全穷举法。首先将十六进制密文转化为原始字节流。然后构建一个从 0 循环到 255 的外层循环在每次循环中使用当前的候选单个字节与整个密文字节流中的每一个字节进行异或解密从而生成 256 个候选明文数组。针对每一个候选明文调用预先设计好的英文文本频率评分函数该函数会遍历文本并根据常见英文字母及空格的统计权重进行累加打分。最后比对并记录全局得分最高的那次循环其对应的循环变量即为正确密钥解密出的文本即为明文。defget_english_score(text_bytes):根据英文字母频率给字节流打分character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}# 统计出现过的英文字母得分总和returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defsingle_byte_xor_crack(ciphertext_bytes):best_score0best_plaintextbbest_key0forkeyinrange(256):# 尝试每一个可能的 key 进行 XOR 解密plaintextbytes([b^keyforbinciphertext_bytes])scoreget_english_score(plaintext)ifscorebest_score:best_scorescore best_plaintextplaintext best_keykeyreturnbest_score,best_plaintext,best_key# 测试用例hex_cipher1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736cipher_bytesbytes.fromhex(hex_cipher)score,plaintext,keysingle_byte_xor_crack(cipher_bytes)print(f[] 挑战 3 通过解密结果:{plaintext.decode(ascii)}(密钥:{chr(key)}))挑战 4Detect single-character XOR本题是在挑战 3 的基础之上增加了一层文件流的处理和全局最优解的筛选。首先需要以只读模式打开题目提供的包含大量十六进制字符串的文本文件并按行进行读取和净化。对于读取到的每一行字符串首先将其转化为原始字节流然后完整地嵌入到挑战 3 所实现的单字节 XOR 暴力破解与频率打分程序中。在遍历文件的整个过程中维护一个全局最高分变量和对应的明文缓冲区一旦某一行在某个密钥下的解密打分超过了当前记录的最高分则更新全局最优解。当文件全部读取完毕后留存下来的便是唯一被加密的那行文本的解密明文。defget_english_score(text_bytes):根据英文字母频率给字节流打分character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}# 统计出现过的英文字母得分总和returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defsingle_byte_xor_crack(ciphertext_bytes):best_score0best_plaintextbbest_key0forkeyinrange(256):# 尝试每一个可能的 key 进行 XOR 解密plaintextbytes([b^keyforbinciphertext_bytes])scoreget_english_score(plaintext)ifscorebest_score:best_scorescore best_plaintextplaintext best_keykeyreturnbest_score,best_plaintext,best_keydefdetect_single_byte_xor(file_path):best_overall_score0best_overall_plaintextbtry:withopen(file_path,r)asf:linesf.read().splitlines()forlineinlines:cipher_bytesbytes.fromhex(line)score,plaintext,keysingle_byte_xor_crack(cipher_bytes)ifscorebest_overall_score:best_overall_scorescore best_overall_plaintextplaintextreturnbest_overall_plaintext.decode(ascii,errorsignore)exceptFileNotFoundError:return未找到 4.txt 数据文件请确保文件存在。resultdetect_single_byte_xor(4.txt)print(f[] 挑战 4 结果:{result})挑战 5Implement repeating-key XOR本题的步骤是实现一个多表代换密码的加密器。首先将多行的明文文本以及给定的多字节密钥本题为 “ICE”统一转换为底层的原始字节流。接着遍历明文字节流中的每一个字节在处理第 i 个明文字节时通过对明文索引 i 与密钥长度进行取模运算i % len(key)从而动态且循环地定位到当前应该使用的密钥字节。将该明文字节与定位到的密钥字节进行按位异或并将结果追加到密文缓冲区中。遍历结束后将密文缓冲区中的原始字节流整体转换为十六进制字符串输出。defrepeating_key_xor(plaintext_bytes,key_bytes):ciphertextbytearray()key_lenlen(key_bytes)fori,binenumerate(plaintext_bytes):key_charkey_bytes[i%key_len]ciphertext.append(b^key_char)returnciphertext.hex()stanza(Burning em, if you aint quick and nimble\nI go crazy when I hear a cymbal)keyICEexpected_hex(0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f)# 将字符串转换为 bytesencrypted_hexrepeating_key_xor(stanza.encode(ascii),key.encode(ascii))print(encrypted_hex)assertencrypted_hexexpected_hexprint([] 挑战 5 通过)挑战 6Break repeating-key XOR本题是本章最具挑战性的多步骤复合破译任务。第一步是推测密钥长度编写汉明距离计算函数让猜测长度 KEYSIZE 从 2 遍历到 40每次切取密文前四块并计算两两之间的汉明距离总和除以 KEYSIZE 进行归一化找出归一化距离最小的 KEYSIZE 作为真实密钥长度。第二步是矩阵转置依据确定的 KEYSIZE 将整段密文切分成等长的若干数据块然后创建一个包含 KEYSIZE 个空存储器的集合遍历密文将每个块的第 1 个字节放入第 1 个存储器第 2 个字节放入第 2 个存储器依此类推完成转置。第三步是单字节破译与拼装转置后的每个存储器内的数据都是被同一个密钥字节加密的直接调用挑战 3 的单字节破解器对这 KEYSIZE 个存储器分别进行穷举和频率打分抓取各自得分最高的密钥字节按顺序拼接便还原出了完整的循环密钥。最后一步使用该密钥对原始密文进行循环异或解密输出最终明文。importbase64# 复用挑战 3 的频率打分函数defget_english_score(text_bytes):character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defhamming_distance(b1,b2):计算两个字节串的汉明距离returnsum(bin(byte1^byte2).count(1)forbyte1,byte2inzip(b1,b2))defbreak_single_byte_xor(block_bytes):破解单字节 XORbest_score0best_key0forkeyinrange(256):decryptedbytes([b^keyforbinblock_bytes])scoreget_english_score(decrypted)ifscorebest_score:best_scorescore best_keykeyreturnbest_keydeffind_keysize(ciphertext_bytes):寻找最有可能的密钥长度normalized_distances[]forkeysizeinrange(2,41):iflen(ciphertext_bytes)keysize*4:break# 取前 4 个块求平均汉明距离以提高准确度blocks[ciphertext_bytes[i*keysize:(i1)*keysize]foriinrange(4)]dist1hamming_distance(blocks[0],blocks[1])dist2hamming_distance(blocks[0],blocks[2])dist3hamming_distance(blocks[0],blocks[3])dist4hamming_distance(blocks[1],blocks[2])dist5hamming_distance(blocks[1],blocks[3])dist6hamming_distance(blocks[2],blocks[3])avg_distance(dist1dist2dist3dist4dist5dist6)/6normalized_distanceavg_distance/keysize normalized_distances.append((normalized_distance,keysize))normalized_distances.sort()returnnormalized_distances[0][1]defsolve_challenge_6(file_path):try:withopen(file_path,r)asf:encrypted_bytesbase64.b64decode(f.read())# 1. 找出 KEYSIZEkeysizefind_keysize(encrypted_bytes)# 2. 矩阵转置transposed_blocks[bytearray()for_inrange(keysize)]fori,byteinenumerate(encrypted_bytes):transposed_blocks[i%keysize].append(byte)# 3. 逐个击破单字节 XOR 得到密钥keybytearray()forblockintransposed_blocks:key.append(break_single_byte_xor(block))# 4. 解密plaintextbytearray()fori,byteinenumerate(encrypted_bytes):plaintext.append(byte^key[i%keysize])returnkey.decode(ascii),plaintext.decode(ascii,errorsignore)exceptFileNotFoundError:return未找到文件,请提供 6.txt# 运行代码key,plaintextsolve_challenge_6(6.txt)print(f[] 找到密钥:{key})print(f[] 明文片段:{plaintext[:100]}...)挑战 7MTC3 Cracking SHA1-Hashed Passwords本题的步骤展示了如何利用物理侧信道痕迹实施精准的哈希密码爆破。首先通过对带有指纹粉的键盘图像进行视觉痕迹分析剔除仅用于导航的数字小键盘后精确锁定主键盘上被按过的 8 个物理按键。由于实验环境基于德国 QWERTZ 键盘布局需特殊处理 Shift 组合键带来的符号映射差异将这 8 个物理按键转化为 8 组、每组包含 2 种可能状态即是否按下 Shift 键的字符矩阵。接着利用笛卡尔积算法生成这 8 个按键的全部 2^8256 种确切的字符组合状态。由于每个物理按键仅被按过一次针对这 256 种组合中的每一种调用全排列算法生成它们在输入先后顺序上的所有排列可能性单次组合产生 8!40320 种序列。最后在双层嵌套循环中将每次生成的 8 位候选字符串进行 SHA-1 哈希计算并将其十六进制摘要与目标哈希值进行碰撞比对一旦哈希值完全吻合则立即中断程序并输出正确的明文密码。importhashlibimportitertools# 目标 SHA1 哈希值target_hash67ae1a64661ac8b4494666f58c4822408dd0a3e4# 物理按键对应的两种可能性受德国键盘布局影响keys_possibilities[[Q,q],[W,w],[I,i],[N,n],[5,%],[8,(],[0,],# 德语键盘[,*]# 德语键盘]print([*] 正在生成所有可能的字符组合并进行哈希碰撞请稍候...)# 1. itertools.product 遍历每个键的 2 种状态组合 (共 256 种)forkey_stateinitertools.product(*keys_possibilities):# 2. itertools.permutations 对选出的 8 个具体字符进行全排列 (共 40,320 种)forperminitertools.permutations(key_state):candidate_password.join(perm)# 3. 计算当前候选密码的 SHA1 值candidate_hashhashlib.sha1(candidate_password.encode(utf-8)).hexdigest()# 4. 对比哈希值ifcandidate_hashtarget_hash:print(f\n[] 破解成功)print(f[] 目标密码是:{candidate_password})exit(0)
现代密码学实验一
密码学第一次实验挑战 1Convert hex to base64本题的核心步骤是实现底层数据格式的正确解码与再编码。首先需要调用环境内置的十六进制处理函数将输入的十六进制字符串转化为计算机底层的原始字节流从而彻底摆脱字符串层面操作带来的编码干扰。接着将这一串原始字节作为输入传递给标准 Base64 编码模块进行编码计算最后将生成的 Base64 字节流解码为标准的 ASCII 字符串输出。此步骤的核心要义在于理解密码学算法的操作对象始终是底层的二进制字节流而非表层的文本字符串。importbase64defhex_to_b64(hex_str):# 十六进制字符串转换为原始字节串raw_bytesbytes.fromhex(hex_str)# 字节串转换为 base64 编码并解码为普通字符串输出b64_bytesbase64.b64encode(raw_bytes)returnb64_bytes.decode(ascii)# 测试用例hex_input49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6dexpected_outputSSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29tprint(hex_to_b64(hex_input))asserthex_to_b64(hex_input)expected_outputprint([] 挑战 1 通过)挑战 2Fixed XOR本题的步骤是实现两组等长数据的按位异或。首先接收两个等长的十六进制字符串并分别将它们解码为对应的二进制字节流数组。随后利用循环结构或迭代器将这两个字节数组在相同索引位置上的字节进行一一配对。针对每一对字节执行 Python 的按位异或运算符^将运算产生的全新字节顺序组合成一个新的字节数组。最后将这个异或后产生的原始字节数组重新格式化为十六进制字符串形式输出。deffixed_xor(hex_str1,hex_str2):bytes1bytes.fromhex(hex_str1)bytes2bytes.fromhex(hex_str2)# 两个字节串逐字节异或xor_bytesbytes([b1^b2forb1,b2inzip(bytes1,bytes2)])returnxor_bytes.hex()hex11c0111001f010100061a024b53535009181chex2686974207468652062756c6c277320657965expected_result746865206b696420646f6e277420706c6179print(fixed_xor(hex1,hex2))assertfixed_xor(hex1,hex2)expected_resultprint([] 挑战 2 通过)挑战 3Single-byte XOR cipher由于单字节的密钥空间极小仅包含 0 到 255 共 256 种可能性因此本题的破解步骤采用完全穷举法。首先将十六进制密文转化为原始字节流。然后构建一个从 0 循环到 255 的外层循环在每次循环中使用当前的候选单个字节与整个密文字节流中的每一个字节进行异或解密从而生成 256 个候选明文数组。针对每一个候选明文调用预先设计好的英文文本频率评分函数该函数会遍历文本并根据常见英文字母及空格的统计权重进行累加打分。最后比对并记录全局得分最高的那次循环其对应的循环变量即为正确密钥解密出的文本即为明文。defget_english_score(text_bytes):根据英文字母频率给字节流打分character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}# 统计出现过的英文字母得分总和returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defsingle_byte_xor_crack(ciphertext_bytes):best_score0best_plaintextbbest_key0forkeyinrange(256):# 尝试每一个可能的 key 进行 XOR 解密plaintextbytes([b^keyforbinciphertext_bytes])scoreget_english_score(plaintext)ifscorebest_score:best_scorescore best_plaintextplaintext best_keykeyreturnbest_score,best_plaintext,best_key# 测试用例hex_cipher1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736cipher_bytesbytes.fromhex(hex_cipher)score,plaintext,keysingle_byte_xor_crack(cipher_bytes)print(f[] 挑战 3 通过解密结果:{plaintext.decode(ascii)}(密钥:{chr(key)}))挑战 4Detect single-character XOR本题是在挑战 3 的基础之上增加了一层文件流的处理和全局最优解的筛选。首先需要以只读模式打开题目提供的包含大量十六进制字符串的文本文件并按行进行读取和净化。对于读取到的每一行字符串首先将其转化为原始字节流然后完整地嵌入到挑战 3 所实现的单字节 XOR 暴力破解与频率打分程序中。在遍历文件的整个过程中维护一个全局最高分变量和对应的明文缓冲区一旦某一行在某个密钥下的解密打分超过了当前记录的最高分则更新全局最优解。当文件全部读取完毕后留存下来的便是唯一被加密的那行文本的解密明文。defget_english_score(text_bytes):根据英文字母频率给字节流打分character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}# 统计出现过的英文字母得分总和returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defsingle_byte_xor_crack(ciphertext_bytes):best_score0best_plaintextbbest_key0forkeyinrange(256):# 尝试每一个可能的 key 进行 XOR 解密plaintextbytes([b^keyforbinciphertext_bytes])scoreget_english_score(plaintext)ifscorebest_score:best_scorescore best_plaintextplaintext best_keykeyreturnbest_score,best_plaintext,best_keydefdetect_single_byte_xor(file_path):best_overall_score0best_overall_plaintextbtry:withopen(file_path,r)asf:linesf.read().splitlines()forlineinlines:cipher_bytesbytes.fromhex(line)score,plaintext,keysingle_byte_xor_crack(cipher_bytes)ifscorebest_overall_score:best_overall_scorescore best_overall_plaintextplaintextreturnbest_overall_plaintext.decode(ascii,errorsignore)exceptFileNotFoundError:return未找到 4.txt 数据文件请确保文件存在。resultdetect_single_byte_xor(4.txt)print(f[] 挑战 4 结果:{result})挑战 5Implement repeating-key XOR本题的步骤是实现一个多表代换密码的加密器。首先将多行的明文文本以及给定的多字节密钥本题为 “ICE”统一转换为底层的原始字节流。接着遍历明文字节流中的每一个字节在处理第 i 个明文字节时通过对明文索引 i 与密钥长度进行取模运算i % len(key)从而动态且循环地定位到当前应该使用的密钥字节。将该明文字节与定位到的密钥字节进行按位异或并将结果追加到密文缓冲区中。遍历结束后将密文缓冲区中的原始字节流整体转换为十六进制字符串输出。defrepeating_key_xor(plaintext_bytes,key_bytes):ciphertextbytearray()key_lenlen(key_bytes)fori,binenumerate(plaintext_bytes):key_charkey_bytes[i%key_len]ciphertext.append(b^key_char)returnciphertext.hex()stanza(Burning em, if you aint quick and nimble\nI go crazy when I hear a cymbal)keyICEexpected_hex(0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f)# 将字符串转换为 bytesencrypted_hexrepeating_key_xor(stanza.encode(ascii),key.encode(ascii))print(encrypted_hex)assertencrypted_hexexpected_hexprint([] 挑战 5 通过)挑战 6Break repeating-key XOR本题是本章最具挑战性的多步骤复合破译任务。第一步是推测密钥长度编写汉明距离计算函数让猜测长度 KEYSIZE 从 2 遍历到 40每次切取密文前四块并计算两两之间的汉明距离总和除以 KEYSIZE 进行归一化找出归一化距离最小的 KEYSIZE 作为真实密钥长度。第二步是矩阵转置依据确定的 KEYSIZE 将整段密文切分成等长的若干数据块然后创建一个包含 KEYSIZE 个空存储器的集合遍历密文将每个块的第 1 个字节放入第 1 个存储器第 2 个字节放入第 2 个存储器依此类推完成转置。第三步是单字节破译与拼装转置后的每个存储器内的数据都是被同一个密钥字节加密的直接调用挑战 3 的单字节破解器对这 KEYSIZE 个存储器分别进行穷举和频率打分抓取各自得分最高的密钥字节按顺序拼接便还原出了完整的循环密钥。最后一步使用该密钥对原始密文进行循环异或解密输出最终明文。importbase64# 复用挑战 3 的频率打分函数defget_english_score(text_bytes):character_frequencies{a:.08167,b:.01492,c:.02782,d:.04253,e:.12702,f:.02228,g:.02015,h:.06094,i:.06094,j:.00153,k:.00772,l:.04025,m:.02406,n:.06749,o:.07507,p:.01929,q:.00095,r:.05987,s:.06327,t:.09056,u:.02758,v:.00978,w:.02360,x:.00150,y:.01974,z:.00074, :.13000}returnsum([character_frequencies.get(chr(b).lower(),0)forbintext_bytes])defhamming_distance(b1,b2):计算两个字节串的汉明距离returnsum(bin(byte1^byte2).count(1)forbyte1,byte2inzip(b1,b2))defbreak_single_byte_xor(block_bytes):破解单字节 XORbest_score0best_key0forkeyinrange(256):decryptedbytes([b^keyforbinblock_bytes])scoreget_english_score(decrypted)ifscorebest_score:best_scorescore best_keykeyreturnbest_keydeffind_keysize(ciphertext_bytes):寻找最有可能的密钥长度normalized_distances[]forkeysizeinrange(2,41):iflen(ciphertext_bytes)keysize*4:break# 取前 4 个块求平均汉明距离以提高准确度blocks[ciphertext_bytes[i*keysize:(i1)*keysize]foriinrange(4)]dist1hamming_distance(blocks[0],blocks[1])dist2hamming_distance(blocks[0],blocks[2])dist3hamming_distance(blocks[0],blocks[3])dist4hamming_distance(blocks[1],blocks[2])dist5hamming_distance(blocks[1],blocks[3])dist6hamming_distance(blocks[2],blocks[3])avg_distance(dist1dist2dist3dist4dist5dist6)/6normalized_distanceavg_distance/keysize normalized_distances.append((normalized_distance,keysize))normalized_distances.sort()returnnormalized_distances[0][1]defsolve_challenge_6(file_path):try:withopen(file_path,r)asf:encrypted_bytesbase64.b64decode(f.read())# 1. 找出 KEYSIZEkeysizefind_keysize(encrypted_bytes)# 2. 矩阵转置transposed_blocks[bytearray()for_inrange(keysize)]fori,byteinenumerate(encrypted_bytes):transposed_blocks[i%keysize].append(byte)# 3. 逐个击破单字节 XOR 得到密钥keybytearray()forblockintransposed_blocks:key.append(break_single_byte_xor(block))# 4. 解密plaintextbytearray()fori,byteinenumerate(encrypted_bytes):plaintext.append(byte^key[i%keysize])returnkey.decode(ascii),plaintext.decode(ascii,errorsignore)exceptFileNotFoundError:return未找到文件,请提供 6.txt# 运行代码key,plaintextsolve_challenge_6(6.txt)print(f[] 找到密钥:{key})print(f[] 明文片段:{plaintext[:100]}...)挑战 7MTC3 Cracking SHA1-Hashed Passwords本题的步骤展示了如何利用物理侧信道痕迹实施精准的哈希密码爆破。首先通过对带有指纹粉的键盘图像进行视觉痕迹分析剔除仅用于导航的数字小键盘后精确锁定主键盘上被按过的 8 个物理按键。由于实验环境基于德国 QWERTZ 键盘布局需特殊处理 Shift 组合键带来的符号映射差异将这 8 个物理按键转化为 8 组、每组包含 2 种可能状态即是否按下 Shift 键的字符矩阵。接着利用笛卡尔积算法生成这 8 个按键的全部 2^8256 种确切的字符组合状态。由于每个物理按键仅被按过一次针对这 256 种组合中的每一种调用全排列算法生成它们在输入先后顺序上的所有排列可能性单次组合产生 8!40320 种序列。最后在双层嵌套循环中将每次生成的 8 位候选字符串进行 SHA-1 哈希计算并将其十六进制摘要与目标哈希值进行碰撞比对一旦哈希值完全吻合则立即中断程序并输出正确的明文密码。importhashlibimportitertools# 目标 SHA1 哈希值target_hash67ae1a64661ac8b4494666f58c4822408dd0a3e4# 物理按键对应的两种可能性受德国键盘布局影响keys_possibilities[[Q,q],[W,w],[I,i],[N,n],[5,%],[8,(],[0,],# 德语键盘[,*]# 德语键盘]print([*] 正在生成所有可能的字符组合并进行哈希碰撞请稍候...)# 1. itertools.product 遍历每个键的 2 种状态组合 (共 256 种)forkey_stateinitertools.product(*keys_possibilities):# 2. itertools.permutations 对选出的 8 个具体字符进行全排列 (共 40,320 种)forperminitertools.permutations(key_state):candidate_password.join(perm)# 3. 计算当前候选密码的 SHA1 值candidate_hashhashlib.sha1(candidate_password.encode(utf-8)).hexdigest()# 4. 对比哈希值ifcandidate_hashtarget_hash:print(f\n[] 破解成功)print(f[] 目标密码是:{candidate_password})exit(0)