coperlm's Blog

古之立大事者 不惟有超世之才
亦必有坚忍不拔之志

题目链接

本场比赛应该算是今年我打的第一场算法竞赛,也是NOIP2021结束之后难得发挥出来的比赛。ABC都是比较简单的题,D是二分+dp,比较难想

E最终还是不会,疑似是一个高级dp

Read more »

[NewStarCTF 2023 公开赛道]Rabin's RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from Crypto.Util.number import *
from secret import flag
p = getPrime(64)
q = getPrime(64)
assert p % 4 == 3
assert q % 4 == 3

n = p * q

e = 2
m = bytes_to_long(flag)

c = pow(m,e,n)

print('n =', n)
print('c =', c)

# n = 201354090531918389422241515534761536573
# c = 20442989381348880630046435751193745753

Rabin加密算法——一种基于摸平方和模平方根的非对称加密

特点:

  • 同一密文,可能有两个以上对应的明文
  • 破解该体制等价于对大整数的分解
  • 满足

Rabin密码体制选取 e=2

加密过程:

解密过程:

  • 根据费马小定理计算 在模 时的平方根

  • 使用拓展欧几里得算法来查找

  • 根据中国剩余定理定理求四个模 时的平方根:


  • 为什么 的解?

即:已知 ,求证

因为 是素数,且 是一个模 的二次剩余,那么有:

恒等号两侧同时乘以

恒等号两侧同时开根

意义下的 即为

证毕。

  • 为什么

根据贝祖定理,有

该式对 取模,得到 ,故

同理对 取模,

故有

证毕


能够抵御低密度指数攻击的原因:

低密度指数攻击基于爆破 满足

本题的 数位相近, 需要枚举到 数位量级才有可能爆破出答案


由于模数 N 通常是两个大质数相乘,其欧拉函数很大概率是偶数,故欧拉函数和加密指数不互素,那么逆元性质将不再成立,导致解密操作无法正确还原出原始明文。

原RSA里面要求 e 和 d 模 N 互为逆元 ,否则明文不唯一,明文不唯一的后果就是容易被攻击

传统RSA算法不能解决不互素的情况,无法得到所有的明文解,而二次剩余的情况可以专门被处理,所以就可以被其他算法专门研究

Tonelli-Shanks算法:

推导:设

由费马定理,

