好题分享系列 - 2023 香山杯 - strange_hash

admin 2024年9月28日11:50:40评论20 views字数 4785阅读15分57秒阅读模式

首先声明,这个系列所分享的“好题” 仅代表我个人在解这道题时可能觉得这道题某一个知识点很有趣;或是很新颖;或是出题人对这道题各个知识点的衔接处理的很好,而不是单纯套娃;或是看了出题人的题解觉得特别优雅,或是觉得自己的解法很妙…… 但并不保证这道题目的实时性、原创性,可能我看到这道题的时候它已经是被抄袭过的,但我并没有遇到过原题。 (题好,但不对比赛给予评价)另外为了避免纯粹的拿来主义,以给读者一定的思考、操作空间,这个系列也不会直接给出完整的解题 exp,大家自己也多试试叭!

今天这道题目来自 2023 香山杯 - strange_hash

题目内容

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
from os import urandomimport socketserverfrom Crypto.Util.number import *import randomfrom hashlib import sha256import stringfrom secret import flagp = 18446744073709551557M = [[8, 56, 280], [18446744073709551543, 18446744073709551467, 18446744073709551123], [7, 35, 155]]ConInv = [0x39a3f978106bac2d,0x2940e055f4a33725,0xfda9a7a293fb5bc9]Con = [[0x9c52c2de7a9373c4,0xf2135cb886d0fa21,0x957df7f3cd4879e9], [0xd54f837d2738d717,0x400ddf1ffaae436d,0xc2abb601d9a26b07], [0x1904359f1deb3495,0xc21aa09ba52b157b,0x3d45525db1b19a0c], [0xed66cf26a65afc73,0x1cee569b29ffa476,0x3da45abf4304849], [0x1c1a642fa0f3d96d,0x59a1c4fbb96aec86,0xa18e9ca93163f63d], [0x9621ec9fbcb402be,0xd69468353c31bee0,0x50655b3f20fee3b8], [0x109cde7a61c2c195,0x5ebbd9e98be60c59,0x334d2d15f6e43190], [0x47af2b0d63901977,0x67ace097bf8c6f34,0xb87da3296b70d64b], [0x52d6344b38f49899,0xad5773add31420e1,0xecd0b7480f8c8095], [0xe2afb6d20f5decda,0xb1767d8be7d1371,0x902fd6806a0ef4db]]assert len(Con) == 10Inv = inverse(3, p-1)Round = 2def add(x, y):    return [(a + b)%p for a, b in zip(x, y)]def multiply(x, M):    result = []    for i in range(len(M[0])):        temp = 0        for j in range(len(x)):            temp += x[j] * M[j][i]        result.append(temp%p)    return resultdef Rescue_Prime(R, P):    X = add(P, ConInv)    Y = [0, 0, 0]    Z = [0, 0, 0]    U = [0, 0, 0]    for r in range(R):        for i in range(3):            Y[i] = pow(X[i], 3, p)        Z = add(Con[2*r%10], multiply(Y, M))        for i in range(3):            U[i] = pow(Z[i], Inv, p)        X = add(Con[(2*r+1)%10], multiply(U, M))    return Xclass Task(socketserver.BaseRequestHandler):    encrypt_history = []    def __init__(self, *args, **kargs):        super().__init__(*args, **kargs)    def proof_of_work(self):        random.seed(urandom(8))        proof = ''.join([            random.choice(string.ascii_letters + string.digits)            for _ in range(20)        ])        digest = sha256(proof.encode()).hexdigest()        self.send_line(            str.encode(("sha256(XXXX + %s) == %s" % (proof[4:], digest))))        self.send_line(str.encode('Give me XXXX:'))        x = self.request.recv(10)        x = (x.strip()).decode("utf-8")        if len(x) != 4 or sha256(                (x + proof[4:]).encode()).hexdigest() != digest:            return False        return True    def send_line(self, msg):        try:            self.request.sendall(msg + b'\n')        except:            pass    def read_line(self):        body = b""        while True:            ch = self.request.recv(1)            if ch == b"\n":                break            body = body + ch        return body    def timeout_handler(self, signum, frame):        raise TimeoutError    def handle(self):        try:            if not self.proof_of_work():                self.dosend(b'You must pass the PoW!')                self.request.close()            self.send_line(b'Send your input:')            input_str = self.read_line().decode()            num_tuple = tuple(map(int, input_str.strip('()').split(',')))              if num_tuple[-1] != 0:                self.send_line(b'The third number is not zero!')                self.request.close()            output = Rescue_Prime(Round, num_tuple)            if output[-1] == 0:                self.send_line(b'congratulate! Here is the flag:')                self.send_line(flag)            else:                self.send_line(b'Oops! Find collision failed.')                self.request.close()        except:            self.send_line(b'What\'s wrong???')            self.request.close()class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):    passHOST, PORT = '0.0.0.0', 9999server = ThreadedServer((HOST, PORT), Task)server.allow_reuse_address = Trueserver.serve_forever()

