Cyber_Apocalypse crypto部分wp

(一)makeshift

题目:

from secret import FLAG

flag = FLAG[::-1]
new_flag = ''

for i in range(0, len(flag), 3):
    new_flag += flag[i+1]
    new_flag += flag[i+2]
    new_flag += flag[i]

print(new_flag)

思路:

属于很简单的流加密

首先,flag = FLAG[::-1],步长为-1,从后向前取值,对字符串进行了反转,效果如下:

然后,直接看作将flag三位为一组,进行同一个模式的乱序,m+下来,对应顺序为HTB,从len(c)-3开始,步长为-3遍历字符串,直到索引为-3,那么取出的c中THB索引为i、i+1、i+2,对应赋值即可。

脚本:

c = "!?}De!e3d_5n_nipaOw_3eTR3bt4{_THB"
m = ''
for i in range(len(c)-3, -3, -3):
    m += c[i+1]
    m += c[i]
    m += c[i+2]

print(m)

(二)dynastic

题目:

from secret import FLAG
from random import randint

def to_identity_map(a):
    return ord(a) - 0x41

def from_identity_map(a):
    return chr(a % 26 + 0x41)

def encrypt(m):
    c = ''
    for i in range(len(m)):
        ch = m[i]
        if not ch.isalpha():
            ech = ch
        else:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi + i)
        c += ech
    return c

with open('output.txt', 'w') as f:
    f.write('Make sure you wrap the decrypted text with the HTB flag format :-]\n')
    f.write(encrypt(FLAG))
	
	
	
ech = chr((ord(mch)-0x41 + i)%26 +0x41)
ord(ech) -0x41 = (ord(mch) - 0x41 + i)mod26

思路:

简单的流加密

对字符串中的字母进行了简单的移位,保留特殊字符,写个等式求逆

c = chr((ord(m) - 0x41 + i)%26 + 0x41)

ord(c) = (ord(m) - 0x41 + i)%26 + 0x41

ord(c) - 0x41 = (ord(m) - 0x41 + i)%26

ord(c) - 0x41 + k*26 = ord(m) - 0x41 +i 

感觉这里不会溢出,所以不取模

ord(c) - 0x41 + k*26 - i = ord(m) - 0x41

感觉会溢出,所以取模

char((ord(c) - 0x41 -i)%26  + 0x41) = m

脚本:

def decrypt(c):
    m = ''
    for i in range(len(c)):
        ch = c[i]
        if not ch.isalpha():
            mch = ch
        else:
            mch = chr((ord(ch)-0x41 - i) % 26 + 0x41)
        m += mch
    return m

(三)primary_knowledge

题目:

import math
from Crypto.Util.number import getPrime, bytes_to_long
from secret import FLAG

m = bytes_to_long(FLAG)

n = math.prod([getPrime(1024) for _ in range(2**0)])
e = 0x10001
c = pow(m, e, n)

with open('output.txt', 'w') as f:
    f.write(f'{n = }\n')
    f.write(f'{e = }\n')
    f.write(f'{c = }\n')

思路:

搞了个骚操作来get n

n = math.prod([getPrime(1024) for _ in range(2**0)])

1. [getPrime(1024) for _ in range(2**0)] 是一个列表推导式,它会生成一个列表。range(2**0) 会生成一个包含 2**0(也就是1)个元素的序列,对于序列中的每个元素(在这里只有一个元素),都会调用 getPrime(1024)。getPrime(1024) 是一个函数调用,假设它会返回一个1024位的质数。所以这个列表推导式会生成一个包含1个1024位质数的列表。  
2. math.prod() 是一个函数,它会计算一个序列中所有元素的乘积。在这里,它会计算上面生成的列表中所有元素(也就是那个1024位质数)的乘积。

所以,本质上这是一题n为单一素数的RSA,那么phi就直接等于 n-1了

脚本:

def decrypt(c,e,n):
    phi = n - 1
    d = inverse(e, phi)
    m = pow(c, d, n)
    return long_to_bytes(m)