也即 (存疑,这一步是怎么得到的https://zhuanlan.zhihu.com/p/631005614

UNFIXED

本题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import *
import gmpy2

n = 201354090531918389422241515534761536573
c = 20442989381348880630046435751193745753
p = 14450452739004884887
q = 13934102561950901579
e = 2

inv_p = gmpy2.invert( p , q )
inv_q = gmpy2.invert( q , p )
mp = pow( c , (p+1)//4 , p )
mq = pow( c , (q+1)//4 , q )

a = (inv_p * p * mq + inv_q * q * mp) % n
b = n - int(a)
c = (inv_p * p * mq - inv_q * q * mp) % n
d = n - int(c)
# 因为rabin 加密有四种结果,全部列出。
aa = [a, b, c, d]

for i in aa:
print(i)
print( long_to_bytes(i) )

flag:flag{r4b1n#4c58}

[b01lers2020]safety_in_numbers

题目给了三个文件:enc.py加密程序,flag加密结果,pubkey公钥文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import sys
import Crypto.PublicKey.RSA as RSA


def enc(msg, pubkey):
(n,e) = pubkey
m = int.from_bytes(msg, byteorder = 'little')
c = pow(m, e, n)
ctxt = (c).to_bytes(c.bit_length() // 8 + 1, byteorder = 'little')
return ctxt


with open("pubkey.pem", "r") as f:
ciph = RSA.importKey(f.read()) # chill out, Crypto.RSA takes its sweet time... (minutes)

pubkey = (ciph.n, ciph.e)


with open("flag.txt", "rb") as f:
flag = f.read()

sys.stdout.buffer.write(enc(flag, pubkey))

通过pem文件提取公钥

1
2
3
4
5
6
7
8
import Crypto.PublicKey.RSA as RSA

with open("pubkey.pem", "r") as f:
ciph = RSA.importKey(f.read()) # chill out, Crypto.RSA takes its sweet time... (minutes)
n = ciph.n
e = ciph.e
print (n)
print (e)

n太大太大了,跑了半天都无法输出(可能超过4300位),所以直接对c开e次方即可得到flag

1
2
3
4
5
6
7
8
9
10
11
12
from gmpy2 import*
from libnum import*
from Crypto.Util.number import long_to_bytes

f = open('flag.enc','rb').read()

e = 65537
tmp = int.from_bytes(f, byteorder = 'little')

m = iroot(tmp,e)[0]
print(long_to_bytes(m))
print(long_to_bytes(m)[::-1])

其中,pem文件的最后一段是存储e的

1
2
3
4
5
6
7
8
from Crypto.Util.number import*
from libnum import*
import base64

s = 'AQAB'
m = base64.b64decode(s)
m = bytes_to_long(m)
print(hex(m))

[AFCTF2018]你听过一次一密么?

1
2
3
4
5
6
7
8
9
10
11
25030206463d3d393131555f7f1d061d4052111a19544e2e5d54
0f020606150f203f307f5c0a7f24070747130e16545000035d54
1203075429152a7020365c167f390f1013170b1006481e13144e
0f4610170e1e2235787f7853372c0f065752111b15454e0e0901
081543000e1e6f3f3a3348533a270d064a02111a1b5f4e0a1855
0909075412132e247436425332281a1c561f04071d520f0b1158
4116111b101e2170203011113a69001b47520601155205021901
041006064612297020375453342c17545a01451811411a470e44
021311114a5b0335207f7c167f22001b44520c15544801125d40
06140611460c26243c7f5c167f3d015446010053005907145d44
0f05110d160f263f3a7f4210372c03111313090415481d49530f

多次一密

已知异或的性质,有

先试用第一行和其他行异或

1
2
3
4
5
6
7
8
9
10
11
12
c = [eval('0x'+x.strip()) for x in open('Problem.txt','r').readlines()]
m1 = c[0]

for i in range( 1 , len(c) ):
tmp = hex( m1^c[i] )[2:]
for i in range( 0 , len(tmp), 2 ):#两位一转ascll
p = chr(eval('0x'+tmp[i:i+2]))
if p.isalpha():
print( p , end='' )
else:
print('.', end='' )
print()

得到:

1
2
3
4
5
6
7
8
9
10
....S....N.U.....A..M.N...
...Ro..I...I....SE....P.I.
.E..H...IN..H...........TU
..A.H.R.....E....P......E.
...RT...E...M....M....A.L.
d...V..I..DNEt........K.DU
.......I....K..I.ST...TiS.
.....f...N.I........M.O...
.........N.I...I.S.I..I...
....P....N.OH...SA....Sg..

规律:小写字母空格=相应的大写字母,大写字母空格=相应的小写字母

故某一 英文字母越多, 相应位置是空格的可能性越大

因为异或运算下, 的逆元是自身

故有 表示列)

只需知道某一字符串的某一位是空格,即可回复所有的密文在这一列的值

解密代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import Crypto.Util.strxor as xo
import libnum, codecs, numpy as np

def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False

def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')

dat = []

def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x!=y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))

c = [codecs.decode(x.strip().encode(), 'hex') for x in open('Problem.txt', 'r').readlines()]

msg = np.zeros([len(c), len(c[0])], dtype=int)

getSpace()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))

得到:

1
2
3
4
5
6
7
8
9
10
11
Dear Friend, T%is tim< I u
nderstood my m$stake 8nd u
sed One time p,d encr ptio
n scheme, I he,rd tha- it
is the only en.ryptio7 met
hod that is ma9hemati:ally
proven to be #ot cra:ked
ever if the ke4 is ke)t se
cure, Let Me k#ow if ou a
gree with me t" use t1is e
ncryption sche e alwa s...

但是有点问题,可以选择手动修复,或者使用代码修复

1
2
3
4
5
6
7
8
def know(s,x,y):
msg[x,y] = ord(s)
for index in range(len(c)):
if index != x:
msg[index,y] = xo.strxor(c[x], c[index])[y] ^ ord(s)

know('h',0,14)
know('e',0,21)

得到

1
2
3
4
5
6
7
8
9
10
11
Dear Friend, This time I u
nderstood my mistake and u
sed One time pad encryptio
n scheme, I heard that it
is the only encryption met
hod that is mathematically
proven to be not cracked
ever if the key is kept se
cure, Let Me know if you a
gree with me to use this e
ncryption scheme always...

有了明文了,计算 即可得到 key

1
2
key = xo.strxor(c[0], ''.join([chr(c) for c in msg[0]]).encode())
print(key)

key就是flag

flag:flag{OPT_1s_Int3rest1ng}


后记:

按行读取TXT中的数据:c = [x for x in open('Problem.txt','r').readlines()]

去除尾部的'\n'c = [x.strip() for x in open('Problem.txt','r').readlines()]

eval的用法十分灵活,默认十进制:c = [eval('0x'+x.strip()) for x in open('Problem.txt','r').readlines()]

[NewStarCTF 2023 公开赛道]babyaes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Cipher import AES
import os
from flag import flag
from Crypto.Util.number import *

def pad(data):
return data + b"".join([b'\x00' for _ in range(0, 16 - len(data))])

