第一次实验
任务1:给出一串用维吉尼亚密码加密后的密文,要求使用重合指数法获得明文。
原理:先使用互重合指数求出密钥长度,将多表替换密码转化为多个单表密码,再对每个单表密码使用重合指数求出替换表。
代码:
s = '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'
from base64 import b64decode
a = b64decode(s.encode())
for i in range(2, 100):
sum = 0
for j in range(i):
cnt = [0 for k in range(256)]
num = 0
for k in range(j, len(a), i):
cnt[a[k]] = cnt[a[k]] + 1
num = num + 1
for k in range(256):
sum = sum + cnt[k] * (cnt[k] - 1) / num / (num - 1) / i
if abs(sum - 0.065) < 0.005:
print(i, sum)
keyl = 29
freq = { # From https://en.wikipedia.org/wiki/Letter_frequency.
'e': 0.12702,'t': 0.09056,'a': 0.08167,'o': 0.07507,'i': 0.06966,'n': 0.06749,
's': 0.06327,'h': 0.06094,'r': 0.05987,'d': 0.04253,'l': 0.04025,'c': 0.02782,
'u': 0.02758,'m': 0.02406,'w': 0.02360,'f': 0.02228,'g': 0.02015,'y': 0.01974,
'p': 0.01929,'b': 0.01492,'v': 0.00978,'k': 0.00772,'j': 0.00153,'x': 0.00150,
'q': 0.00095,'z': 0.00074,' ': 0.25000}
key = []
for i in range(keyl):
keyc = 0
min = 999
for j in range(256):
cnt = [0 for k in range(256)]
num = 0
for k in range(i, len(a), keyl):
cnt[a[k] ^ j] = cnt[a[k] ^ j] + 1
num = num + 1
sum = 0
for k in range(26):
sum = sum + cnt[k + ord('a')] / num * freq[chr(k + ord('a'))]
if abs(sum - 0.065) < min:
min = abs(sum - 0.065)
keyc = j
key.append(keyc)
t = ''
for i in range(len(a)):
t = t + chr(a[i] ^ key[i % keyl])
print(t)
运行结果截图:

任务2:用户输入密码所使用的按键,告诉你密码的长度和密码SHA1之后的值,让你求密码的值。
任务:直接暴力枚举即可。这道题出得很烂,没有指明每个按键只按了一次,如果没有这个条件本题几乎跑不出来。但大胆猜测这个条件就可以做出本题。
代码:
from hashlib import sha1
import time
start = time.time()
def dfs(x, y, z):
if x == z:
if sha1(y.encode()).hexdigest() == '67ae1a64661ac8b4494666f58c4822408dd0a3e4':
print(y)
return 1
return 0
c = 'qQwW5%8(0=iI*+nN'
turn = {
'q': 'Q', 'Q': 'q',
'w': 'W', 'W': 'w',
'5': '%', '%': '5',
'8': '(', '(': '8',
'0': '=', '=': '0',
'i': 'I', 'I': 'i',
'*': '+', '+': '*',
'n': 'N', 'N': 'n'
}
for i in c:
if i not in y and turn[i] not in y:
if dfs(x + 1, y + i, z) == 1:
return 1
return 0
for i in range(10):
print(i)
if dfs(0, '', i) == 1:
break
end = time.time()
print((end - start) // 60, 'min', (end - start) // 1, 'sec')
运行结果截图:

第二次实验
任务1:给你一个函数,每次你可以在秘密的前面加上几个字节,然后得到这些字节经过固定密钥的ECB加密的结果,现在让你破解秘密。
原理:通过在秘密前面加上特定数量的字节,将秘密的第一个未知字节恰好“顶”到一块的最后一个字节,的到一个加密串。另一个则根据已经求出的秘密前缀将暴力猜测的字节“顶”到同样的位置,保证本字节之前的字节和上一个串是一样的。这样通过比较本块的加密结果是否一样就可以暴出这一字节。
代码:
from base64 import b64decode
from Crypto.Cipher import AES
from random import randint, randbytes
def padding(s: bytes):
r = (16 - len(s) % 16) % 16
return s + r.to_bytes(1, 'big') * r
def f1(s: bytes, aes, pre):
c = b'Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkg' + \
b'aGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq' + \
b'dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUg' + \
b'YnkK'
c = b64decode(c)
s = padding(pre + s + c)
return aes.encrypt(s)
def work(aes, pre):
s = f1(b'', aes, pre)
last = s[:16]
pre_len = 0
for i in range(1, 16):
s = f1(b'a' * i, aes, pre)
if s[:16] == last:
pre_len = 16 - i + 1
break
last = s[:16]
print('guess pre_len:', pre_len)
max_len = 1024
m = b''
while True:
blank = b'\x00' * (max_len - 1 - pre_len - len(m))
for i in range(1, 256):
s = blank + m + i.to_bytes(1, 'big')
t = blank
if f1(s, aes, pre)[:max_len] == f1(t, aes, pre)[:max_len]:
m = m + i.to_bytes(1, 'big')
break
print(m.decode())
if __name__ == '__main__':
pre_len = randint(1, 16)
print('true pre_len:', pre_len)
pre = randbytes(pre_len)
key = randbytes(16)
iv = randbytes(16)
aes = AES.new(key, AES.MODE_ECB)
work(aes, pre)
运行结果截图:

任务2: 实现一个padding check算法,并给出数据验证你的结果。
原理:没啥好说的。
代码:
def check_padding(s: bytes):
padding = s[-s[-1]:]
for i in padding:
if not i == len(padding):
return False
return True
print(check_padding(b'ICE ICE BABY\x04\x04\x04\x04'))
print(check_padding(b'ICE ICE BABY\x05\x05\x05\x05'))
print(check_padding(b'ICE ICE BABY\x01\x02\x03\x04'))
print(check_padding(b'ICE ICE BABY'))
运行结果截图:

任务3:告诉你明文的格式是 "comment1=cooking%20MCs;userdata=" + data + ";comment2=%20like%20a%20pound%20of%20bacon",其中data的数据可以自己定,你能把comment2的值改了么。
原理:CBC的比特翻转攻击,通过添加很长的data构造出一个纯没有意义的块,然后异或这一块的某个密文字节,这样下一块的明文字节在解密时就会被篡改。
代码:
from Crypto.Cipher import AES
from random import randbytes
def padding(s: bytes):
r = (16 - len(s) % 16) % 16
return s + r.to_bytes(1, 'big') * r
def f1(s: str, aes):
if ";" in s or "=" in s:
exit(0)
s = "comment1=cooking%20MCs;userdata=" + \
s + \
";comment2=%20like%20a%20pound%20of%20bacon"
return aes.encrypt(padding(s.encode()))
def f2(s: bytes, aes):
s = aes.decrypt(s)
print(s)
return b';admin=true;' in s
if __name__ == '__main__':
key = randbytes(16)
iv = randbytes(16)
aes1 = AES.new(key, AES.MODE_CBC, iv)
aes2 = AES.new(key, AES.MODE_CBC, iv)
payload = '\x00' * 32
c = f1(payload, aes1)
m = b';admin=true;' + b'\x00' * 4
t = b''
for i in range(32, 48):
t = t + (m[i - 32] ^ c[i]).to_bytes(1, 'big')
c = c[:32] + t + c[48:]
print(f2(c, aes2))
运行结果截图:

第三次实验
任务:本次大作业要求尝试第一节全国高校密码学挑战赛,目的为练习RSA算法常见漏洞的利用。Alice 正在使用一个使用RSA加密的通信程序。她发了21条信息,但其中有些是相同的,还有些参数不是很合适。现在已经拦截了所有21条信息,告诉你密文的格式是各64bit的n、e、c拼接,明文的格式是64bit的标识符、32bit的序列号、若干个0和64bit的明文,总共521个bit。要求你尽可能多地破解Alice的信息。
原理:
|
本报告利用了4种常见的RSA破解方法:共模攻击、广播攻击、公因数攻击和p-1分解。
如果一对消息的模数和明文相同,而指数互质,那么可以找到 代码: def common_mod(n, e1, c1, e2, c2): # 共模攻击 x, y = exgcd(e1, e2) return pow(c1, x, n) * pow(c2, y, n) % n
如果若干个消息明文和指数相同,指数和明文个数相同,而且模数互质,那么可以列出方程组
利用中国剩余定理可以解出 代码: def broadcast(a, m, e): c = crt(a, m) l, r = 1, c while l + 1 < r: md = (l + r) // 2 if md ** e < c: l = md else: r = md if l ** e == c: return l if r ** e == c: return r return 0
如果两个不同模数 代码: def common_factor(n1, e1, c1, n2, e2, c2): # 公因数攻击 p = gcd(n1, n2) q1 = n1 // p q2 = n2 // p phi1 = (p - 1) * (q1 - 1) phi2 = (p - 1) * (q2 - 1) d1 = inverse(e1, phi1) d2 = inverse(e2, phi2) return pow(c1, d1, n1), pow(c2, d2, n2)
选取一个数 代码: def p_1(n, e, c, b): # p-1 分解 k = 1 for i in range(b): k *= i + 1
p = gcd(pow(2, k, n) - 1, n) if p == 1 or p == n: return 0 q = n // p if p * q != n: return 0 phi = (p - 1) * (q - 1) d = inverse(e, phi) return pow(c, d, n) return 0 执行以上算法可以求出第0 1 2 4 18 19帧,也就是明文的第0 1 5 6 10 11块,内容为” My secre t is a f”、” instein. That is”和” m A to B . Imagin”。 |
代码:
from Crypto.Util.number import inverse
from random import randint
def int2str(a):
s = ''
for i in range(8):
s += chr(a % 256)
a >>= 8
s = s[::-1]
a >>= 352
return (a & ((1 << 32) - 1)), s
def check(a):
a >>= 64
a = a & ((1 << 352) - 1)
if a == 0:
return 1
else:
return 0
def gcd(a, b):
if b == 0:
return a
return gcd(b, a % b)
def exgcd(a, b):
if b == 0:
return 1, 0
x, y = exgcd(b, a % b)
return y, x - a // b * y
def common_mod(n, e1, c1, e2, c2):
# 共模攻击
x, y = exgcd(e1, e2)
return pow(c1, x, n) * pow(c2, y, n) % n
def common_factor(n1, e1, c1, n2, e2, c2):
# 公因数攻击
p = gcd(n1, n2)
q1 = n1 // p
q2 = n2 // p
phi1 = (p - 1) * (q1 - 1)
phi2 = (p - 1) * (q2 - 1)
d1 = inverse(e1, phi1)
d2 = inverse(e2, phi2)
return pow(c1, d1, n1), pow(c2, d2, n2)
def crt(a, m):
M = 1
for i in m:
M *= i
res = 0
for i in range(len(m)):
res = (res + a[i] * M // m[i] * inverse(M // m[i], m[i])) % M
return res
def broadcast(a, m, e):
c = crt(a, m)
l, r = 1, c
while l + 1 < r:
md = (l + r) // 2
if md ** e < c:
l = md
else:
r = md
if l ** e == c:
return l
if r ** e == c:
return r
return 0
def p_1(n, e, c, b):
# p-1 分解
k = 1
for i in range(b):
k *= i + 1
p = gcd(pow(2, k, n) - 1, n)
if p == 1 or p == n:
return 0
q = n // p
if p * q != n:
return 0
phi = (p - 1) * (q - 1)
d = inverse(e, phi)
return pow(c, d, n)
return 0
def main():
n = []
e = []
c = []
for i in range(21):
f = open('./data/Frame' + str(i))
s = f.read()
n.append(int(s[:256], 16))
e.append(int(s[256:512], 16))
c.append(int(s[512:], 16))
m = [0 for i in range(21)]
# 寻找共模攻击
print("Common mod:")
for i in range(21):
for j in range(i):
if n[i] == n[j]:
# print(i, j, gcd(e[i], e[j]))
m[i] = common_mod(n[i], e[i], c[i], e[j], c[j])
m[j] = m[i]
print(i, j, ":", int2str(m[i]))
# 寻找公因数攻击
print("Common factor:")
for i in range(21):
for j in range(i):
if gcd(n[i], n[j]) > 1 and n[i] != n[j]:
m[i], m[j] = common_factor(n[i], e[i], c[i], n[j], e[j], c[j])
print(i, ":", int2str(m[i]))
print(j, ":", int2str(m[j]))
# 广播攻击
print("Broadcast:")
id = [3, 8, 12, 16, 20]
temp = broadcast([c[i] for i in id], [n[i] for i in id], 5)
for i in id:
m[i] = temp
print(int2str(temp))
# p-1 分解
print("P-1:")
for i in range(1, 21):
if m[i] > 0:
continue
print("Attempt:", i)
temp = p_1(n[i], e[i], c[i], 10000)
if temp > 0:
print(i, ":", int2str(temp))
main()
运行结果截图:

这篇博客记录了三次密码学实验的过程,涉及维吉尼亚密码的重合指数法解密、ECB加密的字节破解、padding check算法实现以及CBC比特翻转攻击。博主详细解释了实验原理并展示了代码运行结果,最后提到了RSA算法的漏洞利用实践。

3746

被折叠的 条评论
为什么被折叠?