print(decrypt(c,e,n))

(四)iced_tea

题目:

import os
from secret import FLAG
from Crypto.Util.Padding import pad
from Crypto.Util.number import bytes_to_long as b2l, long_to_bytes as l2b
from enum import Enum

class Mode(Enum):
    ECB = 0x01
    CBC = 0x02

class Cipher:
    def __init__(self, key, iv=None):
        self.BLOCK_SIZE = 64
        self.KEY = [b2l(key[i:i+self.BLOCK_SIZE//16]) for i in range(0, len(key), self.BLOCK_SIZE//16)]
        self.DELTA = 0x9e3779b9
        self.IV = iv
        if self.IV:
            self.mode = Mode.CBC
        else:
            self.mode = Mode.ECB
    
    def _xor(self, a, b):
        return b''.join(bytes([_a ^ _b]) for _a, _b in zip(a, b))

    def encrypt(self, msg):
        msg = pad(msg, self.BLOCK_SIZE//8)
        blocks = [msg[i:i+self.BLOCK_SIZE//8] for i in range(0, len(msg), self.BLOCK_SIZE//8)]
        
        ct = b''
        if self.mode == Mode.ECB:
            for pt in blocks:
                ct += self.encrypt_block(pt)
        elif self.mode == Mode.CBC:
            X = self.IV
            for pt in blocks:
                enc_block = self.encrypt_block(self._xor(X, pt))
                ct += enc_block
                X = enc_block
        return ct

    def encrypt_block(self, msg):
        m0 = b2l(msg[:4])
        m1 = b2l(msg[4:])
        K = self.KEY
        msk = (1 << (self.BLOCK_SIZE//2)) - 1

        s = 0
        for i in range(32):
            s += self.DELTA
            m0 += ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
            m0 &= msk
            m1 += ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
            m1 &= msk
        
        m = ((m0 << (self.BLOCK_SIZE//2)) + m1) & ((1 << self.BLOCK_SIZE) - 1) # m = m0 || m1

        return l2b(m)



if __name__ == '__main__':
    KEY = os.urandom(16)
    cipher = Cipher(KEY)
    ct = cipher.encrypt(FLAG)
    with open('output.txt', 'w') as f:
        f.write(f'Key : {KEY.hex()}\nCiphertext : {ct.hex()}')

思路:

是个带向量的,有点像AES的块加密,参照着encrypt和encrypt_block写逆。

主要矛盾在块的加密中。明文被分成等长的两部分进行交叉的运算,然后又合并。

(值得注意这步操作

# 创建一个掩码,长度为self.BLOCK_SIZE//2,用于限制m0和m1的长度
msk = (1 << (self.BLOCK_SIZE // 2)) - 1

)

mm1m0
cf(m0)f(m1)

因为在加密过程中,m0 的计算依赖于 m1,所以在解密过程中,我们需要先恢复 m1,然后再恢复 m0。

脚本:

    def decrypt(self, ct):
        blocks = [ct[i:i + self.BLOCK_SIZE // 8] for i in range(0, len(ct), self.BLOCK_SIZE // 8)]

        pt = b''
        if self.mode == Mode.ECB:
            for c in blocks:
                pt += self.decrypt_block(c)
        elif self.mode == Mode.CBC:
            X = self.IV
            for c in blocks:
                dec_block = self.decrypt_block(c)
                pt += self._xor(X, dec_block)
                X = c

        print(pt)
        print(len(pt))

        return pt

    def decrypt_block(self, ciphertext):
        c = b2l(ciphertext)
        msk = (1 << (self.BLOCK_SIZE // 2)) - 1

        m1 = c & msk
        m0 = (c >> (self.BLOCK_SIZE // 2)) & msk

        K = self.KEY
        s = self.DELTA * 32

        for i in range(32):
            m1 -= ((m0 << 4) + K[2]) ^ (m0 + s) ^ ((m0 >> 5) + K[3])
            m1 &= msk
            m0 -= ((m1 << 4) + K[0]) ^ (m1 + s) ^ ((m1 >> 5) + K[1])
            m0 &= msk
            s -= self.DELTA

        original_msg = l2b((m0 << 32) + m1)
        return original_msg

(五)blunt

题目:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import getPrime, long_to_bytes
from hashlib import sha256

from secret import FLAG

import random


p = getPrime(32)
print(f'p = 0x{p:x}')

g = random.randint(1, p-1)
print(f'g = 0x{g:x}')

a = random.randint(1, p-1)
b = random.randint(1, p-1)

A, B = pow(g, a, p), pow(g, b, p)

print(f'A = 0x{A:x}')
print(f'B = 0x{B:x}')

C = pow(A, b, p)
assert C == pow(B, a, p)

# now use it as shared secret
hash = sha256()
hash.update(long_to_bytes(C))

key = hash.digest()[:16]
iv = b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'
cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, 16))
print(f'ciphertext = {encrypted}')

思路:

AES终于来了,哦,原来是皮包AES。

今年Cyber Apocalypse特别爱出的,攻击共享密钥的题目。

这题是最基础的dlp,不确定的是有两个随机数(但是都不大)进行碰撞,我们照着脚本一起碰撞就好。

脚本:

p = 0xdd6cc28d
g = 0x83e21c05
A = 0xcfabb6dd
B = 0xc4a21ba9
iv = b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'
ciphertext = b'\x94\x99\x01\xd1\xad\x95\xe0\x13\xb3\xacZj{\x97|z\x1a(&\xe8\x01\xe4Y\x08\xc4\xbeN\xcd\xb2*\xe6{'

a = sympy.discrete_log(p, A, g)
b = sympy.discrete_log(p, B, g)

C = pow(A, b, p)
assert C == pow(B, a, p)

print(long_to_bytes(C))

hash =sha256()
hash.update(long_to_bytes(C))

key = hash.digest()[:16]
print(key)
print(hash.digest())

cipher = AES.new(key, AES.MODE_CBC, iv)

m = cipher.decrypt(ciphertext)
print(m)

(六)arranged

题目:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes
from hashlib import sha256

from secret import FLAG, p, b, priv_a, priv_b

F = GF(p)
E = EllipticCurve(F, [726, b])
G = E(926644437000604217447316655857202297402572559368538978912888106419470011487878351667380679323664062362524967242819810112524880301882054682462685841995367, 4856802955780604241403155772782614224057462426619061437325274365157616489963087648882578621484232159439344263863246191729458550632500259702851115715803253)

A = G * priv_a
B = G * priv_b

print(A)
print(B)

C = priv_a * B

assert C == priv_b * A

# now use it as shared secret
secret = C[0]

hash = sha256()
hash.update(long_to_bytes(secret))

key = hash.digest()[16:32]
iv = b'u\x8fo\x9aK\xc5\x17\xa7>[\x18\xa3\xc5\x11\x9en'
cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, 16))
print(encrypted)

思路:

crypto到此已是本人极限。

已知椭圆曲线系数a和三点G(x1, y1), A(x2, y2), B(x3, y3)

对于G,A有

y{_{1}}^{2} = x{_{1}}^{3} + a x{_{1}} + b\; (mod\; p)

y{_{2}}^{2} = x{_{2}}^{3} + a x{_{2}} + b \; (mod \; p)

两边相减可得:

y{_{1}}^{2} - y{_{2}}^{2} = (x{_{1}}^{3}-x{_{2}}^{3})+a(x_{1}-x_{2}) \; (mod\;p)

k_{1}*p=({x_{1}}^{3} - {x_{2}}^{3}) + a(x_{1}-x_{2}) - ({y_{1}}^{2} - {y_{2}}^{2})

同理有

k_{2}*p=({x_{1}}^{3} - {x_{3}}^{3}) + a(x_{1}-x_{3}) - ({y_{1}}^{2} - {y_{3}}^{2})

求最大公约数可得p,然后求b,得到椭圆曲线的完整系数

脚本:

待整理

  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值