def main():
flag_ = pad(flag)
key = os.urandom(16) * 2
iv = os.urandom(16)
print(bytes_to_long(key) ^ bytes_to_long(iv) ^ 1)
aes = AES.new(key, AES.MODE_CBC, iv)
enc_flag = aes.encrypt(flag_)
print(enc_flag)

if __name__ == "__main__":
main()
# 3657491768215750635844958060963805125333761387746954618540958489914964573229
# b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'

key是高位16bytes,iv是低位16bytes,所以可以很轻易的区分

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Cipher import AES
import os
from gmpy2 import*
from Crypto.Util.number import*

xor = 3657491768215750635844958060963805125333761387746954618540958489914964573229
enc_flag = b'>]\xc1\xe5\x82/\x02\x7ft\xf1B\x8d\n\xc1\x95i'
out = long_to_bytes(xor)#先转化成16进制形式,aes和rsa不一样,操作一般都是在hex下
key = out[:16]*2#这一部分是key的,另外一部分是iv的(别忘了最低位有个1)
iv = long_to_bytes(bytes_to_long(key[16:])^bytes_to_long(out[16:])^1)
aes = AES.new(key,AES.MODE_CBC,iv)#调用函数库解密
flag = aes.decrypt(enc_flag)
print(flag)

flag:flag{firsT_cry_Aes}

[QCTF2018]Xman-RSA

ciphertext:

1
2
1240198b148089290e375b999569f0d53c32d356b2e95f5acee070f016b3bef243d0b5e46d9ad7aa7dfe2f21bda920d0ac7ce7b1e48f22b2de410c6f391ce7c4347c65ffc9704ecb3068005e9f35cbbb7b27e0f7a18f4f42ae572d77aaa3ee189418d6a07bab7d93beaa365c98349d8599eb68d21313795f380f05f5b3dfdc6272635ede1f83d308c0fdb2baf444b9ee138132d0d532c3c7e60efb25b9bf9cb62dba9833aa3706344229bd6045f0877661a073b6deef2763452d0ad7ab3404ba494b93fd6dfdf4c28e4fe83a72884a99ddf15ca030ace978f2da87b79b4f504f1d15b5b96c654f6cd5179b72ed5f84d3a16a8f0d5bf6774e7fd98d27bf3c9839
129d5d4ab3f9e8017d4e6761702467bbeb1b884b6c4f8ff397d078a8c41186a3d52977fa2307d5b6a0ad01fedfc3ba7b70f776ba3790a43444fb954e5afd64b1a3abeb6507cf70a5eb44678a886adf81cb4848a35afb4db7cd7818f566c7e6e2911f5ababdbdd2d4ff9825827e58d48d5466e021a64599b3e867840c07e29582961f81643df07f678a61a9f9027ebd34094e272dfbdc4619fa0ac60f0189af785df77e7ec784e086cf692a7bf7113a7fb8446a65efa8b431c6f72c14bcfa49c9b491fb1d87f2570059e0f13166a85bb555b40549f45f04bc5dbd09d8b858a5382be6497d88197ffb86381085756365bd757ec3cdfa8a77ba1728ec2de596c5ab

n2&n3:

1
2
PVNHb2BfGAnmxLrbKhgsYXRwWIL9eOj6K0s3I0slKHCTXTAUtZh3T0r+RoSlhpO3+77AY8P7WETYz2Jzuv5FV/mMODoFrM5fMyQsNt90VynR6J3Jv+fnPJPsm2hJ1Fqt7EKaVRwCbt6a4BdcRoHJsYN/+eh7k/X+FL5XM7viyvQxyFawQrhSV79FIoX6xfjtGW+uAeVF7DScRcl49dlwODhFD7SeLqzoYDJPIQS+VSb3YtvrDgdV+EhuS1bfWvkkXRijlJEpLrgWYmMdfsYX8u/+Ylf5xcBGn3hv1YhQrBCg77AHuUF2w/gJ/ADHFiMcH3ux3nqOsuwnbGSr7jA6Cw==
TmNVbWUhCXR1od3gBpM+HGMKK/4ErfIKITxomQ/QmNCZlzmmsNyPXQBiMEeUB8udO7lWjQTYGjD6k21xjThHTNDG4z6C2cNNPz73VIaNTGz0hrh6CmqDowFbyrk+rv53QSkVKPa8EZnFKwGz9B3zXimm1D+01cov7V/ZDfrHrEjsDkgK4ZlrQxPpZAPl+yqGlRK8soBKhY/PF3/GjbquRYeYKbagpUmWOhLnF4/+DP33ve/EpaSAPirZXzf8hyatL4/5tAZ0uNq9W6T4GoMG+N7aS2GeyUA2sLJMHymW4cFK5l5kUvjslRdXOHTmz5eHxqIV6TmSBQRgovUijlNamQ==

n1.encrypted:

