Crypto学习笔记
Crypto学习笔记(持续更新)
数学是个看天赋的学科,而我恰好没有这个天赋,别人很容易理解的内容,我需要学习很久。
本篇博客将记录我探索Crypto世界的点滴旅程,初衷是为了方便自己查阅,也便于自我成长与回顾,倘若笔者浅薄之见,能有幸为诸位师傅学问之海添一滴水,实乃蓬荜生辉,甚为喜悦。在此过程中,各位师傅如有任何观察到的疏漏或偏差,欢迎随时指正,先谢过各位师傅了。
二零二四年四月三十日记
2024第九届中国海洋大学信息安全竞赛-NeXT RSA(费马分解法,p、q相近)
题目描述:聪明的小军觉得既然都选择了随机的 p,那根据 p 选择 q,q 也是随机的辣!
import sympy
import libnum
flag="flag{" + "???" + "}"
m = libnum.s2n(flag)
p = sympy.randprime(1<<1024, 1<<1025)# 生成1024位到1025位之间的随机素数p
q = sympy.nextprime(p)# 找到大于p的下一个素数q
n = p*q
r = (p-1)*(q-1)
e = 65537
c = pow(m, e, n)
print(n, e, c)
# output:
#80044118049755180996754407858488943779355738585718372337839486032339412481191013051614126608584578841408197524632831442032118319629160505851518198448787590483634506563248531254421862061651099856312546562506221294620627871718678484548245902274972044599314097339549053518589561289734819710218838311181044519738709148493164321955860982700783886286661558574861608455547990794798848491695189544811325833194530596317989718866319530140199263278168146224240677087191093183415595617994125075880280632369616506148501757653260154487000183157405531772172082897743929126980157956142627803176227942226654177011633301413616266656761
#65537
#23280133104463252598665779150831148192014617461904564929071121215373331248942762386170411274023248423328388793808975632652896384007449549469345318875514363621903138122407682293848670093433946555776164835208375667498606187869211466397624286383057425296636315379314349307816391315242971306898487494604324473266965665471735612154916305882443496151118031672777088597821127499085632141307413890900246444539517971766135909771880642211582699957211983212981047822362311969553832913399476190919026666192056319334425636757404603336130688707109219644178606626422717046059209499394056295682594928581470210114322505904198054215544
其中 q 是 p 的下一个素数,这题可以使用费马分解法。
由于p,q直接相邻,则必有p < sqrt(n) < q 且p,q都是紧挨着sqrt(n) 的素数,用题目里的nextprime(sqrt(n)) 即可得q,进而解出密文。
解题脚本:
import gmpy2
import sympy
from Crypto.Util.number import *
n = 80044118049755180996754407858488943779355738585718372337839486032339412481191013051614126608584578841408197524632831442032118319629160505851518198448787590483634506563248531254421862061651099856312546562506221294620627871718678484548245902274972044599314097339549053518589561289734819710218838311181044519738709148493164321955860982700783886286661558574861608455547990794798848491695189544811325833194530596317989718866319530140199263278168146224240677087191093183415595617994125075880280632369616506148501757653260154487000183157405531772172082897743929126980157956142627803176227942226654177011633301413616266656761
c = 23280133104463252598665779150831148192014617461904564929071121215373331248942762386170411274023248423328388793808975632652896384007449549469345318875514363621903138122407682293848670093433946555776164835208375667498606187869211466397624286383057425296636315379314349307816391315242971306898487494604324473266965665471735612154916305882443496151118031672777088597821127499085632141307413890900246444539517971766135909771880642211582699957211983212981047822362311969553832913399476190919026666192056319334425636757404603336130688707109219644178606626422717046059209499394056295682594928581470210114322505904198054215544
e = 65537
n2=gmpy2.iroot(n,2)[0]
p=sympy.nextprime(n2)
q=n//p
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
这段代码使用了几个Python库(gmpy2, sympy, Crypto.Util.number)来执行一个RSA加密信息的解密过程。
-
导入所需库:
import gmpy2 import sympy from Crypto.Util.number import *
gmpy2
库用于高效的数学运算,特别是大数运算。sympy
库用于符号数学计算,这里主要用到了寻找下一个素数的功能。Crypto.Util.number
模块包含了处理大整数的工具。
-
定义密文、模数和公钥指数:
n = ... # 很长的整数,模数 c = ... # 密文 e = 65537 # 公钥指数,常见的RSA公钥指数
-
计算n的平方根:
n2=gmpy2.iroot(n,2)[0]
这里尝试计算n的平方根,并取整数部分,用于后续步骤中的近似估计p或q的大小。
-
寻找p和q:
p=sympy.nextprime(n2) q=n//p
首先,使用
sympy.nextprime(n2)
找到大于n的平方根的下一个素数作为p的一个估计值。然后,通过n除以p得到q的近似值。这里的方法假设n是两个相近的素数的乘积,且通过近似方法找到这两个素数。 -
计算欧拉函数φ(n):
phi=(p-1)*(q-1)
计算模数n对应的欧拉函数φ(n),用于计算解密指数d。
-
计算解密指数d:
d=gmpy2.invert(e,phi)
利用扩展欧几里得算法计算d,使得(ed \equiv 1 \mod \phi(n))。
-
解密密文:
m=pow(c,d,n)
使用快速幂算法计算(c^d \mod n),得到原始明文的数值表示。
-
转换并打印解密结果:
print(long_to_bytes(m))
将解密得到的数值转换为字节串并打印出来,通常用于展示解密后的文本信息。
2024第九届中国海洋大学信息安全竞赛-Base64*rot13
题目描述:MzkuM3gyrzI6Z3cyrzHlMKcSra0=
题目名字提示比较明显了,经过base64和rot13的,这里经过测试是先rot13加密后base64加密的,rot13其实就是凯撒的一种变种,它是将字母表中的每个字母替换成字母表中固定位置偏移13个位置的字母,其它非字母的字符保持不变。虽然有很多在线解码脚本,但是我还是用ai写出了解密脚本,方便自己将来在离线环境中仍能做题。
解题脚本:
import base64
def rot13_decode(text):
"""
对给定的文本执行ROT13解码。
"""
result = []
for char in text:
ascii_code = ord(char)
if 'A' <= char <= 'Z':
result.append(chr(((ascii_code - 65 + 13) % 26) + 65))
elif 'a' <= char <= 'z':
result.append(chr(((ascii_code - 97 + 13) % 26) + 97))
else:
result.append(char)
return ''.join(result)
def base64_decode(text):
"""
对给定的Base64编码的文本执行解码,并假设解码后内容为UTF-8编码。
"""
try:
base64_decoded_bytes = base64.b64decode(text)
return base64_decoded_bytes.decode('utf-8')
except base64.binascii.Error:
# 如果解码失败,这里可以选择抛出异常或返回某个默认值
raise ValueError("Invalid Base64 input.")
encoded_text = "MzkuM3gyrzI6Z3cyrzHlMKcSra0="
rot13_decoded_text = rot13_decode(encoded_text)
print("After ROT13 decoding:", rot13_decoded_text)
final_decoded_text = base64_decode(rot13_decoded_text)
print("After Base64 decoding:", final_decoded_text)
2024第九届中国海洋大学信息安全竞赛-模!
题目表述:
from math import factorial
from functools import reduce
flag = "flag{xxxxxxxxx}"
def mooooo(s: str):
res = 0
for i in s:
res <<= 8
res += ( factorial(ord(i)) % 233 )
return res
table = "abcdefghijklmnopqrstuvwxyz{}"
assert(reduce(lambda p,i:(i in table)*p, flag, True))
print(mooooo(flag))
# output: 2508450541438803643416583335895451914701844680466330955847
导入模块
from math import factorial
from functools import reduce
factorial
函数来自math
模块,用于计算一个数的阶乘(即从1乘到该数的所有正整数的乘积)。reduce
函数来自functools
模块,它对一个序列中的元素累积应用二元函数,从左到右,因此通常需要一个初始值。
定义变量
flag = "flag{xxxxxxxxx}"
这是一个字符串变量,表示待处理的“flag”。其中"xxxxxxxxx"
代表未知的具体内容,通常在CTF(Capture The Flag)等信息安全竞赛中用于存储需要解密或解析的秘密信息。
定义函数 mooooo
def mooooo(s: str):
res = 0
for i in s:
res <<= 8
res += (factorial(ord(i)) % 233) # 计算字符的阶乘后对233取模,累加到结果中
return res
此函数接收一个字符串s
作为参数,遍历字符串中的每一个字符。对于每个字符,它先将当前结果左移8位(等效于乘以256),然后加上该字符的ASCII码对应的阶乘值对233取模的结果。最后返回累加计算的总结果。
断言
table = "abcdefghijklmnopqrstuvwxyz{}"
assert(reduce(lambda p,i:(i in table)*p, flag, True))
这里定义了一个字符串table
,包含了小写字母、大括号。接下来的assert
语句用于检查flag
中的每个字符是否都在table
定义的字符集中。reduce
函数配合一个lambda表达式,累积判断flag
中每个字符是否属于table
,若所有字符都在table
内,则累积结果为True,否则为False。如果最终结果为False,程序会抛出AssertionError
异常。
题目脚本中对 flag 的每个字节的值都先进行了阶乘再模 233,结果也是一个字节一个字节地存放,其中flag 每个字节的值都不会超过 233 且 233 是个素数,所以结果中的每个字节的值都能唯一对应上 table中的一个字符,逐位爆破即可。
解密脚本:
from math import factorial
# 已知的输出值
output = 2508450541438803643416583335895451914701844680466330955847
# 逆向mooooo函数的逻辑
def inverse_mooooo(output):
s = ""
while output > 0:
# 从output中获取最右侧的8位
char_val = output & 0xFF
# 查找对应的字符,通过遍历所有可能的字符并计算其阶乘对233取模
for char in "abcdefghijklmnopqrstuvwxyz{}":
if (factorial(ord(char)) % 233) == char_val:
s = char + s # 将找到的字符添加到结果字符串的前面
break
# 左移8位以处理下一个字符
output >>= 8
return s
# 使用inverse_mooooo函数尝试恢复flag
flag = inverse_mooooo(output)
print(flag) # 输出应该是原始的flag字符串
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步