2021强网拟态 密码学writeup

onlyrsa

n在11进制下0特别多,放多项式里分解就行了。
分解后有一半不是素的,拿另一个大因子算就行了

n = 264048827496427248021277383801027180195275776366915828865010362454006394906519399441496561006668252031429735502465174250525698696973129422193405161920872162928097673289330345041221985548078586423910246601720647996170161319016119241836415788315729493164331517547663558380515400720081995290120793014108439083514403659082115510258023834737471488528527557960636984676435543300074504679264476413252780514962473070445293528877641502742438571110744667739728450283295649865745629276142949963507003094791773183928894536793857609738113546410753895719242547720815692998871947957214118354127328586542848234994500987288641595105
e = 65537
c = 76196483810925191371357319946893762223027002702624516192769497540954799651198719100683206759706879828894501526423422596543748404479640715319801018211652987852179907519286760601944889601355220646374788026632971331786307898234821477134265724962397355614076896148563340833323366935479885600112872998594315513803419069126624158092821269145991266528158747750965226483644012365861166608598063649804899693010576080857540523307078138634628539419178875838147396170651777949577793359622498517581948006585916952705460782942977789615065947303447566918741750017127110484065354974088489869377128636357092420660532261674969708694

from Crypto.Util.number import *

digits = n.digits(11)
f = 0
for i, each in enumerate(digits):
    f += each * x ^ i

factors = f.factor_list()
p = factors[0][0]
q = factors[1][0]

p = p(x=11)
q = q(x=11)

assert p * q == n

if not is_prime(p):
    p = q

d = inverse_mod(e, p - 1)

print(long_to_bytes(pow(c, d, p)))

ezhash

中间相遇攻击,尝试从前后分别构造消息块并往中间状态推导并等待碰撞,一旦碰撞说明找到了合适的构造方案。朴素算法时间复杂度为O(2^{40}),中间相遇只需要O(2^{20})

# -*- coding: utf-8 -*-

from Crypto.Cipher import AES
from Crypto.Util.number import *
from tqdm import trange


aes = AES.new(b"a"*32, AES.MODE_ECB)
last = b'\x03\x1c\xddf:\xa0\xea\xb1\xa5\x03\xe7>\x13\x0bL\xbf'


def pad(m):
    padding_len = 11 - len(m) % 11
    m += bytes([0x80] + [padding_len - 1] * (padding_len - 1))
    return m + b'\x00' * 5

def solve(m1, m2):
    m1 = long_to_bytes(m1).rjust(11, b'\x00') + b'\x00' * 5
    m2 = pad(long_to_bytes(m2))

    m1 = bytes([(each + 2) % 256 for each in m1])
    m1 = aes.encrypt(m1)

    m2 = bytes([(each2 - each1 - 2) % 256 for each1, each2 in zip(m2, last)])
    m2 = aes.decrypt(m2)

    mid = bytes([(each2 - each1 - 2) % 256 for each1, each2 in zip(m1, m2)])

    assert mid[-5:] == b'\x00' * 5
    return mid[:-5]

import string
charset = string.ascii_letters+string.digits
from hashlib import sha256

def proof(known, hashcode):
    for each1 in charset:
        for each2 in charset:
            for each3 in charset:
                for each4 in charset:
                    this = each1 + each2 + each3 + each4 + known
                    if sha256(this.encode()).hexdigest() == hashcode:
                        return this[:4]


middle = {}

left = []
right = []

data = 0
while True:
    this = long_to_bytes(data).rjust(11, b'\x00') + b'\x00' * 5
    this = bytes([(each + 2) % 256 for each in this])
    this = aes.encrypt(this)[-5:]
    this = bytes([(each + 2) % 256 for each in this])
    if this not in middle:
        middle[this] = data
        left.append(this)
    elif this not in left:
        print(long_to_bytes(data).rjust(11, '\x00'))
        print(solve(data, middle[this]))
        print(long_to_bytes(middle[this]))
        break

    this = pad(long_to_bytes(data))
    this = bytes([(each2 - each1 - 2) % 256 for each1, each2 in zip(this, last)])
    this = aes.decrypt(this)[-5:]

    if this not in middle:
        middle[this] = data
        right.append(this)
    elif this not in right:
        print(long_to_bytes(middle[this]).rjust(11, b'\x00'))
        print(solve(middle[this], data))
        print(long_to_bytes(data))
        break

    data += 1

输出的三行消息拼接起来就是碰撞

bad prince

prince加密算法的故障注入,题目中每次访问远程,注入的轮数是6、7、8三个值随机的。根据Aikata等人在《PRINCE under Differential Fault Attack: Now in 3D》中提到的解决方案得知,攻击第六轮的注入几乎是不可能的。因此如果链接远程拿了个第六轮注入的,寄,重开。

github上面可以找到这样一个项目:PRINCE-under-Differential-Fault-Attack-Now-in-3D-master,其中积分攻击部分实现了第七轮的故障注入密钥破解,并且条件符合题目情景。只需要把IntegralAttack.py中生成密文的部分去掉,换成题目中给的密文,就可以获取K1和K0-Prime,然后根据逻辑计算k0即可。

具体如何判断注入点是不是第七轮,根据上面paper描述,可以推导出:如果注入在第八轮,那么这些密文的异或值肯定为全0;然后根据GitHub项目,如果注入在第六轮,那么这个项目的代码无法分析注入位置。

# -*- coding: utf-8 -*-

from IntegralAttack import IntegralAttack
from bitstring import BitArray
from os import urandom
from Crypto.Util.number import long_to_bytes
from PRINCE import PRINCE

hint = ['981541862745d3a9', 'f745b43a26392642', 'cd86e761261ea7e9', 'c78b3a7547b8b950', '9c167a7dcdac0268', '5718b269685a3a3b', 'fe930d8ccb2df025', 'ff98c7ad820d6438', '801d1b0f5da07d98', '4a584c3f2a09c88e', '9d2da4929d88dbaa', 'ed5eaacaba82be29', 'cd7ee3a175a83ba1', 'd111a1965a7b08d2', '25e1156a45f70d07', 'ec078e2281df3d31']
enc_flag = "992c4e89dd8a69eaf552808da2b18a426d8f8c9e2e779c88d9f2aeab263f1ab07156e10e966bc069a4f34006cb8b1d76"

hint = [BitArray("0x" + each) for each in hint]

key = BitArray(urandom(16))
attacker = IntegralAttack(BitArray(b"\x00" * 8), key, faultyNibble = 15, c = hint)

#attacker.launch_attack(1)

k1 = 0x40454c5481c7c617
k0_prime=0x67d4e62803b8ee03
data2 = 0x2791aa7c827f2814

k0 = int("1100111110101001110011000101000000000111011100011101110000000100", 2)

key = (k0 << 64) + k1
key = BitArray(hex(key))

princeObj = PRINCE(key)
flag = b''

for i in range(0, len(enc_flag), 16):

    this = princeObj.decrypt(BitArray("0x" + enc_flag[i:i+16])).hex
    flag += long_to_bytes(int(this, 16))

print(flag)

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注