1
2
2639c28e3609a4a8c953cca9c326e8e062756305ae8aee6efcd346458aade3ee8c2106ab9dfe5f470804f366af738aa493fd2dc26cb249a922e121287f3eddec0ed8dea89747dc57aed7cd2089d75c23a69bf601f490a64f73f6a583081ae3a7ed52238c13a95d3322065adba9053ee5b12f1de1873dbad9fbf4a50a2f58088df0fddfe2ed8ca1118c81268c8c0fd5572494276f4e48b5eb424f116e6f5e9d66da1b6b3a8f102539b690c1636e82906a46f3c5434d5b04ed7938861f8d453908970eccef07bf13f723d6fdd26a61be8b9462d0ddfbedc91886df194ea022e56c1780aa6c76b9f1c7d5ea743dc75cec3c805324e90ea577fa396a1effdafa3090
42ff1157363d9cd10da64eb4382b6457ebb740dbef40ade9b24a174d0145adaa0115d86aa2fc2a41257f2b62486eaebb655925dac78dd8d13ab405aef5b8b8f9830094c712193500db49fb801e1368c73f88f6d8533c99c8e7259f8b9d1c926c47215ed327114f235ba8c873af7a0052aa2d32c52880db55c5615e5a1793b690c37efdd5e503f717bb8de716303e4d6c4116f62d81be852c5d36ef282a958d8c82cf3b458dcc8191dcc7b490f227d1562b1d57fbcf7bf4b78a5d90cd385fd79c8ca4688e7d62b3204aeaf9692ba4d4e44875eaa63642775846434f9ce51d138ca702d907849823b1e86896e4ea6223f93fae68b026cfe5fa5a665569a9e3948a

encryption.encrypted:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
gqhb jbkl2 pbkhqw pt_kqpbd
gqhb ht pbkhqw zqreahb
pbkhqw urtd64

adg ulwdt_wh_ezb(u):
qdwzqe pew(u.dexhad('mdi'), 16)

adg ezb_wh_ulwdt(e):
u = mdi(e)[2:-1]
u = '0' + u pg yde(u)%2 == 1 dytd u
qdwzqe u.adxhad('mdi')

adg jdw_r_kqpbd(y):
qreahb_tdda = zqreahb(y)

ezb = ulwdt_wh_ezb(qreahb_tdda)

fmpyd Tqzd:
pg pt_kqpbd(ezb):
uqdrv
ezb+=1
qdwzqe ezb

adg dexqlkw(t, d, e):
k = ulwdt_wh_ezb(t)
k = khf(k, d, e)
qdwzqe ezb_wh_ulwdt(k).dexhad('mdi')

adg tdkrqrwd(e):
k = e % 4
w = (k*k) % 4
qdwzqe w == 1

g = hkde('gyrj.wiw', 'q')
gyrj = g.qdra()

btj1 = ""
btj2 = ""
ghq p pe qrejd(yde(gyrj)):
pg tdkrqrwd(p):
btj2 += gyrj[p]
dytd:
btj1 += gyrj[p]

k1 = jdw_r_kqpbd(128)
k2 = jdw_r_kqpbd(128)
k3 = jdw_r_kqpbd(128)
e1 = k1*k2
e2 = k1*k3
d = 0i1001
x1 = dexqlkw(btj1, d, e1)
x2 = dexqlkw(btj2, d, e2)
kqpew(x1)
kqpew(x2)

d1 = 0i1001
d2 = 0i101
k4 = jdw_r_kqpbd(128)
k5 = jdw_r_kqpbd(128)
e3 = k4*k5
x1 = ezb_wh_ulwdt(khf(e1, d1, e3)).dexhad('mdi')
x2 = ezb_wh_ulwdt(khf(e1, d2, e3)).dexhad('mdi')
kqpew(x1)
kqpew(x2)

kqpew(urtd64.u64dexhad(ezb_wh_ulwdt(e2)))
kqpew(urtd64.u64dexhad(ezb_wh_ulwdt(e3)))

加密代码非要替换一下,直接 词频分析 得到代码原文:(需要自行加入空格)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from gmpy2 import is_prime 
from os import urandom
import base64
def bytes_to_num(b):
return int(b.encode('hex'), 16)
def num_to_bytes(n):
b = hex(n)[2:-1]
b = '0' + b if len(b)%2 == 1 else b
return b.decode('hex')
def get_a_prime(l):
random_seed = urandom(l)

num = bytes_to_num(random_seed)
while True:
if is_prime(num):
break
num+=1
return num
def encrypt(s, e, n):
p = bytes_to_num(s)
p = pow(p, e, n)
return num_to_bytes(p).encode('hex')

def separate(n):
p = n % 4
t = (p*p) % 4
return t == 1

f = open('flag.txt', 'r')
flag = f.read()
msg1 = ""
msg2 = ""
for i in range(len(flag)):
if separate(i):
msg2 += flag[i]
else:
msg1 += flag[i]

