密码学实战 - HTB Quantum-Safe

1,147 阅读4分钟

概述

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)