0xGame 2024-Crypto-Week 4

[Week 4] SIDH

  • SIDH后量子安全密钥交换协议,嗐(学不懂
  • 但是
  • DH,说的很明白了,就是密钥交换
  • 看源码发现只要模仿靶机生成密钥然后和靶机进行交互就可以了
  • 实测:9.3版本代码无法正常运行,建议用10.4
  • 抄靶机代码
from pwn import *

ea, eb = 110, 67
p = 2**ea * 3**eb - 1
F.<i> = GF(p**2, modulus=[1,0,1])

E0 = EllipticCurve(F, [1,0])

addr = "nc 118.195.138.159 10009".split(" ")

io = remote(addr[1],int(addr[2]))
recv = io.recvline().decode()[10:-2]
RA_ = re.split(r"\*i \+ |,", recv)
RA = E0(int(RA_[0])*i + int(RA_[1]), int(RA_[2])*i + int(RA_[3]))
print(f"RA={RA.xy()}")

PB = E0.random_point()
QB = E0.random_point()
sB = randint(0, 2**ea)
RB = PB + sB * QB
xy = [str(i).split("*i + ") for i in RB.xy()]
payload1 = ",".join(",".join(i) for i in xy)
print(f"RB={RB.xy()}")
print(f"payload1={payload1}")

phi_A = E0.isogeny(RA, algorithm='factored')
E_A = phi_A.codomain()

R_share = phi_A(PB) + sB * phi_A(QB)
phi_share = E_A.isogeny(R_share, algorithm='factored')
secret = phi_share.codomain().j_invariant()
payload2 = ",".join(i for i in str(secret).split("*i + "))
print(f"secret={secret}")
print(f"payload2={payload2}")

io.sendlineafter("[+] Give me RB:\n>",payload1.encode())
io.sendlineafter("[+] Tell me the secret\n>",payload2.encode())
flag = io.recvline()
print(flag)

io.interactive()
  • 可能要多跑几次,因为secret出现整数的可能性还是挺大的(不知道为什么
  • 0xGame{4179c8c3-db69-4fb0-bd14-ef6c76ddb973}

[Week 4] RNG

  • 这是一个32位的MT19937伪随机数生成器
  • 真实原理没怎么搞懂还是移步Cryptography wiki吧,那里比较详细
  • 源码分析主要是三个操作,一个是在类生成时候的init初始化
  • 二是624一组过后的twist旋转,在生成第一个数之前也经过旋转
  • 三是每次生成随机数的函数extract
  • 第一步逆向可以看Cryptography wiki,后两步逆向我参考的是独奏の小屋
  • 套模板
from pwn import *
import random
from sympy import invert

addr = "nc 118.195.138.159 10006".split(" ")
io = remote(addr[1],int(addr[2]))
io.recvline()
result = [int(i) for i in io.recvline().decode()[1:-2].split(", ")]

# 逆向MT19937
class MT19937Recover:
    def unshiftRight(self, x, shift):
        res = x
        for i in range(32):
            res = x ^ res >> shift
        return res

    def unshiftLeft(self, x, shift, mask):
        res = x
        for i in range(32):
            res = x ^ (res << shift & mask)
        return res

    def untemper(self, v):
        v = self.unshiftRight(v, 18)
        v = self.unshiftLeft(v, 15, 0xefc60000)
        v = self.unshiftLeft(v, 7, 0x9d2c5680)
        v = self.unshiftRight(v, 11)
        return v

    def go(self, outputs, forward=True):
        result_state = None

        assert len(outputs) >= 624

        ivals = []
        for i in range(624):
            ivals.append(self.untemper(outputs[i]))

        if len(outputs) >= 625:
            challenge = outputs[624]
            for i in range(1, 626):
                state = (3, tuple(ivals+[i]), None)
                r = random.Random()
                r.setstate(state)

                if challenge == r.getrandbits(32):
                    result_state = state
                    break
        else:
            result_state = (3, tuple(ivals+[624]), None)

        rand = random.Random()
        rand.setstate(result_state)

        if forward:
            for i in range(624, len(outputs)):
                assert rand.getrandbits(32) == outputs[i]

        return ivals

# 逆向twist
def untwist(newState, flag: bool = True):
    oldState = [0] * 624
    for i in range(624 - 1, -2, -1):
        x = newState[i] ^ newState[(i + 397) % 624]
        if x & 0x80000000 == 0x80000000:
            x ^= 0x9908b0df
            x <<= 1
            x |= 1
        else:
            x <<= 1
        if i > -1:
            oldState[i] |= x & 0x80000000
        if i + 1 < 624:
            oldState[i + 1] |= x & 0x7fffffff
        if i == 227 and flag:
            newState = list(newState[:227]) + oldState[227:]
    return oldState

# 逆向__init__
def _int32(x):
    return int(0xFFFFFFFF & x)

def invert_right(res,shift):
    tmp = res
    for i in range(32//shift):
        res = tmp^res>>shift
    return _int32(res)

def recover(last):
    n = 1<<32
    inv = invert(1812433253,n)
    for i in range(623,0,-1):
        last = ((last-i)*inv)%n
        last = invert_right(last,30)
    return last

mtc = MT19937Recover()
newstate = mtc.go(result)
oldstate = untwist(newstate)
seed = recover(oldstate[-1])
print(f"seed={seed}")

io.sendlineafter("[+] seed = ?\n>",str(seed).encode())
io.interactive()
  • 0xGame{2569bd55-a14d-46d8-81f5-e1397e4be7bc}
  • p.s. extract逆向还是比较好理解(博客讲的很清楚),其他两种操作就难理解了

[Week 4] Coppersmith-I

  • 这是RSA已知p高位攻击Factoring with High Bits Known
  • 所以可以构造出p用sage求解小根
  • 参考博客
n = 135500646574582511239845764710311769260801998982429500680171919823431178899526463566215834234383331374445093363969218810906991784569340270510936759183504496584225937614940086329775325893307453919055830270986601152002191368431527285285313669979358099782497422114870417519470053198217401297960844455029559146309
c = 41763956818640145556632229720626372656921875856507389014855753965024986594502113237270745517422792354256348958542864591249410500750410658988509136242435502259172258432676502846729088278202750721760451160668653746019965695721844819587671602925551448624324524027931677927410810126647175483982178300855471710099
e = 65537
p_high = 918578024558168836638919636090777586135497638818209533615420650282292168631485

for i in range(2**5):
    p4 = p_high << 5			#这里需要先爆破5位,使得知道264位以后再恢复p
    p4 = p4 + i
    kbits = 248
    p4 = p4 << kbits
    R.<x> = PolynomialRing(Zmod(n))
    f = x + p4
    res = f.small_roots(X=2^kbits, beta=0.4, epsilon=0.01)
    if res != []:
        p = p4 + res[0]
        print(p)
        break
  • 得到p之后常规解密文就行
  • 0xGame{8f4c17cb-442a-49bd-830a-d16af225a5c5}
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