p1 = get_a_prime(128)
p2 = get_a_prime(128)
p3 = get_a_prime(128)

n1 = p1*p2
n2 = p1*p3
e = 0x1001
c1 = encrypt(msg1, e, n1)
c2 = encrypt(msg2, e, n2)
print(c1)
print(c2)
e1 = 0x1001
e2 = 0x101
p4 = get_a_prime(128)
p5 = get_a_prime(128)
n3 = p4*p5
c1 = num_to_bytes(pow(n1, e1, n3)).encode('hex')
c2 = num_to_bytes(pow(n1, e2, n3)).encode('hex')
print(c1)
print(c2)
print(base64.b64encode(num_to_bytes(n2)))
print(base64.b64encode(num_to_bytes(n3)))

从后往前解,n2和n3是从先 long_to_bytes,然后 base64 加密,容易得到代码:

1
2
3
4
5
6
7
8
9
10
11
import base64
from Crypto.Util.number import bytes_to_long

def dec( x ):
return bytes_to_long(base64.b64decode(x))

n2 = dec('PVNHb2BfGAnmxLrbKhgsYXRwWIL9eOj6K0s3I0slKHCTXTAUtZh3T0r+RoSlhpO3+77AY8P7WETYz2Jzuv5FV/mMODoFrM5fMyQsNt90VynR6J3Jv+fnPJPsm2hJ1Fqt7EKaVRwCbt6a4BdcRoHJsYN/+eh7k/X+FL5XM7viyvQxyFawQrhSV79FIoX6xfjtGW+uAeVF7DScRcl49dlwODhFD7SeLqzoYDJPIQS+VSb3YtvrDgdV+EhuS1bfWvkkXRijlJEpLrgWYmMdfsYX8u/+Ylf5xcBGn3hv1YhQrBCg77AHuUF2w/gJ/ADHFiMcH3ux3nqOsuwnbGSr7jA6Cw==')
n3 = dec('TmNVbWUhCXR1od3gBpM+HGMKK/4ErfIKITxomQ/QmNCZlzmmsNyPXQBiMEeUB8udO7lWjQTYGjD6k21xjThHTNDG4z6C2cNNPz73VIaNTGz0hrh6CmqDowFbyrk+rv53QSkVKPa8EZnFKwGz9B3zXimm1D+01cov7V/ZDfrHrEjsDkgK4ZlrQxPpZAPl+yqGlRK8soBKhY/PF3/GjbquRYeYKbagpUmWOhLnF4/+DP33ve/EpaSAPirZXzf8hyatL4/5tAZ0uNq9W6T4GoMG+N7aS2GeyUA2sLJMHymW4cFK5l5kUvjslRdXOHTmz5eHxqIV6TmSBQRgovUijlNamQ==')

print( n2 )
print( n3 )

然后通过共膜攻击,求得 n1

1
2
3
4
5
6
7
8
9
10
11
import gmpy2

e1 = 0x1001
e2 = 0x101
c1 =
c2 =

s, s1, s2 = gmpy2.gcdext(e1, e2)
n1 = (pow(c1, s1, n3) * pow(c2, s2, n3) % n3)

print( n1 )

因为 n1n2 有公因数,易求得 p1,p2,p3

1
2
3
4
5
6
7
8
9
import gmpy2

n1 =
n2 =

p1 = gmpy2.gcd(n1, n2)
p2 = n1 // p1
p3 = n2 // p2
print( p1 , p2 , p3 )

剩下的是常规rsa,注意flag拼接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

c1 =
c2 =
e = 0x1001

phi1 = (p1-1)*(p2-1)
phi2 = (p1-1)*(p3-1)
d1 = gmpy2.invert(e, phi1)
d2 = gmpy2.invert(e, phi2)
m1 = pow(c1, d1, n1)
m2 = pow(c2, d2, n2)
flag1 = long_to_bytes(int(m1))
flag2 = long_to_bytes(int(m2))

print(flag1)
print(flag2)

for i in range(len(flag1)):
print(chr(flag1[i]), end = '')
try:
print(chr(flag2[i]), end = '')
except:
pass

flag:flag{CRYPT0_I5_50_Interestingvim rsa.py}


[羊城杯 2020]RRRRRRRSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import hashlib
import sympy
from Crypto.Util.number import *

flag = 'GWHT{************}'
flag1 = flag[:19].encode()
flag2 = flag[19:].encode()
assert(len(flag) == 38)
P1 = getPrime(1038)
P2 = sympy.nextprime(P1)
assert(P2 - P1 < 1000)
Q1 = getPrime(512)
Q2 = sympy.nextprime(Q1)
N1 = P1 * P1 * Q1
N2 = P2 * P2 * Q2
E1 = getPrime(1024)
E2 = sympy.nextprime(E1)
m1 = bytes_to_long(flag1)
m2 = bytes_to_long(flag2)
c1 = pow(m1, E1, N1)
c2 = pow(m2, E2, N2)