是一道交互型题目,用的 socketserver 写法,所以代码显得很长,实际题目关键函数在于 Rescue_Prime

理论上我们需要输入一个三元数组 input,并且满足最后一个元素是 0,然后在经过 Rescue_Prime 函数一通操作后得到输出 output,且最后一个元素也是 0。

题目的原型来自于今年 第八届(2023年)全国高校密码数学挑战赛 赛道一:有限域密码原语CICO问题

可以在 github 找到相关题目介绍和附件:https://github.com/ismdeep/cmsecc-problems/tree/main/2023/problem-01

挑战的难度系数在于解决不同轮次 $R$ 下的 $CICO$ 问题,这道题目是取得是最简单的 $R=2$ 的情况。

心路历程

最开始的想法是,把输入用两个变量 $a,b$ 和一个常量 0 进行表示,然后带入 Rescue_Prime 后会输出一个关于 $a,b,c$ 的多项式向量,然后我找到结果中第三个元素(多项式)的解就行了。自己解当然是不会解的了,想的是 sagemath 自带的 root 函数能够给出我一个解,但是经过一顿操作后,发现最后得到的式子奇长无比,sagemath表示自己也无能为力。然后就剩我懵逼在那了。

后来再看看他具体的操作,无非就是向量加法,矩阵乘法,对向量进行的幂次运算,由于模数是素数,也可以求逆弄回来。所以我们可以直接定死一个输出,然后从尾巴往上逆回去看看输入就行了。原来是加的,就减;原来是乘的,就除(乘以逆);原来是幂次的,也幂次,不是幂的是原来次数在 $\varphi(p)$ 下的逆,这里题目直接给了。

最终大概代码长这样(非常的粗鄙)

123456789101112131415161718
ConInv = matrix(Zmod(p),ConInv)Con = matrix(Zmod(p),Con)M = matrix(Zmod(p),M)output = vector(Zmod(p),[1, 1, 0])tmp = output - Con[3]tmp = tmp * M^-1tmp = tmp * diagonal_matrix(tmp)^2tmp = tmp - Con[2]tmp = tmp * M^-1tmp = tmp * diagonal_matrix(tmp)^(Inv-1)tmp = tmp - Con[1]tmp = tmp * M^-1tmp = tmp * diagonal_matrix(tmp)^2tmp = tmp - Con[0]tmp = tmp * M^-1tmp = tmp * diagonal_matrix(tmp)^(Inv-1)input = tmp - ConInv[0]

这样能搞到一个输入 [1340156074189456211, 16362045171765893968, 18169133141834315644]

但是,输入的第三个元素不是 0 啊?这咋操作呢?继续懵逼。

赛后 @沛公 一语惊醒梦中人,输入检查的不是第三个元素,而是最后一个元素。。所以直接再加一个元素 0 就可以通过输入的 check 了,而这个 0 在第一次向量加法的时候就会被抛掉,不会影响后面的运算。

可是,,这应该是非预期叭,那么预期解该怎么做呢?希望有参加了今年 全国高校密码数学挑战赛赛道一 的大佬能指教一下子 Orz。

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可联系QQ 643713081,也可以邮件至 [email protected] - source:Van1sh的小屋

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月28日11:50:40
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   好题分享系列 - 2023 香山杯 - strange_hashhttps://cn-sec.com/archives/3093833.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息