概述
Quantum-Safe是来自于HTB(hackthebox.com)的一个容易级密码学挑战,完成该挑战所需要掌握的知识点在于基本的矩阵计算。
题目分析
相关的任务文件包括一个source.sage源代码和enc.txt文本文件。
source.sage给出了加密的计算方法,而enc.txt则是加密的结果输出。
source.sage内容如下
from random import randint
from secrets import flag, r
pubkey = Matrix(ZZ, [
[47, -77, -85],
[-49, 78, 50],
[57, -78, 99]
])
for c in flag:
v = vector([ord(c), randint(0, 100), randint(0, 100)]) * pubkey + r
print(v)
对明文中的各个字符,首先生成一个1行3列的向量,第一个数字是字符的ASCII码, 后两个则是0与100之间的随机数, 然后将该向量与一个3行3列的矩阵相乘,根据矩阵相乘的定义,其结果是一个1行3列的向量,该向量加上一个固定但未知的r后的 结果则输出到结果文件中。
解题的思路在于对于明文中所有的字符而言,r都是一样的,也就是说,我们对于每个字符位置,都必须要有一个字符和两个0与100之间的数来组成第一个向量,并通过定义的计算方法来得到相应的结果。
#解题过程
outputs = [
[-981, 1395, -1668],
[6934, -10059, 4270],
[3871, -5475, 3976],
[4462, -7368, -8954],
[2794, -4413, -3461],
[5175, -7518, 3201],
[3102, -5051, -5457],
[7255, -10884, -266],
[5694, -8016, 6237],
[4160, -6038, 2582],
[4940, -7069, 3770],
[3185, -5158, -4939],
[7669, -11686, -2231],
[5601, -9013, -7971],
[5600, -8355, 575],
[1739, -2838, -3037],
[2572, -4120, -3788],
[8055, -11985, 1137],
[7088, -10247, 5141],
[8384, -12679, -1381],
[-785, 1095, -1841],
[4250, -6762, -5242],
[3716, -5364, 2126],
[5673, -7968, 6741],
[5877, -9190, -4803],
[5639, -8865, -5356],
[1980, -3230, -3366],
[6183, -9334, -1002],
[2575, -4068, -2828],
[7521, -11374, -1137],
[5639, -8551, -1501],
[4194, -6039, 3213],
[2072, -3025, 383],
[2444, -3699, -502],
[6313, -9653, -2447],
[4502, -7090, -4435],
[-421, 894, 2912],
[4667, -7142, -2266],
[4228, -6616, -3749],
[6258, -9719, -4407],
[6044, -9561, -6463],
[266, -423, -637],
[3849, -6223, -5988],
[5809, -9021, -4115],
[4794, -7128, 918],
[6340, -9442, 892],
[5322, -8614, -8334]
]
PRINTABLE_CHARS = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
def getCandidates(index, output, candidates, chars):
results = set()
for c in chars:
cc = ord(c)
for a1 in range(101):
for a2 in range(101):
#矩阵计算
r1 = output[0] - (cc * 47) - (a1 * -49) - (a2 * 57)
r2 = output[1] - (cc * -77) - (a1 * 78) - (a2 * -78)
r3 = output[2] - (cc * -85) - (a1 * 50) - (a2 * 99)
r = str([r1, r2, r3])
#r必须适用于所有的字符
if (len(candidates) == 0) or (r in candidates):
candidateMap[i][r] = c
results.add(r)
return results
candidateMap = []
numberOfOutputs = len(outputs)
candidates = set()
for i in range(numberOfOutputs):
candidateMap.append(dict())
#flag前四个字符"HTB{"已知
if (i == 0):
chars = "H"
elif (i == 1):
chars = "T"
elif (i == 2):
chars = "B"
elif (i == 3):
chars = "{"
else:
chars = PRINTABLE_CHARS
#穷举可能的组合
candidates = getCandidates(i, outputs[i], candidates, chars)
print("number of candidates =", len(candidates))
for r in candidates:
print("r = ", r)
flag = ""
for i in range(numberOfOutputs):
flag += (candidateMap[i][r])
print("flag = ", flag)