output = open('secret', 'w')
output.write('N1=' + str(N1) + '\n')
output.write('c1=' + str(c1) + '\n')
output.write('E1=' + str(E1) + '\n')
output.write('N2=' + str(N2) + '\n')
output.write('c2=' + str(c2) + '\n')
output.write('E2=' + str(E2) + '\n')
output.close()
1
2
3
4
5
6
N1=
c1=
E1=
N2=
c2=
E2=

wiener attack 是依靠连分数进行的攻击方式,适用于非常接近某一值(比如1)时,求一个比例关系,通过该比例关系再来反推关键信息就简单很多。这种攻击对于解密指数d很小时有很好的效果,一般的用法是通过

得到

这种情况下 ,且 非常大

所以有

也就是说 非常接近,而 又是已知的

进行连分数展开,得到的一串分数的分母很有可能就是

只要检验一下 ,看它是不是 就知道对不对了。

但是这道题和普通的wiener attack 不同的是,e与N并没有近到相除约为1的地步,相差还是很大的,也就是说解密指数d也许还是很大的,这样就解不出来。

值得注意的是,e和N的关系不符合利用条件,但是N1和N2的关系却适合

对于这一道题:

显然我们可以知道的是

所以在

尝试对 进行连分数展开并求其各项渐进分数,其中某个连分数的分母可能就是 (依靠 来验证)

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import gmpy2
from Crypto.Util.number import long_to_bytes

N1=
c1=
E1=
N2=
c2=
E2=

def continuedFra(x, y): #不断生成连分数的项
cF = []
while y:
cF += [x // y]
x, y = y, x % y
return cF
def Simplify(ctnf): #化简
numerator = 0
denominator = 1
for x in ctnf[::-1]: #注意这里是倒叙遍历
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator) #把连分数分成分子和算出来的分母
def getit(c):
cf=[]
for i in range(1,len(c)):
cf.append(Simplify(c[:i])) #各个阶段的连分数的分子和分母
return cf #得到一串连分数

def wienerAttack(e, n):
cf=continuedFra(e,n)
for (Q2,Q1) in getit(cf):#遍历得到的连分数,令分子分母分别是Q2,Q1
if Q1 == 0:
continue
if N1%Q1==0 and Q1!=1:#满足这个条件就找到了
return Q1
print('not find!')
Q1=wienerAttack(N1,N2)

P1=gmpy2.iroot(N1//Q1,2)[0]
P2=gmpy2.next_prime(P1)
Q2=gmpy2.next_prime(Q1)
phi1=P1*(P1-1)*(Q1-1)
phi2=P2*(P2-1)*(Q2-1)
d1=gmpy2.invert(E1,phi1)
d2=gmpy2.invert(E2,phi2)
m1=long_to_bytes(gmpy2.powmod(c1,d1,N1))
m2=long_to_bytes(gmpy2.powmod(c2,d2,N2))
print((m1+m2))

flag:flag{3aadab41754799f978669d53e64a3aca}

[UTCTF2020]OTP

1
2
3
4
5
6
7
8
Encoded A: 213c234c2322282057730b32492e720b35732b2124553d354c22352224237f1826283d7b0651
Encoded B: 3b3b463829225b3632630b542623767f39674431343b353435412223243b7f162028397a103e

Original A: 5448452042455354204354462043415445474f52592049532043525950544f47524150485921
Original B: 4e4f205448452042455354204f4e452049532042494e415259204558504c4f49544154494f4e

A XOR A: 7574666c61677b7477305f74696d335f703464737d7574666c61677b7477305f74696d335f70
B XOR B: 7574666c61677b7477305f74696d335f703464737d7574666c61677b7477305f74696d335f70

一次一密是牢不可破的!

不过原文和密文都给了,就可以轻易得到flag了

1
2
3
4
c = '7574666c61677b7477305f74696d335f703464737d7574666c61677b7477305f74696d335f70'

for i in range(0, len(c), 2):
print(chr(int(c[i:i+2], 16)), end = '')

flag:flag{tw0_tim3_p4ds}

[Dest0g3 520迎新赛]babyAES

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Cipher import AES
import os
iv = os.urandom(16)
key = os.urandom(16)
my_aes = AES.new(key, AES.MODE_CBC, iv)
flag = open('flag.txt', 'rb').read()
flag += (16 - len(flag) % 16) * b'\x00'
c = my_aes.encrypt(flag)
print(c)
print(iv)
print(key)

'''
b'C4:\x86Q$\xb0\xd1\x1b\xa9L\x00\xad\xa3\xff\x96 hJ\x1b~\x1c\xd1y\x87A\xfe0\xe2\xfb\xc7\xb7\x7f^\xc8\x9aP\xdaX\xc6\xdf\x17l=K\x95\xd07'
b'\xd1\xdf\x8f)\x08w\xde\xf9yX%\xca[\xcb\x18\x80'
b'\xa4\xa6M\xab{\xf6\x97\x94>hK\x9bBe]F'
'''

最喜欢的大水题,该给的都给了,直接解就可以了

1
2
3
4
5
6
7
8
9
from Crypto.Cipher import AES

c = b'C4:\x86Q$\xb0\xd1\x1b\xa9L\x00\xad\xa3\xff\x96 hJ\x1b~\x1c\xd1y\x87A\xfe0\xe2\xfb\xc7\xb7\x7f^\xc8\x9aP\xdaX\xc6\xdf\x17l=K\x95\xd07'
iv = b'\xd1\xdf\x8f)\x08w\xde\xf9yX%\xca[\xcb\x18\x80'
key = b'\xa4\xa6M\xab{\xf6\x97\x94>hK\x9bBe]F'

my_aes = AES.new(key, AES.MODE_CBC, iv)
m = my_aes.decrypt(c)
print(m)

flag:flag{d0e5fa76-e50f-76f6-9cf1-b6c2d576b6f4}

[ACTF新生赛2020]crypto-des

1
2
3
4
5
6
7
8
72143238992041641000000.000000,
77135357178006504000000000000000.000000,
1125868345616435400000000.000000,
67378029765916820000000.000000,
75553486092184703000000000000.000000,
4397611913739958700000.000000,
76209378028621039000000000000000.000000
To solve the key, Maybe you know some interesting data format about C language?

网上抄来的脚本,我也不知道为什么要这么干(感觉和密码学没关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from libnum import*
import struct
import binascii

s = [72143238992041641000000.000000,77135357178006504000000000000000.000000,1125868345616435400000000.000000,67378029765916820000000.000000,75553486092184703000000000000.000000,4397611913739958700000.000000,76209378028621039000000000000000.000000]
a = ''
b = ''
for i in s:
i = float(i)
a += struct.pack('<f',i).hex() #小端
print(a)

for j in s:
i = float(i)
b += struct.pack('>f',i).hex() #小端
print(b)

print(n2s(a))
print(n2s(b))

得到:

1
2
b'Interestring Idea to encrypt'
b'tpyrtpyrtpyrtpyrtpyrtpyrtpyr'

但是我自己习惯的写法,得到的a是相同的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import struct
import binascii
from Crypto.Util.number import long_to_bytes , bytes_to_long

s = [
72143238992041641000000.000000,
77135357178006504000000000000000.000000,
1125868345616435400000000.000000,
67378029765916820000000.000000,
75553486092184703000000000000.000000,
4397611913739958700000.000000,
76209378028621039000000000000000.000000
]

def solve( f ):
output = ''
for i in s:
output += str(struct.pack(f,float(i)))[2:].strip('\'')
return output

a = solve('<f')
b = solve('>f')
print( a )
print( b )

得到:

1
2
Interestring Idea to encrypt
etnItsergniredI ot acne tpyr

这篇文章的解法看着相对靠谱很多,但是没有详细代码,不知道是如何操作的,尝试只好一番之后未成功只好作罢

输出结果中,b的不一样而a一样,但是解压密码就是a的输出

解压密码是:Interestring Idea to encrypt

得到zip文件:

1
2
3
4
5
6
7
8
9
import pyDes
import base64
from FLAG import flag
deskey = "********"
DES = pyDes.des(deskey)
DES.setMode('ECB')
DES.Kn = 一个矩阵
cipher_list = base64.b64encode(DES.encrypt(flag))
#b'vrkgBqeK7+h7mPyWujP8r5FqH5yyVlqv0CXudqoNHVAVdNO8ML4lM4zgez7weQXo'

新生赛的题是这样的,直接解就可以了

1
2
3
4
5
6
7
8
9
10
11
12
import pyDes
import base64
from Crypto.Util.number import*
deskey = "********"
DES = pyDes.des(deskey)
DES.setMode('ECB')
DES.Kn =

k = b'vrkgBqeK7+h7mPyWujP8r5FqH5yyVlqv0CXudqoNHVAVdNO8ML4lM4zgez7weQXo'
data = base64.b64decode(k)
flag = DES.decrypt(data)
print(flag)

flag:flag{breaking_DES_is_just_a_small_piece_of_cake}

[AFCTF2018]One Secret, Two encryption

1
2
3
一份秘密发送给两个人不太好吧,那我各自加密一次好啦~~~
素数生成好慢呀
偷个懒也……不会有问题的吧?

flag_encry1

flag_encry2

public1.pub

public2.pub


先用 公钥解析 提取一下公钥

得到两组n和e

1
print( math.gcd(n1,n2) )

得到两组p和q

也可以直接用库函数来解

1
2
3
4
5
6
import rsa
d=int(gmpy2.invert(e,(p-1)*(q-1)))
Rsa=rsa.PrivateKey(n,e,d,p,q)
with open('flag_encry1','rb') as f:
cipher1=f.read()
print(rsa.decrypt(cipher1,Rsa))

flag:flag{You_Know_0p3u55I}

[watevrCTF 2019]Swedish RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
flag = bytearray(raw_input())
flag = list(flag)
length = len(flag)
bits = 16

## Prime for Finite Field.
p = random_prime(2^bits-1, False, 2^(bits-1))

file_out = open("downloads/polynomial_rsa.txt", "w")
file_out.write("Prime: " + str(p) + "\n")

## Univariate Polynomial Ring in y over Finite Field of size p
R.<y> = PolynomialRing(GF(p))

## Analogous to the primes in Z
def gen_irreducable_poly(deg):
while True:
out = R.random_element(degree=deg)
if out.is_irreducible():
return out


## Polynomial "primes"
P = gen_irreducable_poly(ZZ.random_element(length, 2*length))
Q = gen_irreducable_poly(ZZ.random_element(length, 2*length))

## Public exponent key
e = 65537

## Modulus
N = P*Q
file_out.write("Modulus: " + str(N) + "\n")

## Univariate Quotient Polynomial Ring in x over Finite Field of size 659 with modulus N(x)
S.<x> = R.quotient(N)

## Encrypt
m = S(flag)
c = m^e

file_out.write("Ciphertext: " + str(c))
file_out.close()

将传统 RSA 中的 p和q 用多项式来替代

1
2
传统欧拉函数:对于正整数n,欧拉函数是小于等于n的数中与n互质的数的个数。
多项式欧拉函数:对于多项式P(y)来讲,欧拉函数phi(P(y))表示所有不高于P(y)幂级的环内所有多项式中,与P(y)无(除1以外)公因式的其他多项式的个数。

经过 is_irreducible 函数的判断,可以得知 是不可约多项式,所以

就是多项式的最高项指数

信息是多项式形式的,明文的每个字符都转化成数值,作为多项式上的系数

1
2
3
4
5
6
7
8
9
10
11
12
P=43753
R.<y> = PolynomialRing(GF(P))
N=
S.<x> = R.quotient(N)
C=
p,q = N.factor()
p,q = p[0],q[0]
phi=(pow(P,65)-1)*(pow(P,112)-1)
e = 65537
d = inverse_mod(e,phi)
m = C^d
print("".join([chr(c) for c in m.list()]))

flagflag{RSA_from_ikea_is_fun_but_insecure#k20944uehdjfnjd335uro}

[watevrCTF 2019]ECC-RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from fastecdsa.curve import P521 as Curve
from fastecdsa.point import Point
from Crypto.Util.number import bytes_to_long, isPrime
from os import urandom
from random import getrandbits

def gen_rsa_primes(G):
urand = bytes_to_long(urandom(521//8))
while True:
s = getrandbits(521) ^ urand

Q = s*G
if isPrime(Q.x) and isPrime(Q.y):
print("ECC Private key:", hex(s))
print("RSA primes:", hex(Q.x), hex(Q.y))
print("Modulo:", hex(Q.x * Q.y))
return (Q.x, Q.y)


flag = int.from_bytes(input(), byteorder="big")

ecc_p = Curve.p
a = Curve.a
b = Curve.b

Gx = Curve.gx
Gy = Curve.gy
G = Point(Gx, Gy, curve=Curve)


e = 0x10001
p, q = gen_rsa_primes(G)
n = p*q


file_out = open("downloads/ecc-rsa.txt", "w")

file_out.write("ECC Curve Prime: " + hex(ecc_p) + "\n")
file_out.write("Curve a: " + hex(a) + "\n")
file_out.write("Curve b: " + hex(b) + "\n")
file_out.write("Gx: " + hex(Gx) + "\n")
file_out.write("Gy: " + hex(Gy) + "\n")

file_out.write("e: " + hex(e) + "\n")
file_out.write("p * q: " + hex(n) + "\n")

c = pow(flag, e, n)
file_out.write("ciphertext: " + hex(c) + "\n")

发射点到对方前哨站的距离:16m;发射点到对方基地的距离:25m

Read more »

Initially, lets just look at a question.

Read more »

hexo s #启动并预览

hexo c #清除缓存文件 db.json 和已生成的静态文件 public

hexo g #生成网站静态文件到默认设置的 public 文件夹(hexo generate 的缩写)

hexo d #自动生成网站静态文件,并部署到设定的仓库(hexo deploy 的缩写)

0%