目录

CTF 密码学总结

题目类型总结:

简单密码类型:

复杂密码类型:

文件相关类型:

算法类总结:

密码学脚本类总结:

单独的密文类型(优先使用ciphey工具)

多层传统加密混合:

Bugku的密码学的入门题/.-:(摩斯密码、url编码、出人意料的flag)

攻防世界之混合编码:(base64解密、unicode解密、ASCII转字符脚本、传统base64解密、ASCII解密)

单层传统加密:

Bugku crypto之聪明的小羊:(题目描述暗示、栅栏密码)

攻防世界之转轮机加密:(转轮机加密、)

攻防世界之告诉你个秘密:(16进制转字符、键盘密码)

攻防世界之sherlock:(大小写字符提取密码)

攻防世界之Decrypt-the-Message:(poem codes诗歌加密、)

文件相关类型:

攻防世界之你猜猜:(16进制转字符、传统base64解密、16进制文件流)

攻防世界之banana-princess:(ROT13加密、文件流加密)

流量相关类型:

攻防世界之工业协议分析2:(16进制转字符、)

加密逻辑平铺类型

传统密码加密逻辑平铺:

2021年9月绿城杯,CRYPTO的[warmup]加密算法:(暴力破解、仿射密码、下标对应解密)

复杂加密类型

RSA直接给参数类型:

攻防世界之cr3-what-is-this-encryption:(RSA通用脚本解密)

攻防世界之OldDriver:(低加密指数广播攻击)

RSA明文密钥文件类型:

攻防世界之best_rsa:(明文密钥文件提取参数、RSA共模攻击、CTF-RSA-tool脚本修改)

攻防世界之RSA256:()

RSA脚本逻辑加密类型:

2021年9月广州羊城杯,CRYPTO的BigRsa:(RSA多层模n加密、CTF-RSA-tool脚本修改、RSA模不互素)

2021年9月绿城杯,CRYPTO的RSA-1:(CTF-RSA-tool脚本修改、RSA通用脚本解密)

2021年9月绿城杯,CRYPTO的RSA-2:(费马分解算法)

2021年10月广东强网杯,CRYPTO的RSA AND BASE?:(排列组合算法、下标对应解密)

ECC椭圆曲线加密:

攻防世界之easy_ECC:(ECC加密)

LFSR反馈移位寄存器类型:

攻防世界之streamgame1:(CTF中的LFSR考点(一)、文件读取对齐的二进制)

攻防世界之streamgame2:(CTF中的LFSR考点(一)、文件读取对齐的二进制)

js类型加密

js逻辑平铺类型:

攻防世界之flag_in_your_hand1:(字符串中文含义暗示、冗余中锁定关键代码)

python类型逻辑加密

pyc文件反编译:

攻防世界之easychallenge:(源代码修改逻辑解密、)

传统密码类型解析

凯撒密码(24个字母):

摩斯密码(只有01(无规则)或.-,空格或/做分隔符):

云影密码(01248):

栅栏密码(分组数作密钥):

培根密码(大小写的ABab,而且必须是5个一组,不是5个就考虑摩斯密码):

与佛论禅编码,要加上佛曰:才能转换(BASE64类型转不了就ROT13一下)

转轮机加密:

键盘密码:

poem codes诗歌加密:

URL编码规则:

仿射密码:

非传统密码类型解析

CTF中的LFSR考点(一):

LFSR简介:

CTF的LFSR题目示例:

解密工具、脚本积累

Ciphey工具:

CTF-RSA-tool工具:

RSA前景知识:

RSA脚本工具使用说明:

多组n,e,c在解题时长这个样子:

一组n,e,c的题目样式:

不同情景下工具运行示例:

RSA通用的简单脚本:(已知p、q、e、c值)

ECC加密:

ECC脚本积累(解出最后的公钥和私钥即可):


CTF 密码学总结

出人意料的flag:

指在题目中获取到了flag,但是这个flag可能长得不像flag,或者flag还要经过进一步的脑洞处理,而不是常规的解密处理。

非预期行为:

指解题中出现与预想结果不符合的一系列非预期行为,这基本说明了在中间或前面存在其他自己还没分析的操作。

冗余中锁定关键代码:

从后往前看,就是确定比较关键对象,从该对象开始排除其他无关变量,一步步找出与该对象有关的其它变量,最后串起找到的所有相关变量,然后开始逆向分析。

题目类型总结:

题目描述暗示:

指题目给出的描述中有解题的大方向思路,以及对解题过程中出现的一些疑惑点的解释。

字符串中文含义暗示:

指解题中遇到带有中文暗示的字符串,这通常是出题者给的提示,抓住暗示重新梳理思路往往是正确的选择。

简单密码类型:

摩斯密码:

指解题中的密文涉及摩斯密码,摩斯密码的特征是以.-或01组成的,分隔符有空格或斜杠/。

url编码:

指解题中的密文涉及url编码,url编码的特征是使用 "%" 其后跟随两位的十六进制数来替换非 ASCII 字符。

传统base64解密:

指题目中密文是涉及base64加密,密文通常是4的倍数,基本元素是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/和补充的'='

unicode解密:

指解题中密文涉及 unicode 解密,unicode现在已知的特征是ASCII(英文也是ASCII码)转unicode码时是 &# 前缀 +2 个 16 进制数,并用 ; 分隔。中文转unicode时是 \u + 4 个 16 进制数,中间没有间隔。

举例:1234 ----->1234 牛逼-------->\u725b\u903c

ASCII解密:

指解题中密文涉及ASCII码,需要转成字符。ASCII共128个可显示字符,范围是0~127或0~7F。不同通常每个ASCII码的间隔依据出题者来定。

栅栏密码:

指解题中密文涉及栅栏密码,因为栅栏密码有传统的矩阵型和 W 型,所以需要自己辨认。根据题目给的 key 分段来逐个尝试。

转轮机加密:

指解题中密文涉及转轮机加密,转轮机密文的特点是等长的分好组的乱序字母,原理是转齿轮把一个字母换成另一个来拼成一句话,所以会有多组密钥,但是只有一组密文。

格式举例,等长的分好组的字符串:

ZWAXJGDLUBVIQHKYPNTCRMOSFE

KPBELNACZDTRXMJQOYHGVSFUWI

键盘密码:

指解题中密文涉及键盘密码加密,键盘密码的特征是4~6个为一组,在键盘上呈包围态势,有明显的间隔。

16进制转字符:

指解题中密文是由16进制基本元素组成的,0~F或0~f,直接16进制转字符即可。

大小写字符提取密码:

指解题中题目给出的密文是一篇小说之类的,其中的内容里面并没有flag,所以内容含义没有意义。但是有一些字母的大小写形式与其他的不一样,这些不一样的字母提取出来就是一种加密类型了。

举例提取大写字符命令:

cat 1.txt | grep -o [A-Z] |tr -d '\n'

grep -o 只显示匹配到的字符串,tr -d 删除指定字符,不删除换行符的话就很长的打竖显示。

ROT13加密:

指解题中给出的密文是简单的数字或字母,但是难以判断加密类型,这时可以尝试用一下ROT13之类的字符移动来转换一下,由于是同一层面的数字和字母,所以通常可以装换出同层的具备传统密码特征的密文,就可以继续解题了。

poem codes诗歌加密:

指解题中密文涉及poem codes诗歌加密,poem codes诗歌加密的特征是诗歌 --> 关键词,原文 --> 参照顺序排列,密文 --> 按诗歌关键词对原文映射取值。

仿射密码:

指解题中密文涉及仿射密码,仿射密码加密的特征是一种替换密码,它是一个字母对一个字母的。字母系统中所有字母都藉一简单数学方程加密。

复杂密码类型:

ECC加密:

是一种建立公开密钥加密的算法,基于椭圆曲线数学的椭圆曲线密码学。

CTF-RSA-tool脚本修改:

指解题中RSA类型是CTF-RSA-tool工具中内嵌类型的一种变形,无法直接用工具生成答案,需要重CTF-RSA-tool中锁定对应的代码,抽出来自己修改才行。

factor_N.py:是对应的解密逻辑封装,解出p、q。

RSAutils.py:是对应的输出结果部分,解决精度和字节串转为字符串问题。

RSA通用脚本解密:

指简单的RSA题目中,直接给出或求出p、q、e、c的值,不需要再用N来大数分解,所有参数都有了就可以直接运行RSA解密脚本解题了。

RSA多层模n加密:

指解题中给了多个模,且都是2048bit 4096bit等无法正面分解的数。需要使用欧几里得算法求取模之间的公约数,也可以直接用p1 = gmpy2.gcd(n1, n2) 这个系统提供的欧几里得封装函数。根据欧几里德算法算出的p之后,再用n除以p即可求出q,由此可以得到的参数有p、q、n、e,再使用常规方法计算出d,即可破解密文。

注意:

这和RSA模不互素很像,但是模不互素只用一个n加密,另一个n是给你求公因子而已。

RSA模不互素:

指解题中RSA类型给了多个模n,且都是2048bit 4096bit等无法正面分解的数,与RSA多层模n加密的区别就是模不互素只用一个n加密,另一个n是给你求公因子而已。

低加密指数广播攻击:

指解题中RSA类型给了多个n、c、e,广播指我们需要将一份明文进行多份加密,但是每份使用不同的密钥,密钥中的模数n不同但指数e相同且很小,我们只要拿到多份密文和对应的n就可以利用中国剩余定理进行解密。

明文密钥文件提取参数:

指解题中题目给了RSA的明文和密钥文件,可能是多个,所以无法直接用CTF-RSA-tool解题(CTF-RSA-tool好像只能输入一对明文密钥文件)。

密钥文件和明文文件读取出对应数字的方法,提取n、e都是用Crypto.PublicKey.RSA模块,再抽取对应的n,c属性的。

提取加密密文c,则是直接二进制读取文件后用Crypto.Util.number模块的bytes_to_long函数转二进制流为数字的。

RSA共模攻击:

指解题中题目给了两个相同的n,不同的e、c,来加密密文。

文件相关类型:

16进制文件流:

指解题中给的密文或者附件中的内容是16进制的文件流,这需要16进制转字符后再base64解码后才能发现是类似于抓包的文件流。所以最开始的16进制流就是文件流,扔入winhex中保存为指定后缀即可。

文件流加密:

指解题中题目给的文件扔入winhex工具中16进制显示的内容,文件头等信息不符合题目给的后缀或不符合题目的文件类型描述。这时就要考虑是否在文件流层面上进行了加密处理,通常是简单的移位处理。

文件读取对齐的二进制:

指解题中需要从文件中读取二进制数,二进制数有时是不能直接从文件中复制粘贴转换的,因为有时候会有乱码显示。可以用前面积累的 base64 编码的代码写一串从文件中读取对齐的二进制的代码。

(在线转换都会省略最开头的0导致结果位数错误,进而导致结果错误,所以自己要注意)

f = open('5key','rb') #以二进制格式打开文件

content = f.read() #读取的是\xhh类型的十六进制

key=['{:0>8}'.format(str(bin(i)).replace('0b','')) for i in content] #从base64编码汲取的经验,二进制8位对齐。

print(''.join(key)[:19])

算法类总结:

费马分解算法:

指RSA题目类型中模n是4个p、q的混合乘积。

费马分解算法的特征就是n是4个数的乘积,分解n之后我们会得到p、p1、q、q1四组隔开的排列组合,但是我们的脚本可以把组合限定成p * q1, p1 * q,和p * q ,p1 * q这样。

然后通过欧几里得算法求公因子的封装函数gcd(pq1,pq) = p、gcd(p1q,p1q) = q 求出两组各一个数,然后就可以求出φ(n)=φ(p)⋅φ(p1)⋅φ(q)⋅φ(q1)=(p−1)⋅(q−1)⋅(p1−1)⋅(q1−1)了。

排列组合算法:

指解题中加密表单缺少了多个字母,但是这个多个字母有多个组合,因为无法确定是那个组合才能拼凑出正确的加密表单,所以需要用排列组合算法全部穷举出来。

密码学脚本类总结:

ASCII转字符脚本:

指解题中遇到长串ASCII码形式,需要转字符,但是一个个转太麻烦,又没有在线的长串ASCII码转字符网站。且给出的长串ASCII码的间隔依情况而定,如:/119/101/,这时需要自己根据对应间隔写出批量转换脚本。

源代码修改逻辑解密:

指解题中在有较完整源代码的情况下代码逻辑比较明朗,且可以逆向。这时需要充分利用有源代码的优势来在源代码中修改处逆向逻辑,不要自己从头到尾另写一份。

暴力破解:

指解题中对每个密文在ASCII的32~127中逐个正向加密对比,找到加密后与密文对应的字符后取chr(i)。

下标对应解密:

指解题中遇到单表替换类型,类似于仿射密码或base家族变形表单加密,正向字母表中每个字母的值使用一个简单的数学函数映射到对应的值。

对于这种加密映射的单表替换型我们可以反着来把正向表单全部加密得出反向表单,密文在反向表单中的下标等同与flag在正向表单的下标,就是下标等价,类似于base64表单替换。

单独的密文类型(优先使用ciphey工具)

多层传统加密混合:

Bugku的密码学的入门题/.-:(摩斯密码、url编码、出人意料的flag)

摩斯密码是以.-或01组成的,分隔符有空格或斜杠/,所以直接扔去摩斯密码在线解密即可。

网址:https://www.bejson.com/enc/morse/

答案差不多了,却被%u7b和%u7d卡住了,猜想是{ }的url编码,{的url编码是%7B,}的url编码是%7D

所以去掉u符号(这里u符号应该是什么十六进制之类的,我也不知道)

直接得到flag:

FLAG{D3FCBF17F9399504}

结果全部要小写:

flag{d3fcbf17f9399504}

攻防世界之混合编码:(base64解密、unicode解密、ASCII转字符脚本、传统base64解密、ASCII解密)

下载附件,打开,发现两个等号和19azA~Z的典型base64编码型,直接base64转换:

转了一堆&#出来,根据以前的做题经验,猜unicode或hex:

一开始用了十六进制来转,转了个四不像出来,后来发现转错了,unicode在线解码网址:

http://www.jsons.cn/unicode/

这三个数的看着像ASCII,因为题目暗示混合编码,直接转换看看:ASCCII表对照法:

ASCII转字符脚本法:(这里因为string.split切片后返回的是列表,所以可以直接用索引获取。)

import re

r="/119/101/108/99/111/109/101/116/111/97/116/116/97/99/107/97/110/100/100/101/102/101/110/99/101/119/111/114/108/100"

r=re.split("/",r)

#print(r)

flag=""

for i in range(1,len(r)):

flag+=chr(int(r[i]))

print(flag)

单层传统加密:

Bugku crypto之聪明的小羊:(题目描述暗示、栅栏密码)

好的,传统栅栏密码,下面是我以前的笔记:

所谓栅栏密码,就是把要加密的明文分成N个一组,然后把每组的第1个字连起来,形成一段无规律的话。 不过栅栏密码本身有一个潜规则,就是组成栅栏的字母一般不会太多。(一般不超过30个,也就是一、两句话)

传统栅栏密码(矩阵行列,密钥是行数):

假如有一个字符串:123456789

取字符串长度的因数进行分组,假如key=3

1 2 3 \\分组情况,每三个数字一组,分为三组

4 5 6

7 8 9

然后每一组依次取一个数字组成一个新字符串:147258369 \\加密完成的字符串

解题:

试一般的栅栏密码,取5为矩阵行数,得到" cyperrocaegireeol} eahfocec gnbip不正确,取5为矩阵列数,得到" cebgccfe en eohplprgecrayoii aoreg”,也不正确,除了常规的栅栏密码,还有

由题目描述可知分两组:

fa{fe13f590

lg6d46d0d0}

那么答案很明显了,上一个下一个即可得flag:

flag{6fde4163df05d900}

攻防世界之转轮机加密:(转轮机加密、)

下载附件:

好了,记住了,以后这个内容格式的就是转轮机加密了:

原理就是转齿轮把一个字母换成另一个,直接上一个修改后的大佬脚本:

rotor = [ #这里是要输入的转轮机原始字符串

"ZWAXJGDLUBVIQHKYPNTCRMOSFE", "KPBELNACZDTRXMJQOYHGVSFUWI",

"BDMAIZVRNSJUWFHTEQGYXPLOCK", "RPLNDVHGFCUKTEBSXQYIZMJWAO",

"IHFRLABEUOTSGJVDKCPMNZQWXY", "AMKGHIWPNYCJBFZDRUSLOQXVET",

"GWTHSPYBXIZULVKMRAFDCEONJQ", "NOZUTWDCVRJLXKISEFAPMYGHBQ",

"XPLTDSRFHENYVUBMCQWAOIKZGJ", "UDNAJFBOWTGVRSCZQKELMXYIHP",

"MNBVCXZQWERTPOIUYALSKDJFHG", "LVNCMXZPQOWEIURYTASBKJDFHG",

"JZQAWSXCDERFVBGTYHNUMKILOP"

]

cipher = "NFQKSEVOQOFNP" #这是要输入转轮机密文

key = [2,3,7,5,13,12,9,1,8,10,4,11,6] #这是要输入转轮机密钥

tmp_list=[]

for i in range(0, len(rotor)):

tmp=""

k = key[i] - 1

for j in range(0, len(rotor[k])):

if cipher[i] == rotor[k][j]:

if j == 0:

tmp=rotor[k]

break

else:

tmp=rotor[k][j:] + rotor[k][0:j]

break

tmp_list.append(tmp)

# print(tmp_list)

message_list = []

for i in range(0, len(tmp_list[i])):

tmp = ""

for j in range(0, len(tmp_list)):

tmp += tmp_list[j][i]

message_list.append(tmp)

print(message_list)

def spread_list(lst):

for item in lst:

if isinstance(item,(list,tuple)):

yield from spread_list(item)

else:

yield item

pass

if __name__ == '__main__':

for i in spread_list(message_list):

print("*"*25)

print(i) #在多个输出中查找有语义的字符串即为flag内容

攻防世界之告诉你个秘密:(16进制转字符、键盘密码)

下载附件,是个.txt文件,打开:

虽然没有f,但是看起来就是16进制的基本组成单位0~F,既然是十六进制就不用先十六进制转字符串,目前接触的也只有十六进制转字符串了:

转完之后是大小写字母混合和数字,虽然没有+/,但看起来也的确是base64的基本组成单位了,base64解码一下:

得出的东西是一个四不像,查了很多资料,大部分说是键盘围起来的密码,而且就叫键盘密码。

(唯一的暗示可能就是空格吧,附上别人的一句话:

看到明⽬张胆的空格,再瞅⼀下键盘,发现是键盘密码,)

r5yG lp9I BjM tFhB T6uh y7iJ QsZ bhM

最后flag就是这些字符在键盘中围起来的键,但是要大写才能提交:

TONGYUAN

攻防世界之sherlock:(大小写字符提取密码)

下载附件,是一个txt文档,内容是一篇小说。一开始我以为flag藏在关键字里,我还用百度翻译一个个看内容,现在回想起来真的太傻了,查了资料才发现字符中是有异或点的,大写字母就是要提取出来分析的地方:

参考了别人的命令写了自己的提取大写shell命令:

cat 1.txt | grep -o [A-Z] |tr -d '\n'

其中:

grep -o 只显示匹配到的字符串

tr -d 删除指定字符,不删除换行符的话就很长的打竖显示。

结果:

然后可以发现都是ZERO和ONE的单词,不是二进制字符串就是摩斯密码,可是摩斯密码要空格,这里没有,所以是二进制字符串。

然后就是自己写python脚本转换01率,一开始用for语句卡了一下,后来直接换while语句:

key1="ZEROONEZEROZEROZEROZEROONEZEROZEROONEZEROZEROONEZEROZEROONEZEROONEZEROONEZEROONEZEROZEROZEROONEZEROONEZEROZEROONEONEZEROONEZEROZEROZEROZEROONEONEZEROONEZEROONEZEROONEZEROZEROZEROONEZEROZEROZEROONEONEZEROZEROONEONEONEONEZEROONEONEZEROONEONEZEROONEZEROZEROZEROZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROZEROONEZEROZEROZEROZEROONEONEZEROZEROONEONEZEROONEZEROONEONEONEONEONEZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROONEONEONEZEROZEROONEZEROONEONEONEONEONEZEROONEONEONEZEROZEROZEROZEROZEROONEONEZEROONEONEZEROZEROZEROZEROONEONEZEROONEZEROZEROZEROZEROONEONEZEROZEROZEROONEZEROONEONEZEROONEONEONEZEROZEROONEZEROONEONEONEONEONEZEROZEROONEONEZEROONEZEROONEZEROZEROONEONEZEROZEROZEROONEZEROZEROONEONEZEROONEONEONEZEROZEROONEONEZEROZEROONEONEZEROONEONEONEONEONEZEROONE"

flag=""

i=0

while i<len(key1):

if key1[i]=='Z'and key1[i+1]=='E'and key1[i+2]=='R'and key1[i+3]=='O':

i+=4

flag+='0'

else:

flag+='1'

i+=3

print(flag)

结果:

攻防世界之Decrypt-the-Message:(poem codes诗歌加密、)

下载附件,是个.txt文件,内容是诗歌,下面是一行四不像的英文,后来发现是加密后的密文:

诗歌类的加密:

一开始还以为是唐伯虎点秋香中句子开头组成实际内容,结果发现不是。查了查资料,是poem codes加密。

然后,我也不知道诗歌中关键词在哪,而且题目诗歌内容也太长了,所以只能用github的脚本了:

(单独复制poemcode.py是会报错的,因为文件中有其他依靠):

git clone git://github.com/abpolym/crypto-tools

用法:(python2,ctfpoem是诗歌,ctfcip是加密密文)

python2 poemcode.py examples/2/ctfpoem examples/2/ctfcip

结果,在众多输出中找到通顺的句子,其实后面我也不知道后面开头的单词合不合理,英语太菜了~(哭 ~)

文件相关类型:

攻防世界之你猜猜:(16进制转字符、传统base64解密、16进制文件流)

下载附件,是一个.txt文件,打开,数字和字母:

504B03040A0001080000626D0A49F4B5091F1E0000001200000008000000666C61672E7478746C9F170D35D0A45826A03E161FB96870EDDFC7C89A11862F9199B4CD78E7504B01023F000A0001080000626D0A49F4B5091F1E00000012000000080024000000000000002000000000000000666C61672E7478740A0020000000000001001800AF150210CAF2D1015CAEAA05CAF2D1015CAEAA05CAF2D101504B050600000000010001005A000000440000000000

往base家族想,字母只有A~F,base16解码:

嗯~好熟悉,后来想起来是web题中bp抓过的数据,查了资料发现是一个zip文件的16进制数据,竟然这么短也能组成zip的数据,也是开了眼界,zip里面也可以看到有个flag.txt文件。

一开始还直接修改成.zip后缀,真是太天真了,这是把hex数据放入txt文件啊。

打开winhex64复制粘贴成zip文件即可:

解密的时候发现需要密码,也不是zip伪加密。嗯~查了资料,上网下载了Ziperello来爆破密码,密码组成只能一个个试了:

拿到了密码123456,解压得到flag:

攻防世界之banana-princess:(ROT13加密、文件流加密)

下载附件,是一个PDF文件,打不开,题目英文提示香蕉原则,好吧并没有什么用。(^ ~ ^)用记事本打开看一下内容:

看起来像是一个文件流:

扔到winhex64中再看一下,嗯~其实一开始我也看不出有什么不妥,红框那里是查了资料说与正常PDF有不同。

正常PDF头:

到这里我的思想就和别人不一样了,别人是思考%CQS-1.5和%PDF-1.x的关系。而我的第一反应是%CQS-1.5是一个没学过的文件头。。。。。毕竟没学过的文件头大把,,所以才有这么菜的自己。(哭~)

然后要问一个字母和另一个字母的关系,加密中能把一个字母加密后是另一个字母的目前学过的有培根,ROT13,24字母移动的凯撒密码。ROT13和凯撒是同一个类型,所以这里看看移动了多少位,发现都是移动了13位。那么这整个PDF文件的内容应该都是移动了13位才会有这种有规则数据和文件乱码数据的现象吧。

附上kali的字符移动13位的命令shell,这里tr命令的应用也是学到了知识,A-Za-z按顺序对应N-ZA-Mn-za-m,这连着的正则表达式之间不用空格也不用分号,无拘无束:

cat 1.pdf | tr A-Za-z N-ZA-Mn-za-m > 2.pdf

然后,转出来的PDF还自带黑格隐藏,一开始我都不记得怎么分离了,后来查资料说转html可以分离,因为这是两张图片重叠在一起而已。事实上用我的嗨格式永久VIP会员PDF转HTML、WORD、PPT都是可以分离的。

流量相关类型:

攻防世界之工业协议分析2:(16进制转字符、)

下载附件,是一个pcapng流量文件:

题目描述说已提取出上位机通信流量,尝试分析出异常点,获取FLAG。 flag形式为 flag{},这其实就是一个暗示,flag就在通信流量中,至于哪里异常,查了资料,有的说UDP的长度有部分异常,要一个个点击查看。可是为什么我感觉UDP大的一堆,小的也一堆,也不知道哪里异常:

然后就是题目暗示说flag在异常流量中,那直接明文匹配查找不就行了?先搜索flag,无果,换十六进制666c6167试试,查到了,用as printable text 选项dump下来即可:

结果:

加密逻辑平铺类型

传统密码加密逻辑平铺:

2021年9月绿城杯,CRYPTO的[warmup]加密算法:(暴力破解、仿射密码、下标对应解密)

下载附件,是一个文本文件,逻辑代码平铺在里面:

打开文件,发现是一个简单的加密表单元素下标对应加密:

因为下标加密是求余运算加密,所以上网找了一下求余运算的逆运算,结果发现负数的求余运算我解决不了。。。(哭~)

所以直接爆破算了,这是我第一次真正用爆破做题,所以比较生疏,先回顾一下一开始我犯的错误。

一开始我写的脚本是这样的,在ASCII的32~127中找到加密后与密文对应的字符,然后取chr(i),然后错误就比较明显了,因为for循环会一直向前走,如果密文不按顺序摆放就会跳过,所以没法用flag+=chr(i)的方法来获取密文,结果就是得到明文字符----密文字符的对应,然后要自己一个个拼接:

mi_wen= 'aoxL{XaaHKP_tHgwpc_hN_ToXnnht}'

str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' #长度52

c=0

flag=[]

cipher_text = ''

for i in range(32,127,1):

if chr(i) in str1: #flag在a~Z内,就获取下标并进行下标替换操作,替换后还是在str1内啊!

addr = str1.find(chr(i))

cipher_text = str1[(37*addr+23) % 52] #求余52

else: #flag不在a~Z内,加1后还是不在str1内

cipher_text = chr(i) #flag在a~Z内,就不用加密直接用

for a in mi_wen:

if cipher_text==a:

print(a,chr(i))

后来想了想,竟然for循环一直往前走,但是如果我换一下顺序,每个密文字符遍历一次ASCII字符,那不就密文也往前走了吗?虽然这样的算法复杂度大大增加,但是对电脑来说根本不值得一提好吧:

mi_wen= 'aoxL{XaaHKP_tHgwpc_hN_ToXnnht}'

str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' #长度52

c=0

flag=[]

cipher_text = ''

for a in mi_wen:

for i in range(32,127):

if chr(i) in str1: #flag在a~Z内,就获取下标并进行下标替换操作,替换后还是在str1内啊!

addr = str1.find(chr(i))

cipher_text = str1[(37*addr+23) % 52] #求余52

else: #flag不在a~Z内,加1后还是不在str1内

cipher_text = chr(i) #flag在a~Z内,就不用加密直接用

if cipher_text==a:

flag+=chr(i)

print(''.join(flag))

这里补充一些别人的做法,他直接把码表加密,之后按位找。是一种比较新颖的方法,是对正向反向下标搞操作,值得研究,我感觉他的逻辑应该是这样的:

还来有一天发现了是仿射密码:

下标逆向脚本:

mi_wen= 'aoxL{XaaHKP_tHgwpc_hN_ToXnnht}'

str1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' #长度52

flag=''

def encode(plain_text, a, b, m):

cipher_text = ''

for i in plain_text:

if i in str1:

addr = str1.find(i)

cipher_text += str1[(a*addr+b) % m]

else:

cipher_text += i

return cipher_text

reverse=encode(str1,37,23,52) #正向表单全部加密得出反向表单

for i in mi_wen: #对应密文下标

if i in str1:

addr=reverse.find(i) #对应反向str1下标,密文在反向表单中的下标等同与flag在正向表单的下标,就是下标等价,类似于base64表单替换。

flag+=str1[addr] #获取正向明文,因为小标是一样对应的

else:

flag+=i

print(flag)

结果:

最后还差原本的负数求余逆运算了,这个暂时找不到资料,先放着。~

复杂加密类型

RSA直接给参数类型:

攻防世界之cr3-what-is-this-encryption:(RSA通用脚本解密)

没有附件,依稀看得出有q、p、e、c,是简单的RSA题目,用我之前积累的RSA脚本CTF-RSA-tool跑一下,。。。跑不出来:(反复试了好多次,还是报错,我放弃了)

然后在网上查资料中找到一个讲得比较好的脚本和讲解:

https://www.cnblogs.com/zhengna/p/13501563.html

RSA的密钥对生成算法:

讲得很透彻了,解密的算法也提供了,附上脚本和我的一点点见解:(这是RSA通用脚本)

import libnum

from Crypto.Util.number import long_to_bytes

q = int(

"0xa6055ec186de51800ddd6fcbf0192384ff42d707a55f57af4fcfb0d1dc7bd97055e8275cd4b78ec63c5d592f567c66393a061324aa2e6a8d8fc2a910cbee1ed9",

16)

p = int(

"0xfa0f9463ea0a93b929c099320d31c277e0b0dbc65b189ed76124f5a1218f5d91fd0102a4c8de11f28be5e4d0ae91ab319f4537e97ed74bc663e972a4a9119307",

16)

e = int(

"0x6d1fdab4ce3217b3fc32c9ed480a31d067fd57d93a9ab52b472dc393ab7852fbcb11abbebfd6aaae8032db1316dc22d3f7c3d631e24df13ef23d3b381a1c3e04abcc745d402ee3a031ac2718fae63b240837b4f657f29ca4702da9af22a3a019d68904a969ddb01bcf941df70af042f4fae5cbeb9c2151b324f387e525094c41",

16)

c = 0x7fe1a4f743675d1987d25d38111fae0f78bbea6852cba5beda47db76d119a3efe24cb04b9449f53becd43b0b46e269826a983f832abb53b7a7e24a43ad15378344ed5c20f51e268186d24c76050c1e73647523bd5f91d9b6ad3e86bbf9126588b1dee21e6997372e36c3e74284734748891829665086e0dc523ed23c386bb520

n = q * p

d = libnum.invmod(e, (p - 1) * (q - 1)) #invmod(a, n) - 求a对于n的模逆,这里逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据ed=1modψ(n),求出d

m = pow(c, d, n) # pow(x, y[, z])--函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z,对应前面解密算法中M=D(C)=C^d(mod n)

#print(m) #明文的十进制格式

string = long_to_bytes(m) # m明文,用长字节划范围

print(string.decode())

攻防世界之OldDriver:(低加密指数广播攻击)

下载附件,一个.txt文件,打开,发现是c、n、e的RSA类型题:

上网查了查,发现类型是低加密指数广播攻击,这里附上别人的话:(里面的中国剩余定理我还没看懂)

首先介绍什么是广播,加入我们需要将一份明文进行多份加密,但是每份使用不同的密钥,密钥中的模数n不同但指数e相同且很小,我们只要拿到多份密文和对应的n就可以利用中国剩余定理进行解密。关于中国剩余定理请参考文章:

https://www.cnblogs.com/freinds/p/6388992.html

只要满足以下情况,我们便可以考虑使用低加密指数广播攻击:

加密指数e非常小

一份明文使用不同的模数n,相同的加密指数e进行多次加密

可以拿到每一份加密后的密文和对应的模数n、加密指数e

本来想参考着写一个脚本的,发现CTF-RSA-tool工具里面好像可以解决低加密指数广播攻击。附上我以前的笔记:

那么把题目的enc.txt照着格式摆放,然后运行脚本即可:

c : 7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042

e : 10

n : 25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803

c : 21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461

e : 10

n : 23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193

c : 6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983

e : 10

n : 18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623

c : 4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052

e : 10

n : 23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723

c : 22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672

e : 10

n : 31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493

c : 17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087

e : 10

n : 22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949

c : 1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639

e : 10

n : 25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043

c : 15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352

e : 10

n : 32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047

c : 8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797

e : 10

n : 52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553

c : 13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247

e : 10

n : 30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621

结果:

积累一下别人的脚本以备后用:(python3)

import libnum

import gmpy2

dic =[{"c":7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042, "e": 10, "n":25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803},

{"c":21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461, "e": 10, "n":23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193},

{"c":6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983, "e": 10, "n":18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623},

{"c":4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052, "e": 10, "n":23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723},

{"c":22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672, "e": 10, "n":31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493},

{"c":17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087, "e": 10, "n":22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949},

{"c":1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639, "e": 10, "n":25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043},

{"c":15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352, "e": 10, "n":32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047},

{"c":8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797, "e": 10, "n":52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553},

{"c":13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247, "e": 10, "n":30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621}]

n = []

C = []

for i in dic:

n.append(i["n"])

C.append(i["c"])

N = 1

for i in n:

N *= i

Ni = []

for i in n:

Ni.append(N // i)

T = []

for i in range(10):

T.append(int(gmpy2.invert(Ni[i], n[i])))

X = 0

for i in range(10):

X += C[i] * Ni[i] * T[i]

m10 = X % N

m = gmpy2.iroot(m10, 10)

print (libnum.n2s(m[0]))

python2:

import libnum

import gmpy2

dic =[{"c":7366067574741171461722065133242916080495505913663250330082747465383676893970411476550748394841437418105312353971095003424322679616940371123028982189502042, "e": 10, "n":25162507052339714421839688873734596177751124036723831003300959761137811490715205742941738406548150240861779301784133652165908227917415483137585388986274803},

{"c":21962825323300469151795920289886886562790942771546858500842179806566435767103803978885148772139305484319688249368999503784441507383476095946258011317951461, "e": 10, "n":23976859589904419798320812097681858652325473791891232710431997202897819580634937070900625213218095330766877190212418023297341732808839488308551126409983193},

{"c":6569689420274066957835983390583585286570087619048110141187700584193792695235405077811544355169290382357149374107076406086154103351897890793598997687053983, "e": 10, "n":18503782836858540043974558035601654610948915505645219820150251062305120148745545906567548650191832090823482852604346478335353784501076761922605361848703623},

{"c":4508246168044513518452493882713536390636741541551805821790338973797615971271867248584379813114125478195284692695928668946553625483179633266057122967547052, "e": 10, "n":23383087478545512218713157932934746110721706819077423418060220083657713428503582801909807142802647367994289775015595100541168367083097506193809451365010723},

{"c":22966105670291282335588843018244161552764486373117942865966904076191122337435542553276743938817686729554714315494818922753880198945897222422137268427611672, "e": 10, "n":31775649089861428671057909076144152870796722528112580479442073365053916012507273433028451755436987054722496057749731758475958301164082755003195632005308493},

{"c":17963313063405045742968136916219838352135561785389534381262979264585397896844470879023686508540355160998533122970239261072020689217153126649390825646712087, "e": 10, "n":22246342022943432820696190444155665289928378653841172632283227888174495402248633061010615572642126584591103750338919213945646074833823905521643025879053949},

{"c":1652417534709029450380570653973705320986117679597563873022683140800507482560482948310131540948227797045505390333146191586749269249548168247316404074014639, "e": 10, "n":25395461142670631268156106136028325744393358436617528677967249347353524924655001151849544022201772500033280822372661344352607434738696051779095736547813043},

{"c":15585771734488351039456631394040497759568679429510619219766191780807675361741859290490732451112648776648126779759368428205194684721516497026290981786239352, "e": 10, "n":32056508892744184901289413287728039891303832311548608141088227876326753674154124775132776928481935378184756756785107540781632570295330486738268173167809047},

{"c":8965123421637694050044216844523379163347478029124815032832813225050732558524239660648746284884140746788823681886010577342254841014594570067467905682359797, "e": 10, "n":52849766269541827474228189428820648574162539595985395992261649809907435742263020551050064268890333392877173572811691599841253150460219986817964461970736553},

{"c":13560945756543023008529388108446940847137853038437095244573035888531288577370829065666320069397898394848484847030321018915638381833935580958342719988978247, "e": 10, "n":30415984800307578932946399987559088968355638354344823359397204419191241802721772499486615661699080998502439901585573950889047918537906687840725005496238621}]

n = []

C = []

for i in dic:

n.append(i["n"])

C.append(i["c"])

N = 1

for i in n:

N *= i

Ni = []

for i in n:

Ni.append(N / i)

T = []

for i in xrange(10):

T.append(long(gmpy2.invert(Ni[i], n[i])))

X = 0

for i in xrange(10):

X += C[i] * Ni[i] * T[i]

m10 = X % N

m = gmpy2.iroot(m10, 10)

print libnum.n2s(m[0])

脚本解析:

RSA明文密钥文件类型:

攻防世界之best_rsa:(明文密钥文件提取参数、RSA共模攻击、CTF-RSA-tool脚本修改)

下载题目,是一个明文和密钥的4个附件:

其实一开始我并不知道RSA的明文和密钥是怎么生成的,CTF-RSA-tool中应对的也只有一对明文密钥文件而已,这里两对的话就只能查资料弄懂原理了再做了。

从别人的博客 攻防世界 best_rsa - vict0r - 博客园 中找到了从密钥文件和明文文件读取出对应数字的方法,提取n、e都是用Crypto.PublicKey.RSA模块,再抽取对应的n,c属性的。

提取加密密文c,则是直接二进制读取文件后用Crypto.Util.number模块的bytes_to_long函数转二进制流为数字的。

from Crypto.PublicKey import RSA

from Crypto.Util.number import *

f1 = open("publickey1.pem","rb").read()

f2 = open("publickey2.pem","rb").read()

c1 = open("cipher1.txt","rb").read()

c2 = open("cipher2.txt","rb").read()

pub1 = RSA.importKey(f1)

pub2 = RSA.importKey(f2)

n1 = pub1.n

e1 = pub1.e

n2 = pub2.n

e2 = pub2.e

c1 = bytes_to_long(c1)

c2 = bytes_to_long(c2)

print("n1 =",n1)

print("e1 =",e1)

print("c1 =",c1)

print("n2 =",n2)

print("e2 =",e2)

print("c2 =",c2)

结果:

n1 = 13060424286033164731705267935214411273739909173486948413518022752305313862238166593214772698793487761875251030423516993519714215306808677724104692474199215119387725741906071553437840256786220484582884693286140537492541093086953005486704542435188521724013251087887351409946184501295224744819621937322469140771245380081663560150133162692174498642474588168444167533621259824640599530052827878558481036155222733986179487577693360697390152370901746112653758338456083440878726007229307830037808681050302990411238666727608253452573696904083133866093791985565118032742893247076947480766837941319251901579605233916076425572961

e1 = 117

c1 = 12847007370626420814721007824489512747227554004777043129889885590168327306344216253180822558098466760014640870748287016523828261890262210883613336704768182861075014368378609414255982179769686582365219477657474948548886794807999952780840981021935733984348055642003116386939014004620914273840048061796063413641936754525374790951194617245627213219302958968018227701794987747717299752986500496848787979475798026065928167197152995841747840050028417539459383280735124229789952859434480746623573241061465550303008478730140898740745999035563599134667708753457211761969806278000126462918788457707098665612496454640616155477050

n2 = 13060424286033164731705267935214411273739909173486948413518022752305313862238166593214772698793487761875251030423516993519714215306808677724104692474199215119387725741906071553437840256786220484582884693286140537492541093086953005486704542435188521724013251087887351409946184501295224744819621937322469140771245380081663560150133162692174498642474588168444167533621259824640599530052827878558481036155222733986179487577693360697390152370901746112653758338456083440878726007229307830037808681050302990411238666727608253452573696904083133866093791985565118032742893247076947480766837941319251901579605233916076425572961

e2 = 65537

c2 = 6830857661703156598973433617055045803277004274287300997634648800448233655756498070693597839856021431269237565020303935757530559600152306154376778437832503465744084633164767864997303080852153757211172394903940863225981142502888126928982009493972076013486758460894416710122811249903322437742241269681934551237431668187006176418124934488775505816544733929241927900392924886649420943699356314278255683484998359663404611236056664149725644051300950988495549164517140159041907329062655574220869612072289849679613024196448446224406889484578310512232665571188351621585528255501546941332782446448144033997067917984719103068519

这里两个相同的n,就是共模攻击了,在CTF-RSA-tool工具里有对公模攻击的解法:

所以摆好格式后直接跑脚本:

当然完全依靠工具是不行的,所以抽取出CTF-RSA-tool对应代码做成脚本:

(注意:这里因为用python2运行,所以不能用直接用open().read()来读取文档内容,会报错。在外面要裹上libnum.s2n()才行)

from Crypto.PublicKey import RSA

from Crypto.Util.number import *

import gmpy2

import libnum

def share_N(N, e1, e2, c1, c2):

gcd, s, t = gmpy2.gcdext(e1, e2)

if s < 0:

s = -s

c1 = gmpy2.invert(c1, N)

if t < 0:

t = -t

c2 = gmpy2.invert(c2, N)

plain = gmpy2.powmod(c1, s, N) * gmpy2.powmod(c2, t, N) % N

print(libnum.n2s(plain))

#上面的函数是从CTF-RSA-tool工具中抽取出来的,下面的n、e、c属性是前面自己写的

c1=libnum.s2n(open('cipher1.txt','rb').read())

c2=libnum.s2n(open('cipher2.txt','rb').read())

pub1=RSA.importKey(open('publickey1.pem').read())

pub2=RSA.importKey(open('publickey2.pem').read())

n = pub1.n

e1= pub1.e

e2= pub2.e

share_N(n,e1,e2,c1,c2)

攻防世界之RSA256:()

下载压缩包,解压,是两个附件,一个没有后缀,一个.txt文件,打开查看内容,感觉是RSA的密文密钥文件:

翻一下以前的笔记,这是对CTF-RSA-tool使用的示例,感觉题目类型就是这种密钥和密文的文件:

验证猜想,直接脚本跑一下,得到flag:

RSA脚本逻辑加密类型:

2021年9月广州羊城杯,CRYPTO的BigRsa:(RSA多层模n加密、CTF-RSA-tool脚本修改、RSA模不互素)

下载附件,pub.py:

打开文件,发现内容是RSA加密过程:

from Crypto.Util.number import *

from flag import *

n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061

n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073

e = 65537

m = bytes_to_long(flag)

c = pow(m, e, n1)

c = pow(c, e, n2)

print("c = %d" % c)

# output

# c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264

首先回顾一下以前的积累的RSA脚本解题的知识:

然后回到羊城杯的题目你就会发现,题目先用公共模数n1对flag m加密一次,再用公共模数n2对RSA一次加密后的密文再加密一次,这是两层加密:

按理来说两层常规的RSA解密即可,关键就是这里的n1、n2太大了,无法硬分解,常规的分解素数网站没法用。

然后就去查资料了,因为RSA自己也不在行,下面是从 CTF密码学中RSA学习以及总结_韦全敏的博客-CSDN博客

中找到的。

RSA小指数e攻击

如果RSA系统的公钥e选取较小的值,可以使得加密和验证签名的速度有所提高,但是如果e的选取太小,就容易受到攻击。

有三个分别使用不同的模数n1,n2,n3,但是都选取e=3,加密同一个明文可以得到:

c1 = pow(m,3,n1)

c2 = pow(m,3,n2)

c3 = pow(m,3,n3)

一般情况下,n1,n2,n3互素,否则会比较容易求出公因子,从而安全性大幅度的减低。

利用公约数:

如果两次加密的n1和n2具有相同的素因子,可以利用欧几里德算法直接分解n1和n2.

通过欧几里德算法计算出两个n的最大公约数p:

def gcd(a, b):

if a < b:

a, b = b, a

while b != 0:

temp = a % b

a = b

b = temp

def gcd_digui(a, b):

if b != 0:

return a

return gcd(b,a%b)

p = gcd(n1,n2)

RSA小指数e攻击题目特征识别:

识别此类题目,通常会发现题目给了若干个n,均不相同,并且都是2048bit,4096bit级别,无法正面硬杠,并且明文都没什么联系,e也一般取65537。

根据欧几里德算法算出的p之后,再用n除以p即可求出q,由此可以得到的参数有p、q、n、e,再使用常规方法计算出d,即可破解密文。

和题目八九不离十,那这道bigrsa就是这样解的了,用两个公共模数n来求公因子:

在此之前中间还有个小插曲,那就是CTF-RSA-tool工具,一开始我以为这中两个n、一个e、一个c的是CTF-RSA-tool工具中example的模不互素:(下面是我以前的笔记)

后来怎么跑都跑不出来,看了工具内对应代码才发现模不互素是给你两个单独分解不了的大数级n,方便让你求公因子。然后,只用一个n来加密,对,只用一个n。(我也是现在才理解模不互素的内容)

前面博客的欧几里德算法脚本不太会用,所以直接抽出CTF-RSA-tool工具的这段脚本来用算了,因为上面的求公因子代码已经写好了,只要再加多一层解密即可,脚本如下:

import gmpy2

def share_factor(n1, n2, e, c1):

p1 = gmpy2.gcd(n1, n2) #gcd是求共因子用的,相当于欧几里德算法的封装实现

q1 = n1 / p1

q2 = n2 / p1

d1 = gmpy2.invert(e, (p1 - 1) * (q1 - 1))

plain = gmpy2.powmod(c1, d1, n1)

d2 = gmpy2.invert(e, (p1 - 1) * (q2 - 1))

plain = gmpy2.powmod(plain, d2, n2)

plain = hex(plain)[2:]

if len(plain) % 2 != 0:

plain = '0' + plain

print('Here are your plain text: \n' + plain.decode('hex'))

if __name__ == "__main__":

n1 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073

n2 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061

e = 65537

c1 = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264

share_factor(n1, n2, e, c1)

最后附上别人WP的脚本(只能截图了):

不同在于我的脚本直接用p1 = gmpy2.gcd(n1, n2)取公因子,而他使用自定义gcd函数求公约数,就是利用了前面的欧几里得算法:

2021年9月绿城杯,CRYPTO的RSA-1:(CTF-RSA-tool脚本修改、RSA通用脚本解密)

下载附件,是逻辑平铺类型:

打开文件,发现是很常规的RSA加密,就是明文进行了二次处理:

照例用工具CTF-RSA-tool工具,首先提取出来符合CTF-RSA-tool的格式的信息先:

N is 17365231154926348364478276872558492775911760603002394353723603461898405740234715001820111548600914907617003806652492391686710256274156677887101997175692277729648456087534987616743724646598234466094779540729413583826355145277980479040157075453694250572316638348121571218759769533738721506811175866990851972838466307594226293836934116659685215775643285465895317755892754473332034234495795936183610569571016400535362762699517686781602302045048532131426035260878979892169441059467623523060569285570577199236309888155833013721997933960457784653262076135561769838704166810384309655788983073376941843467117256002645962737847

e is 65537

c is 6944967108815437735428941286784119403138319713455732155925055928646536962597672941805831312130689338014913452081296400272862710447207265099750401657828165836013122848656839100854719965188680097375491193249127725599660383746827031803066026497989298856420216250206035068180963797454792151191071433645946245914916732637007117085199442894495667455544517483404006536607121480678688000420422281380539368519807162175099763891988648117937777951069899975260190018995834904541447562718307433906592021226666885638877020304005614450763081337082838608414756162253825697420493509914578546951634127502393647068722995363753321912676

运行脚本看一下回显,明文必然是错误的,因为M经过了二次简单乘法处理,所以我们要在脚本中找到对应的地方修改一下才行:

这里就属于CTF-RSA-tool工具的进阶理解了:

首先根据回显DEBUG: factor N: try Common factor between ciphertext and modulus attack我在文件factor_N.py找到了对应的部分:

原来是密文与模数不互素,难怪我在http://www.factordb.com/index.php网站中分解不出N。而且也不是像以前积累的2021年9月广州羊城杯的BigRsa一样有两个N的模不互素:

我们修改一下CTF-RSA-tool打印出p、q:

然后用常规的脚本来计算试一下,结果错误又出现了,除数太大,精度丢失了,只有前缀flag了:

import libnum

from Crypto.Util.number import long_to_bytes

q = 115544353401076813303707955026809960381216232736189720201691794640724518676996765546980623105046200417460503255773857079426889487335934106430981939859723844442935408148185112500163743051467736536409887068250813490971705717411149279581182052591953379888333356928093109561978986910375048128808860432864671882543

p = 150290608270992439844054823303154263794197803561695786056860615174575181277160032222859532335454486914357850849343036173838960820180867595169623670363963732315901587946639577107202780317748525709407153327463601548012321945759392416846089189522151851138821377551427960151260776474250605261723480167088408148729

e = 65537

c = 6944967108815437735428941286784119403138319713455732155925055928646536962597672941805831312130689338014913452081296400272862710447207265099750401657828165836013122848656839100854719965188680097375491193249127725599660383746827031803066026497989298856420216250206035068180963797454792151191071433645946245914916732637007117085199442894495667455544517483404006536607121480678688000420422281380539368519807162175099763891988648117937777951069899975260190018995834904541447562718307433906592021226666885638877020304005614450763081337082838608414756162253825697420493509914578546951634127502393647068722995363753321912676

n = 17365231154926348364478276872558492775911760603002394353723603461898405740234715001820111548600914907617003806652492391686710256274156677887101997175692277729648456087534987616743724646598234466094779540729413583826355145277980479040157075453694250572316638348121571218759769533738721506811175866990851972838466307594226293836934116659685215775643285465895317755892754473332034234495795936183610569571016400535362762699517686781602302045048532131426035260878979892169441059467623523060569285570577199236309888155833013721997933960457784653262076135561769838704166810384309655788983073376941843467117256002645962737847

d = libnum.invmod(e, (p - 1) * (q - 1)) #invmod(a, n) - 求a对于n的模逆,这里逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据e*d=1modψ(n),求出d

#print(hex(d))

m = pow(c, d, n) # 这里的m是十进制形式,pow(x, y[, z])--函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z,对应前面解密算法中M=D(C)=(C^d)mod n

print(long_to_bytes(m/(2021*1001*p)))

然后一开始我的思路是用在线大数除法工具解决精度丢失的问题,找不到。于是进一步修改CTF-RSA-tool工具,终于在RSAutils.py中找到输出结果部分修改一下,成功输出flag:

2021年9月绿城杯,CRYPTO的RSA-2:(费马分解算法)

下载附件,是逻辑平铺类型:

打开文件,发现是分成两段的RSA加密,第一段加密flag[:20],第二段加密flag[20:]:

from Crypto.Util.number import *

import gmpy2

from flag import flag

assert flag[:5]==b'flag{'

m1 = bytes_to_long(flag[:20])

p = getPrime(512)

p1 = gmpy2.next_prime(p)

q = getPrime(512)

q1 = gmpy2.next_prime(q)

n1 = p*q*p1*q1

print('n1 =',n1)

e = 0x10001

c1 = pow(m1,e,n1)

print('c1 =',c1)

m2 = bytes_to_long(flag[20:])

p2 = getPrime(1024)

q2 = getPrime(1024)

print('p2+q2 =',p2+q2)

print('q2*q2 =',p2*q2)

n2 = p2*p2*q2*q2*q2

print('n2 =',n2)

c2 = pow(m2,e,n2)

print('c2 =',c2)

#n1 = 6348779979606280884589422188738902470575876294643492831465947360363568026280963989291591157710389629216109615274754718329987990551836115660879103234129921943824061416396264358110216047994331119920503431491509529604742468032906950984256964560405062345280120526771439940278606226153077959057882262745273394986607004406770035459301695806378598890589432538916219821477777021460189140081521779103226953544426441823244765828342973086422949017937701261348963541035128661464068769033772390320426795044617751909787914185985911277628404632533530390761257251552073493697518547350246993679844132297414094727147161169548160586911

#c1 = 6201882078995455673376327652982610102807874783073703018551044780440620679217833227711395689114659144506630609087600915116940111002026241056808189658969089532597757995423694966667948250438579639890580690392400661711864264184444018345499567505424672090632235109624193289954785503512742400960515331371813467034511130432319427185134018830006918682733848618201088649690422818940385123599468595766345668931882249779415788129316594083269412221804774856038796248038700275509397599351533280014908894068141056694660319816046357462684688942519849441237878018480036145051967731081582598773076490918572392784684372694103015244826

#p2+q2 = 274773146761138462708137582309097386437793891793691383033856524303010811294101933454824485010521468914846151819876043508541879637544444256520741418495479393777132830985856522008561088410862815913292288683761657919121930016956916865849261153721097671315883469348972925757078089715102032241818526925988645578778

#q2*q2 = 18514724270030962172566965941723224386374076294232652258701085781018776172843355920566035157331579524980108190739141959926523082142273672741849552475156278397131571360099018592018959785627785130126477982765210498547680367230723634424036009539347854344573537848628061468892166199866227984167843139793429682559241317072979374002912607549039431398267184818771503468116379618249319324788996321340764624593443106354104274472601170229835219638093242557547840060892527576940077162990069687019966946826210112318408269749294366586682732614372434218768720577917368726530200897558912687470088583774711767599580037663378929000217

#n2 = 40588227045595304080360385041082238507044292731344465815296032905633525556943787610712651675460810768762763493579129831271018141591546207557410817432455139315527674932933085299277599173971912445226532235814580879585317211349524406424200622675880992390782025158621241499693400288031658194434641718026910652327933253877313106112861283314274635124734817398465059373562194694957841264834312640926278890386089611103714990646541470577351599526904458342660444968591197606820361364761648205241041444681145820799054413179462285509661124362074093583494932706249461954240408827087015525507173082129412234486228092002841868365895837463699200959915782767657258729794037776401995309244941171415842403617486719492483671490834562579225506831496881542530519595438932482796867853234159664409420977526102480385193101883785161080269573707156626838551506024455480650224305894501968583442346807126920740779780593650871645915149689424292912611578291912721896864772950410266629045542480009266574096080138709683466489568290569363478444349563498507530805502511051165160827192795520182720802422213364247355775222858214648603034743679187470844212529134374975737510982287957316878179964602394749601431823167982157434890459245394370728942790117156485268116758052636794417268680901420193002289035538753620555488506926366624641291881353268617130968991258983002165300186971963661666476600998389048880565199317280428349802824448329898502788492233381873026217202981921654673840142095839603360666049476100561268336225902504932800605464136192275593886736746497955270280541423593

#c2 = 25591090168544821761746024178724660839590948190451329227481168576490717242294520739865602061082558759751196452117720647426598261568572440942370039702932821941366792140173428488344932203576334292648255551171274828821657097667106792872200082579319963310503721435500623146012954474613150848083425126987554594651797477741828655238243550266972216752593788734836373144363217639612492397228808215205862281278774096317615918854403992620720969173788151215489908812749179861803144937169587452008097008940710091361183942268245271154461872102813602754439939747566507116519362821255724179093051041994730856401493996771276172343313045755916751082693149885922105491818225012844519264933137622929024918619477538521533548551789739698933067212305578480416163609137189891797209277557411169643568540392303036719952140554435338851671440952865151077383220305295001632816442144022437763089133141886924265774247290306669825085862351732336395617276100374237159580759999593028756939354840677333467281632435767033150052439262501059299035212928041546259933118564251119588970009016873855478556588250138969938599988198494567241172399453741709840486953189764289118312870580993115636710724139809708256360212728127786394411676427828431569046279687481368215137561500777480380501551616577832499521295655237360184159889151837766353116185320317774645294201044772828099074917077896631909654671612557207653830344897644115936322128351494551004652981550758791285434809816872381900401440743578104582305215488888563166054568802145921399726673752722820646807494657299104190123945675647

先看第一段:

gmpy2.next_prime(p)函数的意思是取邻近p的下一个素数,那么很明显p和p1,q和q1都是两两相邻的素数,相差很小,n1是2048bit级别的,没法硬钢。

后半段的n2和前半段的加密逻辑差别很大,所以不是两个n的模不互素。也不是像上一道题RSA1一样的密文与模数不互素。

然后查了资料后发现关键在p和p1,q和q1都是两两相邻的素数这里,也就是说p,q,p1,q1两两互素。单纯的factordb.com和yafu分解n肯定是分解不出来的,毕竟是2048bit嘛。所以我们需要一些算法,比如前面模不互素的欧几里得算法这样,这里我们要用的是费马分解算法。

费马分解算法的特征就是n是4个数的乘积,分解n之后我们会得到p、p1、q、q1四组隔开的排列组合,但是我们的脚本可以把组合限定成 p * q1, p1 * q 和 p * q ,p1 * q 这样。然后通过欧几里得算法求公因子的封装函数 gcd(pq1,pq) = p、gcd(p1q,p1q) = q 求出两组各一个数,然后就可以求出 φ(n)=φ(p)⋅φ(p1)⋅φ(q)⋅φ(q1)=(p−1)⋅(q−1)⋅(p1−1)⋅(q1−1) 了。

然后后面的参考以前积累的RSA解密流程做即可:

费马因子分解代码:

取自博客:

https://blog.csdn.net/weixin_56678592/article/details/120555169?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link

import gmpy2

from gmpy2 import *

from Crypto.Util.number import *

import sympy

e = 0x10001

n1 = 6348779979606280884589422188738902470575876294643492831465947360363568026280963989291591157710389629216109615274754718329987990551836115660879103234129921943824061416396264358110216047994331119920503431491509529604742468032906950984256964560405062345280120526771439940278606226153077959057882262745273394986607004406770035459301695806378598890589432538916219821477777021460189140081521779103226953544426441823244765828342973086422949017937701261348963541035128661464068769033772390320426795044617751909787914185985911277628404632533530390761257251552073493697518547350246993679844132297414094727147161169548160586911

c1 = 6201882078995455673376327652982610102807874783073703018551044780440620679217833227711395689114659144506630609087600915116940111002026241056808189658969089532597757995423694966667948250438579639890580690392400661711864264184444018345499567505424672090632235109624193289954785503512742400960515331371813467034511130432319427185134018830006918682733848618201088649690422818940385123599468595766345668931882249779415788129316594083269412221804774856038796248038700275509397599351533280014908894068141056694660319816046357462684688942519849441237878018480036145051967731081582598773076490918572392784684372694103015244826

def fermat_factorization(n):

factor_list = []

get_context().precision = 2048 #这里应该是n1的数量级吧,len(bin(n1))就等于2048bit。

sqrt_n = int(sqrt(n))

c = sqrt_n

while True:

c += 1

d_square = c**2 - n

if is_square(d_square):

d_square = mpz(d_square)

get_context().precision = 2048

d = int(sqrt(d_square))

factor_list.append([c+d,c-d])

if len(factor_list)==2:

break

return factor_list

factor_list = fermat_factorization(n1)

[X1,Y1] = factor_list[0] #费马函数分解最大的特征就是输出两组互相交叉的p * q1, p1 * q,和p * q ,p1 * q,我们必须用gcd(X1,X2)和gcd(Y1,Y2)求出对应的p、q

[X2,Y2] = factor_list[1]

assert X1*Y1 == n1

assert X2*Y2 == n1

p1 = gcd(X1,X2)

q1 = X1 // p1 #这是python向下取整除运算符,我真的第一次发现python有这个运算符。

p2 = gcd(Y1,Y2)

q2 = Y1 // p2

phi1 = (p1-1)*(q1-1)*(p2-1)*(q2-1) #求φ(n)

d1 = invert(e,phi1) #常规RSA解密流程求d

print(long_to_bytes(gmpy2.powmod(c1,d1,n1)),end='') #常规RSA解密流程求明文

#flag{Euler_funct1ons

结果:

接下来分析后半段:

后半段给了x+y和x*y的值,按照初中数学的逻辑直接列个方程就可以解出x和y的值了,但是我看别人博客各种算法来解这个简单的逻辑,什么欧拉函数,因式方程看得头都晕。

然后翻着翻着突然发现一个秀儿,他p2和q2求法是这样的,因为n2=p2*p2*q2*q2*q2,所以 q2 = n2 // (p2_mul_q2*p2_mul_q2)、p2 = p2_mul_q2 // q2,真的我都鼓掌了,太棒了,简单题就简单做啊,简单的逻辑就应该这样求才对啊。

所以直接套用脚本即可,这里要注意的是φ(n)这里,因为因子只有p2和q2,所以φ(n)=p2*(p2 - 1)*q2*q2*(q2 - 1),只用对单个因子减1即可。

import libnum

from Crypto.Util.number import long_to_bytes

n2=40588227045595304080360385041082238507044292731344465815296032905633525556943787610712651675460810768762763493579129831271018141591546207557410817432455139315527674932933085299277599173971912445226532235814580879585317211349524406424200622675880992390782025158621241499693400288031658194434641718026910652327933253877313106112861283314274635124734817398465059373562194694957841264834312640926278890386089611103714990646541470577351599526904458342660444968591197606820361364761648205241041444681145820799054413179462285509661124362074093583494932706249461954240408827087015525507173082129412234486228092002841868365895837463699200959915782767657258729794037776401995309244941171415842403617486719492483671490834562579225506831496881542530519595438932482796867853234159664409420977526102480385193101883785161080269573707156626838551506024455480650224305894501968583442346807126920740779780593650871645915149689424292912611578291912721896864772950410266629045542480009266574096080138709683466489568290569363478444349563498507530805502511051165160827192795520182720802422213364247355775222858214648603034743679187470844212529134374975737510982287957316878179964602394749601431823167982157434890459245394370728942790117156485268116758052636794417268680901420193002289035538753620555488506926366624641291881353268617130968991258983002165300186971963661666476600998389048880565199317280428349802824448329898502788492233381873026217202981921654673840142095839603360666049476100561268336225902504932800605464136192275593886736746497955270280541423593

p2_add_q2=274773146761138462708137582309097386437793891793691383033856524303010811294101933454824485010521468914846151819876043508541879637544444256520741418495479393777132830985856522008561088410862815913292288683761657919121930016956916865849261153721097671315883469348972925757078089715102032241818526925988645578778

p2_mul_q2=18514724270030962172566965941723224386374076294232652258701085781018776172843355920566035157331579524980108190739141959926523082142273672741849552475156278397131571360099018592018959785627785130126477982765210498547680367230723634424036009539347854344573537848628061468892166199866227984167843139793429682559241317072979374002912607549039431398267184818771503468116379618249319324788996321340764624593443106354104274472601170229835219638093242557547840060892527576940077162990069687019966946826210112318408269749294366586682732614372434218768720577917368726530200897558912687470088583774711767599580037663378929000217

e = 0x10001

c2 = 25591090168544821761746024178724660839590948190451329227481168576490717242294520739865602061082558759751196452117720647426598261568572440942370039702932821941366792140173428488344932203576334292648255551171274828821657097667106792872200082579319963310503721435500623146012954474613150848083425126987554594651797477741828655238243550266972216752593788734836373144363217639612492397228808215205862281278774096317615918854403992620720969173788151215489908812749179861803144937169587452008097008940710091361183942268245271154461872102813602754439939747566507116519362821255724179093051041994730856401493996771276172343313045755916751082693149885922105491818225012844519264933137622929024918619477538521533548551789739698933067212305578480416163609137189891797209277557411169643568540392303036719952140554435338851671440952865151077383220305295001632816442144022437763089133141886924265774247290306669825085862351732336395617276100374237159580759999593028756939354840677333467281632435767033150052439262501059299035212928041546259933118564251119588970009016873855478556588250138969938599988198494567241172399453741709840486953189764289118312870580993115636710724139809708256360212728127786394411676427828431569046279687481368215137561500777480380501551616577832499521295655237360184159889151837766353116185320317774645294201044772828099074917077896631909654671612557207653830344897644115936322128351494551004652981550758791285434809816872381900401440743578104582305215488888563166054568802145921399726673752722820646807494657299104190123945675647

q2 = n2 // (p2_mul_q2*p2_mul_q2) #//是python的除法下取整运算符

p2 = p2_mul_q2 // q2

d2 = libnum.invmod(e, p2*(p2 - 1)*q2*q2*(q2 - 1)) #invmod(a, n) - 求a对于n的模逆,这里逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据e*d=1modψ(n),求出d

m = pow(c2, d2, n2) # 这里的m是十进制形式,pow(x, y[, z])--函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z,对应前面解密算法中M=D(C)=(C^d)mod n

string = long_to_bytes(m) # 获取m明文

print(string)

结果:

2021年10月广东强网杯,CRYPTO的RSA AND BASE?:(排列组合算法、下标对应解密)

下载附件,是一个txt文件,打开,发现RSA密文和类似base32的变码表,也符合题目暗示:

RSA题目照例先用CTF-RSA-TOOL工具跑一下,发现跑得出来:

这应该是一层的flag,而且看起来像base32的四个等号,联想题目和TXT文件中后面的BASE码,可以猜出是BASE32变码的加密,而且还有4位未知:

首先通过和密文以及传统base32的码表对比可以发现缺了2 T Y Z四个字母,这四个字母共有24种排列组合,可以用下面代码求出排列组合:

list1=['2','T','Z','Y']

len1=len(list1)

list2=[]

w=""

for i in list1:

for j in list1:

if j!=i:

for k in list1:

if k!=j and k!=i:

for l in list1:

if l !=k and l !=j and l !=i:

w=i+j+k+l

list2.append(w)

print(list2)

print(len(list2))

结果:

然后就是获取BASE32的编码实现来替换码表了,由于我在网上找不到base32的python编码实现,而且我也不会GO语言,没法直接替换封装函数码表,所以我用了我广州羊城杯的BabySmc技巧,通过下标对应来转为传统的base32密文。

下标对应法,这就要了解base32加密解密的本质了。

base32加密是5*8变8*5,获取的5个8位数对应着0~32内的范围,而base32的基本字符表ABCDEFGHIJKLMNOPQRSTUVWXYZ234567不过是0~32范围内对应的映射下标而已。

解密的时候也是用每个加密字符在0 ~32范围的数来拆分解密,关键就是这个解密时的5位数是怎么找的呢?是通过base32.index('加密字符')来找对应的0 ~ 32的下标。

所以加密字符表单的作用只是用来根据下标来映射5位数的0~32的范围而已,本质是0 ~64的下标。

那么我们就可以通过一一对应的方法来把题目中新的加密表单的下标来对应原生的base32加密下标了,因为base32在线解密工具只能通过base32.index('加密字符')来找0 ~ 32的下标。

脚本如下,注意抽出'='来,并且在最后要把'='加上去,因为base32解密必须是8的倍数:

import base64

#key1="GHI45FQRSCX****UVWJK67DELMNOPAB3" #少了2TYZ

key1="GHI45FQRSCX" #变形表单1

key2="UVWJK67DELMNOPAB3" #变形表单2

base32="ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" #传统表单

key3="TCMDIEOH2MJFBLKHT2J7BLYZ2WUE5NYR2HNG" #变形密文

list1=['2TZY', '2TYZ', '2ZTY', '2ZYT', '2YTZ', '2YZT', 'T2ZY', 'T2YZ', 'TZ2Y', 'TZY2', 'TY2Z', 'TYZ2', 'Z2TY', 'Z2YT', 'ZT2Y', 'ZTY2', 'ZY2T', 'ZYT2', 'Y2TZ', 'Y2ZT', 'YT2Z', 'YTZ2', 'YZ2T', 'YZT2']

secret=""

for i in list1:

key4=key1+i+key2 #最终变形表单

#print(key4)

for m in key3:

g=key4.index(m)

secret+=base32[g]

secret+='====' #注意抽出'='来,并且在最后要把'='加上去,因为base32解密必须是8的倍数

print(secret)

print(base64.b32decode(secret))

secret=""

结果:

ECC椭圆曲线加密:

攻防世界之easy_ECC:(ECC加密)

下载附件,打开:

椭圆曲线ECC加密,没接触过,不懂原理,主要是找不到集成脚本,算了,浏览中发现一篇讲得透彻的博客:

https://blog.csdn.net/weixin_30951231/article/details/95919343

这里直接使用脚本:

#!/usr/bin/env python3

# -*- coding: UTF-8 -*-

# @Time :2020/9/28

# @Author :PeterJoin

import collections

import random

EllipticCurve = collections.namedtuple('EllipticCurve', 'name p a b g n h')

def banner():

print(("""%s

_____ ____ ____

| ____/ ___/ ___|

| _|| | | |

| |__| |__| |___

|_____\____\____|

%s%s

# Coded By PeterJoin -椭圆曲线加密(´・ω・)%s

""" % ('\033[91m', '\033[0m', '\033[93m', '\033[0m')))

curve = EllipticCurve(

'secp256k1',

# Field characteristic.

p=int(input('p=')),

# Curve coefficients.

a=int(input('a=')),

b=int(input('b=')),

# Base point.

g=(int(input('Gx=')),

int(input('Gy='))),

# Subgroup order.

n=int(input('k=')),

# Subgroup cofactor.

h=1,

)

# Modular arithmetic ##########################################################

def inverse_mod(k, p):

"""Returns the inverse of k modulo p.

This function returns the only integer x such that (x * k) % p == 1.

k must be non-zero and p must be a prime.

"""

if k == 0:

raise ZeroDivisionError('division by zero')

if k < 0:

# k ** -1 = p - (-k) ** -1 (mod p)

return p - inverse_mod(-k, p)

# Extended Euclidean algorithm.

s, old_s = 0, 1

t, old_t = 1, 0

r, old_r = p, k

while r != 0:

quotient = old_r // r

old_r, r = r, old_r - quotient * r

old_s, s = s, old_s - quotient * s

old_t, t = t, old_t - quotient * t

gcd, x, y = old_r, old_s, old_t

assert gcd == 1

assert (k * x) % p == 1

return x % p

# Functions that work on curve points #########################################

def is_on_curve(point):

"""Returns True if the given point lies on the elliptic curve."""

if point is None:

# None represents the point at infinity.

return True

x, y = point

return (y * y - x * x * x - curve.a * x - curve.b) % curve.p == 0

def point_neg(point):

"""Returns -point."""

assert is_on_curve(point)

if point is None:

# -0 = 0

return None

x, y = point

result = (x, -y % curve.p)

assert is_on_curve(result)

return result

def point_add(point1, point2):

"""Returns the result of point1 + point2 according to the group law."""

assert is_on_curve(point1)

assert is_on_curve(point2)

if point1 is None:

# 0 + point2 = point2

return point2

if point2 is None:

# point1 + 0 = point1

return point1

x1, y1 = point1

x2, y2 = point2

if x1 == x2 and y1 != y2:

# point1 + (-point1) = 0

return None

if x1 == x2:

# This is the case point1 == point2.

m = (3 * x1 * x1 + curve.a) * inverse_mod(2 * y1, curve.p)

else:

# This is the case point1 != point2.

m = (y1 - y2) * inverse_mod(x1 - x2, curve.p)

x3 = m * m - x1 - x2

y3 = y1 + m * (x3 - x1)

result = (x3 % curve.p,

-y3 % curve.p)

assert is_on_curve(result)

return result

def scalar_mult(k, point):

"""Returns k * point computed using the double and point_add algorithm."""

assert is_on_curve(point)

if k < 0:

# k * point = -k * (-point)

return scalar_mult(-k, point_neg(point))

result = None

addend = point

while k:

if k & 1:

# Add.

result = point_add(result, addend)

# Double.

addend = point_add(addend, addend)

k >>= 1

assert is_on_curve(result)

return result

# Keypair generation and ECDHE ################################################

def make_keypair():

"""Generates a random private-public key pair."""

private_key = curve.n

public_key = scalar_mult(private_key, curve.g)

return private_key, public_key

private_key, public_key = make_keypair()

print("private key:", hex(private_key))

print("public key: (0x{:x}, 0x{:x})".format(*public_key))

if __name__ == '__main__':

banner()

make_keypair()

运行之后照着输入题目附件给的参数即可:

解出的x+y就是flag了,原理太难了,以后有机会再接触。

LFSR反馈移位寄存器类型:

攻防世界之streamgame1:(CTF中的LFSR考点(一)、文件读取对齐的二进制)

下载附件,是典型的LFSR类型:

from flag import flag

assert flag.startswith("flag{")

# 作用:判断字符串是否以指定字符或子字符串开头flag{

assert flag.endswith("}")

# 作用:判断字符串是否以指定字符或子字符串结尾},flag{},6个字节

assert len(flag)==25

# flag的长度为25字节,25-6=19个字节

#3<<2可以这么算,bin(3)=0b11向左移动2位变成1100,0b1100=12(十进制)

def lfsr(R,mask):

output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111'=0xffffff的二进制补码

i=(R&mask)&0xffffff #按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0

lastbit=0

while i!=0:

lastbit^=(i&1) #按位异或运算符:当两对应的二进位相异时,结果为1

i=i>>1

output^=lastbit

return (output,lastbit)

R=int(flag[5:-1],2)

mask = 0b1010011000100011100

f=open("key","ab") #以二进制追加模式打开

for i in range(12):

tmp=0

for j in range(8):

(R,out)=lfsr(R,mask)

tmp=(tmp << 1)^out #按位异或运算符:当两对应的二进位相异时,结果为1

f.write(chr(tmp)) #chr() 用一个范围在 range(256)内的(就是0~255)整数作参数,返回一个对应的字符。

f.close()

明文key如下,需要转成能推出初始状态值(flag)的对应位数的flag:

LFSR类型我在后面非传统密码类型解析中已经总结过了,所以这里直接应用前面的总结步骤仿照着做即可:

补充:

最后的 12 内嵌 8 循环一共产生12个字符。其中的前 3 个字符的前 19 位二进制数是一个加密循环。19 位后面的数是继续用这 19 个加密后的二进制数继续新一轮加密,就是多层加密。所以我们取 19 位即可,结果 flag 也是 19 个二进制数。

关键就是这个key值怎么取,一开始我直接复制粘贴字符转16进制,然后取前19位,可想而知当然是错的了:

然后查了好些资料发些他们从文件中读取二进制数的代码还是不够简便,于是我吸取了我前面base64编码的代码写了一串从文件中读取对齐的二进制的代码,以后也直接拿来用即可。

(在线转换都会省略最开头的0导致结果位数错误,进而导致结果错误,所以自己要注意。)

f = open('5key','rb') #以二进制格式打开文件

content = f.read() #读取的是\xhh类型的十六进制

key=['{:0>8}'.format(str(bin(i)).replace('0b','')) for i in content] #从base64编码汲取的经验,二进制8位对齐。

print(''.join(key)[:19])

最终解题脚本,还是一样要注意小端顺序:

f = open('5key','rb') #以二进制格式打开文件

content = f.read() #读取的是\xhh类型的十六进制

key=['{:0>8}'.format(str(bin(i)).replace('0b','')) for i in content] #从base64编码汲取的经验,二进制8位对齐。

key1=''.join(key)[:19] #lastbit全部值,就是反馈函数生成的值,32位的key1

key2=key1

flag=[]

for i in range(19):

output='?'+key1[:18] #?0100000111111011110111011111000,因为后面有key1=str(lastbit)+key1[:31],key1不断填补,output不断取前31位,所以这里output每次把?定在第i位上,注意output和key1是独立的分开的。

flag.append(str(int(key2[-1-i])^int(output[-3])^int(output[-4])^int(output[-5])^int(output[-9])^int(output[-13])^int(output[-14])^int(output[-17])))

#这里之所以取负数是因为我们截取是从左往右取,而在计算机中是小端顺序,应该从右往左取才对,这里的key2[-1-i]就是小端左到右的第i位,也就是前面分析的反馈函数生成值的第i位。flag值的原第i位,现在在第19位,可以通过⊕的可逆性来求,就是R19=lastbit ⊕ R3 ⊕ R4 ⊕ R5 ⊕ R9 ⊕ R13 ⊕ R14 ⊕ R17

key1=str(flag[i])+key1[:18] #不断填补key1,让key1向右推进,

print("flag{"+bin(int(''.join(flag[::-1]),2)).replace('0b','')+"}") #这里是经过一系列操作,首先把flag变成小端顺序的[::-1],然后就是转十六进制。

结果:

攻防世界之streamgame2:(CTF中的LFSR考点(一)、文件读取对齐的二进制)

下载附件,还是典型的LFSR类型:

from flag import flag

assert flag.startswith("flag{")

assert flag.endswith("}")

assert len(flag)==27

def lfsr(R,mask):

output = (R << 1) & 0xffffff

i=(R&mask)&0xffffff

lastbit=0

while i!=0:

lastbit^=(i&1)

i=i>>1

output^=lastbit

return (output,lastbit)

R=int(flag[5:-1],2)

mask=0x100002

f=open("key","ab")

for i in range(12):

tmp=0

for j in range(8):

(R,out)=lfsr(R,mask)

tmp=(tmp << 1)^out

f.write(chr(tmp))

f.close()

原理同streamgame1,这里唯一的不同就是mask也是要截取的,因为mask要看成常数,要求的是21位初始值,所以24位的mask要截取成21位。

补充:

最后的 12 内嵌 8 循环一共产生12个字符。其中的前 3 个字符的前 21 位二进制数是一个加密循环。21 位后面的数是继续用这 21 个加密后的二进制数继续新一轮加密,就是多层加密。所以我们取 21 位即可,结果 flag 也是 21 个二进制数。

直接上脚本:

f = open('3key','rb') #以二进制格式打开文件

content = f.read() #读取的是\xhh类型的十六进制

key=['{:0>8}'.format(str(bin(i)).replace('0b','')) for i in content] #从base64编码汲取的经验,二进制8位对齐。

key1=''.join(key)[:21] #lastbit全部值,就是反馈函数生成的值,32位的key1

key2=key1

flag=[]

for i in range(21):

output='?'+key1[:20] #?0100000111111011110111011111000,因为后面有key1=str(lastbit)+key1[:31],key1不断填补,output不断取前31位,所以这里output每次把?定在第i位上,注意output和key1是独立的分开的。

flag.append(str(int(key2[-1-i])^int(output[-2])))

#这里之所以取负数是因为我们截取是从左往右取,而在计算机中是小端顺序,应该从右往左取才对,这里的key2[-1-i]就是小端左到右的第i位,也就是前面分析的反馈函数生成值的第i位。flag值的原第i位,现在在第21位,可以通过⊕的可逆性来求,就是R21=lastbit ⊕ R2

key1=str(flag[i])+key1[:20] #不断填补key1,让key1向右推进,

print("flag{"+bin(int(''.join(flag[::-1]),2)).replace('0b','')+"}") #这里是经过一系列操作,首先把flag变成小端顺序的[::-1],然后就是转十六进制。

结果:

js类型加密

js逻辑平铺类型:

攻防世界之flag_in_your_hand1:(字符串中文含义暗示、冗余中锁定关键代码)

下载附件,解压,一个js一个html,两边出击,浏览器看html页面,记事本看js和html的逻辑和它们之间的关系:

bm函数,我在js代码那里跟踪啊跟踪,发现它是好多个函数的嵌套,没办法了,根本不知道关键逻辑放在哪里。查了资料说看跟踪ic,真是一语惊醒梦中人!ic是判断条件,归根结底还是判断ic,找ic即可:

找到ic了,这个ic也的确在bm函数嵌套内,由于在学逆向,所以直接写逆向脚本即可:

key1=[118, 104, 102, 120, 117, 108, 119, 124, 48,123,101,120]

token=""

for i in key1:

token+=chr(i-3)

print(token)

结果:

最后回顾一下,为什么下面这个每次都有且每次都不一样呢,观察js代码可以发现每个js函数的接受参数s就是我们传入token,而fg生成函数bm嵌套了很多函数,所以直接逆向bm函数生成flag不现实,而参数token作为s传入后就会加密回显,所以输入错误的token也会显示出不同的加密串:

python类型逻辑加密

pyc文件反编译:

攻防世界之easychallenge:(源代码修改逻辑解密、)

下载附件,是pyc文件,于是要反编译,一开始看资料说用uncompyle6,我也不知道为什么我的老是报错,后来又找了个在线反编译,可以支持的Python版本比较多:

https://tool.lu/pyc/

反编译代码:

#!/usr/bin/env python

# visit https://tool.lu/pyc/ for more information

import base64

def encode1(ans):

s = ""

for i in ans:

x = ord(i) ^ 36

x = x + 25

s += chr(x)

return s

def encode2(ans):

s = ""

for i in ans:

x = ord(i) + 36

x = x ^ 36

s += chr(x)

return s

def encode3(ans):

return base64.b32encode(ans)

flag = " "

print "Please Input your flag:"

flag = raw_input()

final = "UC7KOWVXWVNKNIC2XCXKHKK2W5NLBKNOUOSK3LNNVWW3E==="

if encode3(encode2(encode1(flag))) == final:

print "correct"

else:

print "wrong"

本来是自己一层层改的,怎么加密就怎么逆过来解密,后来发现又犯了以前的错误,有源码就要用源码啊!!!

直接在源码上修改即可:

#!/usr/bin/env python

# visit https://tool.lu/pyc/ for more information

import base64

def decode1(ans):

s = ''

for i in ans:

x = ord(i) -25

x = x ^ 36

s += chr(x)

return s

def decode2(ans):

s = ''

for i in ans:

x = i ^ 36

x = x - 36

s += chr(x)

return s

def decode3(ans):

return base64.b32decode(ans)

final = 'UC7KOWVXWVNKNIC2XCXKHKK2W5NLBKNOUOSK3LNNVWW3E==='

print(decode1(decode2(decode3(final))) )

传统密码类型解析

凯撒密码(24个字母):

特点:24个字母间的移动

在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。

加密就是明文向后移动展现出对应的密文。

解密就是密文向前移动展现出对应的明文。

明文字母表

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

密文字母表

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Y

Z

摩斯密码(只有01(无规则)或.-,空格或/做分隔符):

摩尔斯电码也被称作摩斯密码,是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号。它发明于1837年,是一种早期的数字化通信形式。不同于现代化的数字通讯,摩尔斯电码只使用零和一两种状态的二进制代码,它的代码包括五种:短促的点信号“・”,读“滴”(Di)保持一定时间的长信号“-”,读“嗒”(Da)表示点和划之间的停顿、每个词之间中等的停顿,以及句子之间长的停顿。

摩斯电码:(格式要求:可用空格或单斜杠/来分隔摩斯电码,但只可用一种,不可混用)

云影密码(01248):

此密码运用了1248代码,因为本人才疏学法,问未发现有过使用的先例,因此暂归为原创密码。由于这个密码,我和片风云影初识,为了纪念,将其命名为“云影密码”。

有了1,2,4,8这四个苘单的数字,你可以以加法表示出0~9任何个数字,例如0=28,7=124,9=18这样,再用1-26来表示A-Z,就可以用作密码了。为了不至于混乱,我个人引入了第五个数字0,来用作间隔,以遍免翻译错误,所以还可以称“01248密码”

注意(3个及以上数字时):

虽然是相加,但是可以在数字内不按顺序相加,如124可写成(12)4和1(24)结果分别是7和16,只要保证不大于26即可

题目(总不超过26):

12401011801180212011401804

第一步分割:

即124 、1、118、118、212、114、18、4

第二步基本翻译:

例如124可以表示7,也可以表示16(但不可能是34,因为不会超过26),所以可以放弃来翻译其他没有异议的,可得:124、a、s、s、w、o、18、d

第三步推测得出明文:

可以推测后面的18表示r,前面的为p最合适。

所以最后明文:

password(密码)

栅栏密码(分组数作密钥):

所谓栅栏密码,就是把要加密的明文分成N个一组,然后把每组的第1个字连起来,形成一段无规律的话。 不过栅栏密码本身有一个潜规则,就是组成栅栏的字母一般不会太多。(一般不超过30个,也就是一、两句话)

传统栅栏密码(矩阵行列,密钥是行数):

假如有一个字符串:123456789

取字符串长度的因数进行分组,假如key=3

1 2 3 \\分组情况,每三个数字一组,分为三组

4 5 6

7 8 9

然后每一组依次取一个数字组成一个新字符串:147258369 \\加密完成的字符串

解题:

试一般的栅栏密码,取5为矩阵行数,得到" cyperrocaegireeol} eahfocec gnbip不正确,取5为矩阵列数,得到" cebgccfe en eohplprgecrayoii aoreg”,也不正确,除了常规的栅栏密码,还有一种w型的栅栏密码。

w型的栅栏密码(第一行是Key数,后面排成w型横竖读取):

同样一个字符串:123456789

key=3

1----5----9 \\让数字以W型组织,同样是三组,但每组的数量不一定相同

-2--4-6--8

--3----7--

加密密文:159246837

解题:

题目提示:栅栏密码,密钥长度为5

是将明文按照w型排列,并横(竖)向读取密文,其解密过程就是加密的逆过程,即将密文横(竖)向按一定规律排列后,以w型读取,对于此题,根据题目提示为以下5行。

培根密码(大小写的ABab,而且必须是5个一组,不是5个就考虑摩斯密码):

培根所用的密码是一种本质上用二进制数设计的,没有用通常的0和1来表示,而是采用a和b

培根密码加密方式

第一种方式:

A aaaaa B aaaab C aaaba D aaabb E aabaa F aabab G aabba H aabbb I abaaa J abaab

K ababa L ababb M abbaa N abbab O abbba P abbbb Q baaaa R baaab S baaba T baabb

U babaa V babab W babba X babbb Y bbaaa Z bbaab

第二种方式:

a AAAAA g AABBA n ABBAA t BAABA

b AAAAB h AABBB o ABBAB u-v BAABB

c AAABA i-j ABAAA p ABBBA w BABAA

d AAABB k ABAAB q ABBBB x BABAB

e AABAA l ABABA r BAAAA y BABBA

f AABAB m ABABB s BAAAB z BABBB

举例

例1、 baabaaabbbabaaabbaaaaaaaaabbabaaaabaaaaaabaaabaabaaaabaabbbaabbbaababb

baaba aabbb abaaa bbaaa aaaaa abbab aaaab aaaaa abaaa baaba  aaaba abbba abbba ababb

s           h         i           y         a         n         b         a        i           s          c         o          o        l

附加解密Python脚本如下:

#!/usr/bin/python

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

import re

alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

first_cipher = ["aaaaa","aaaab","aaaba","aaabb","aabaa","aabab","aabba","aabbb","abaaa","abaab","ababa","ababb","abbaa","abbab","abbba","abbbb","baaaa","baaab","baaba","baabb","babaa","babab","babba","babbb","bbaaa","bbaab"]

second_cipher = ["aaaaa","aaaab","aaaba","aaabb","aabaa","aabab","aabba","aabbb","abaaa","abaaa","abaab","ababa","ababb","abbaa","abbab","abbba","abbbb","baaaa","baaab","baaba","baabb","baabb","babaa","babab","babba","babbb"]

def encode():

string = raw_input("please input string to encode:\n") #这里接收要加密的字符串

e_string1 = ""

e_string2 = ""

for index in string:

for i in range(0,26):

if index == alphabet[i]:

e_string1 += first_cipher[i]

e_string2 += second_cipher[i]

break

print "first encode method result is:\n"+e_string1

print "second encode method result is:\n"+e_string2

return

def decode():

e_string = raw_input("please input string to decode:\n") #这里接收要解密的字符串

e_array = re.findall(".{5}",e_string)

d_string1 = ""

d_string2 = ""

for index in e_array:

for i in range(0,26):

if index == first_cipher[i]:

d_string1 += alphabet[i]

if index == second_cipher[i]:

d_string2 += alphabet[i]

print "first decode method result is:\n"+d_string1

print "second decode method result is:\n"+d_string2

return

if __name__ == '__main__':

while True:

print "\t*******Bacon Encode_Decode System*******"

print "input should be lowercase,cipher just include a b"

print "1.encode\n2.decode\n3.exit"

s_number = raw_input("please input number to choose\n")

if s_number == "1":

encode()

raw_input()

elif s_number == "2":

decode()

raw_input()

elif s_number == "3":

break

else:

continue

与佛论禅编码,要加上佛曰:才能转换(BASE64类型转不了就ROT13一下)

网址:

与佛论禅

题目文字:

夜哆悉諳多苦奢陀奢諦冥神哆盧穆皤三侄三即諸諳即冥迦冥隸數顛耶迦奢若吉怯陀諳怖奢智侄諸若奢數菩奢集遠俱老竟寫明奢若梵等盧皤豆蒙密離怯婆皤礙他哆提哆多缽以南哆心曰姪罰蒙呐神。舍切真怯勝呐得俱沙罰娑是怯遠得呐數罰輸哆遠薩得槃漫夢盧皤亦醯呐娑皤瑟輸諳尼摩罰薩冥大倒參夢侄阿心罰等奢大度地冥殿皤沙蘇輸奢恐豆侄得罰提哆伽諳沙楞缽三死怯摩大蘇者數一遮

转换后的

MzkuM3gvMUAwnzuvn3cgozMlMTuvqzAenJchMUAeqzWenzEmLJW9

的确是BASE64类型,但是直接BASE64是转换不出来的,还要先ROT13一下,可以算是一个小混淆,长见识了。

转轮机加密:

特点是等长的分好组的乱序字母,原理是转齿轮把一个字母换成另一个来拼成一句话。

格式是这样的:

脚本解题积累:

rotor = [ #这里是要输入的转轮机原始字符串

"ZWAXJGDLUBVIQHKYPNTCRMOSFE", "KPBELNACZDTRXMJQOYHGVSFUWI",

"BDMAIZVRNSJUWFHTEQGYXPLOCK", "RPLNDVHGFCUKTEBSXQYIZMJWAO",

"IHFRLABEUOTSGJVDKCPMNZQWXY", "AMKGHIWPNYCJBFZDRUSLOQXVET",

"GWTHSPYBXIZULVKMRAFDCEONJQ", "NOZUTWDCVRJLXKISEFAPMYGHBQ",

"XPLTDSRFHENYVUBMCQWAOIKZGJ", "UDNAJFBOWTGVRSCZQKELMXYIHP",

"MNBVCXZQWERTPOIUYALSKDJFHG", "LVNCMXZPQOWEIURYTASBKJDFHG",

"JZQAWSXCDERFVBGTYHNUMKILOP"

]

cipher = "NFQKSEVOQOFNP" #这是要输入转轮机密文

key = [2,3,7,5,13,12,9,1,8,10,4,11,6] #这是要输入转轮机密钥

tmp_list=[]

for i in range(0, len(rotor)):

tmp=""

k = key[i] - 1

for j in range(0, len(rotor[k])):

if cipher[i] == rotor[k][j]:

if j == 0:

tmp=rotor[k]

break

else:

tmp=rotor[k][j:] + rotor[k][0:j]

break

tmp_list.append(tmp)

# print(tmp_list)

message_list = []

for i in range(0, len(tmp_list[i])):

tmp = ""

for j in range(0, len(tmp_list)):

tmp += tmp_list[j][i]

message_list.append(tmp)

print(message_list)

def spread_list(lst):

for item in lst:

if isinstance(item,(list,tuple)):

yield from spread_list(item)

else:

yield item

pass

if __name__ == '__main__':

for i in spread_list(message_list):

print("*"*25)

print(i) #在多个输出中查找有语义的字符串即为flag内容

键盘密码:

键盘密码应该不算是一种加密算法,但是一种有趣的设置密码方式。他就是a-z(A-Z)对应成键盘上的字母,把键盘字母一行一行的对应即可。包围的键就是要找的值。

每个围起来的圈之间通常会有明显的间隔,比如空格。如:r5yG lp9I BjM tFhB T6uh y7iJ QsZ bhM

poem codes诗歌加密:

(内容地址出处)https://blog.csdn.net/weixin_45530599/article/details/108027293:

① 给出一首诗歌

for my purpose holds to sail beyond the sunset, and the baths of all the western stars until I die.

② 给出5个关键单词。

“for”, “sail”, “all”, “stars”, “die.”

对其进行拆散:

f o r s a i l a l l s t a r s d i e

接下来按照 字母表顺序 进行编号,若遇相同字母,则继续 +1

③ 将要传递的消息进行加密。

We have run out of cigars, situation desperate。

先对其进行编码。因为给出的5个关键词,其长度为18.所以以18为一组。

若一组长度不满18,则用abc(不要求有序)进行补充。

将排好的消息,按照之前给出的诗歌字母编号写下密文。

for my purpose holds to sail beyond the sunset, and the baths of all the western stars until I die.

如, for --> eud tdk oek 那么得到的又可以按照5个(适当个数)为一组进行重新分组,得到最后密文。

我的看法:

其实排序逻辑挺常规的,就是诗歌 --> 关键词,原文 --> 参照顺序排列,密文 --> 按诗歌关键词对原文映射取值。

解题脚本:

用github的脚本:(单独复制poemcode.py是会报错的,因为文件中有其他依靠):

git clone git://github.com/abpolym/crypto-tools

用法:(python2,ctfpoem是诗歌,ctfcip是加密密文)

python2 poemcode.py examples/2/ctfpoem examples/2/ctfcip

URL编码规则:

URL 编码使用 "%" 其后跟随两位的十六进制数来替换非 ASCII 字符。

ASCII Value

URL-encode

ASCII Value

URL-encode

ASCII Value

URL-encode

ASCII Value

URL-encode

ASCII Value

URL-encode

ASCII Value

URL-encode

NULL结束符

%00

0

%30

`

%60

%90

À

%c0

ð

%f0

%01

1

%31

a

%61

%91

Á

%c1

ñ

%f1

%02

2

%32

b

%62

%92

Â

%c2

ò

%f2

%03

3

%33

c

%63

%93

Ã

%c3

ó

%f3

%04

4

%34

d

%64

%94

Ä

%c4

ô

%f4

%05

5

%35

e

%65

%95

Å

%c5

õ

%f5

%06

6

%36

f

%66

%96

Æ

%c6

ö

%f6

%07

7

%37

g

%67

%97

Ç

%c7

÷

%f7

backspace

%08

8

%38

h

%68

˜

%98

È

%c8

ø

%f8

tab

%09

9

%39

i

%69

%99

É

%c9

ù

%f9

换行符

%0a

:

%3a

j

%6a

š

%9a

Ê

%ca

ú

%fa

%0b

;

%3b

k

%6b

%9b

Ë

%cb

û

%fb

%0c

<

%3c

l

%6c

œ

%9c

Ì

%cc

ü

%fc

c return

%0d

=

%3d

m

%6d

%9d

Í

%cd

ý

%fd

%0e

>

%3e

n

%6e

ž

%9e

Î

%ce

þ

%fe

%0f

?

%3f

o

%6f

Ÿ

%9f

Ï

%cf

ÿ

%ff

%10

@

%40

p

%70

%a0

Ð

%d0

%11

A

%41

q

%71

¡

%a1

Ñ

%d1

%12

B

%42

r

%72

¢

%a2

Ò

%d2

%13

C

%43

s

%73

£

%a3

Ó

%d3

%14

D

%44

t

%74

%a4

Ô

%d4

%15

E

%45

u

%75

¥

%a5

Õ

%d5

%16

F

%46

v

%76

|

%a6

Ö

%d6

%17

G

%47

w

%77

§

%a7

%d7

%18

H

%48

x

%78

¨

%a8

Ø

%d8

%19

I

%49

y

%79

©

%a9

Ù

%d9

%1a

J

%4a

z

%7a

ª

%aa

Ú

%da

%1b

K

%4b

{

%7b

«

%ab

Û

%db

%1c

L

%4c

|

%7c

¬

%ac

Ü

%dc

%1d

M

%4d

}

%7d

¯

%ad

Ý

%dd

%1e

N

%4e

~

%7e

®

%ae

Þ

%de

%1f

O

%4f

%7f

¯

%af

ß

%df

空格

%20

P

%50

%80

°

%b0

à

%e0

!

%21

Q

%51

%81

±

%b1

á

%e1

"

%22

R

%52

%82

²

%b2

â

%e2

#

%23

S

%53

ƒ

%83

³

%b3

ã

%e3

$

%24

T

%54

%84

´

%b4

ä

%e4

%

%25

U

%55

%85

µ

%b5

å

%e5

&

%26

V

%56

%86

%b6

æ

%e6

'

%27

W

%57

%87

·

%b7

ç

%e7

(

%28

X

%58

ˆ

%88

¸

%b8

è

%e8

)

%29

Y

%59

%89

¹

%b9

é

%e9

*

%2a

Z

%5a

Š

%8a

º

%ba

ê

%ea

+

%2b

[

%5b

%8b

»

%bb

ë

%eb

,

%2c

\

%5c

Œ

%8c

¼

%bc

ì

%ec

-

%2d

]

%5d

%8d

½

%bd

í

%ed

.

%2e

^

%5e

Ž

%8e

¾

%be

î

%ee

/

%2f

_

%5f

%8f

¿

%bf

ï

%ef

仿射密码:

仿射密码是一种替换密码,它是一个字母对一个字母的。为单表加密的一种,字母系统中所有字母都藉一简单数学方程加密,对应至数值,或转回字母。 其仍有所有替代密码之弱处。所有字母皆借由方程加密,b为移动大小。

在仿射加密中,大小为m之字母系统首先对应至0..m-1范围内之数值, 接着使用模数算数来将原文件中之字母转换为对应加密文件中的数字。 (其实这有点像我的base64表单下标替换)

它的加密函数是:(其中a和m互质,m是字母的数目)

解密函数是:

补充求集合Z上数x的逆元的:

gmpy2.invert(x,Z) 或 libnum.invmode(e,(p-1)*(q-1))

a之乘法逆元素仅存在于a与m互质条件下。 由此,没有a的限制,可能无法解密。 易知解密方程逆于加密方程:

非传统密码类型解析

CTF中的LFSR考点(一):

前提概要:

这是我在理解了作者:道路结冰的博客深入分析CTF中的LFSR类题目(一)下写的一次回顾和分析,只是在其中加上自己的见识和理解来加深印象。

博客地址: 深入分析CTF中的LFSR类题目(一) - 安全客,安全资讯平台

前言:

LFSR(线性反馈移位寄存器)已经成为如今CTF中密码学方向题目的一个常见考点了,在今年上半年的一些国内赛和国际赛上,也出现了非常多的这类题目,但是其中绝大多数题目目前都没有writeups(或者writeups并没有做cryptanalysis,而是通过爆破的方法解决,这种思路只适用于部分类似去年强网杯出现的几道非常基础的LFSR类题目有效,对于绝大多数国际赛上的题目不仅是没有任何效果的,也是没有任何意义的,只有真正掌握了LFSR的密码学原理,才有可能在国际赛上解决一道高分值的LFSR类题目),网上针对这类考点的详细分析也不多,因此接下来我将通过几篇文章,对这类知识点进行一个详细的分析。

LFSR简介:

LFSR简介:

LFSR是属于FSR(反馈移位寄存器)的一种,除了LFSR之外,还包括NFSR(非线性反馈移位寄存器)。

附加:

反馈移位就是可以通过前面已经存在的寄存器中的值反馈出后面的的寄存器的值,通过不断移位对应不同的前寄存器值一直反馈出后面连续的后寄存器值。

FSR是流密码产生密钥流的一个重要组成部分,在GF(2)上的一个n级FSR通常由n个二元存储器和一个反馈函数组成,如下图所示:

如果这里的反馈函数是线性的,我们则将其称为LFSR,此时该反馈函数可以表示为:

(其中cn=0或1,⊕表示异或(模二加),也就是说反馈函数必然为a1……⊕……an形式中的一部分)

我们接下来通过一个例子来更直观的明确LFSR的概念:

假设给定一个5级的LFSR,其初始状态(即a1到a5这5个二元存储器的值)为:

其反馈函数为:

整个过程可以表示为下图所示的形式:

接下来我们来计算该LFSR的输出序列,输出序列的前5位即为我们的初始状态10011,第6位的计算过程如下:

第7位的计算过程如下:

由此类推,可以得到前31位的计算结果如下:

1001101001000010101110110001111

对于一个 n 级的LFSR来讲,其最大周期为2^n-1 ,因此对于我们上面的 5 级 LFSR 来讲,其最大周期为 2^5-1=31,再后面的输出序列即为前 31 位的循环。

注意:

这里的级就是能通过反馈函数生成完整连续序列的最少寄存器数,因为a6=a1⊕a4,所以a5必须包含在内,所以是5级寄存器。

通过上面的例子我们可以看到,对于一个LFSR来讲,我们目前主要关心三个部分:

初始状态、反馈函数和输出序列。

CTF的LFSR题目示例:

那么对于CTF中考察LFSR的题目来讲也是如此,大多数情况下,我们在CTF中的考察方式都可以概括为:

给出反馈函数和输出序列,要求我们反推出初始状态,初始状态即为我们需要提交的flag,另外大多数情况下,初始状态的长度我们也是已知的。

显然,这个反推并不是一个容易的过程,尤其当反馈函数十分复杂的时候,接下来我们就通过一些比赛当中出现过的具体的CTF题目,来看一下在比赛当中我们应该如何解决这类问题,由于不同题目之间难度差异会很大,所以我们先从最简单的题目开始,我将尽可能的用最通俗的语言和脚本来进行演示,在后面会逐渐提升题目的难度,同时补充相应的代数知识。

2018 CISCN 线上赛 oldstreamgame

题目给出的脚本如下:

flag = "flag{xxxxxxxxxxxxxxxx}"

assert flag.startswith("flag{")

assert flag.endswith("}")

assert len(flag)==14

def lfsr(R,mask):

output = (R << 1) & 0xffffffff

i=(R&mask)&0xffffffff

lastbit=0

while i!=0:

lastbit^=(i&1)

i=i>>1

output^=lastbit

return (output,lastbit)

R=int(flag[5:-1],16)

mask = 0b10100100000010000000100010010100

f=open("key","w")

for i in range(100):

tmp=0

for j in range(8):

(R,out)=lfsr(R,mask)

tmp=(tmp << 1)^out

f.write(chr(tmp))

f.close()

分析一下我们的已知条件(1):

已知初始状态的长度为4个十六进制数,即32位,初始状态的值即我们要去求的flag,所以初步判断这里的级是32,那么最大周期就是2^32-1。

已知反馈函数lfsr,只不过这里的反馈函数是代码的形式,我们需要提取出它的数学表达式。 已知输出序列。

那么我们的任务很明确,就是通过分析lfsr函数,整理成数学表达式的形式求解即可,接下来我们一行一行的来分析这个函数:

把反馈函数从代码形式整理成反馈函数表达式:

通过上面的分析,我们可以看出在这道题的情境下,lfsr函数本质上就是一个输入R输出lastbit的函数,虽然我们现在已经清楚了R是如何经过一系列运算得到lastbit的,但是我们前面的反馈函数都是数学表达式的形式,我们能否将上述过程整理成一个表达式的形式呢?这就需要我们再进一步进行分析:

mask只有第3、5、8、12、20、27、30、32这几位为1,其余位均为0。

mask与R做按位与运算得到i,当且仅当R的第3、5、8、12、20、27、30、32这几位中也出现1时,i中才可能出现1,否则i中将全为0。

lastbit是由 i 的最低位向i的最高位依次做异或运算得到的,在这个过程中,所有为 0 的位我们可以忽略不计(因为0异或任何数等于任何数本身,不影响最后运算结果),因此lastbit的值仅取决于 i 中有多少个1:当i中有奇数个1时,lastbit等于1;当i中有偶数个1时,lastbit等于0。

当R的第3、5、8、12、20、27、30、32这几位依次异或结果为1时,即R中有奇数个1,因此将导致 i 中有奇数个1;当R的第3、5、8、12、20、27、30、32这几位依次异或结果为0时,即R中有偶数个1,因此将导致 i 中有偶数个1。

因此我们可以建立出联系:lastbit等于R的第3、5、8、12、20、27、30、32这几位依次异或的结果。

将其写成数学表示式的形式,即为我们要求的反馈函数,反馈函数的形式也说明了初始位数要32位:

然后我们看一下明文key是怎么来的:

key=20FDEEF8A4C9F4083F331DA8238AE5ED083DF0CB0E7A83355696345DF44D7C186C1F459BCE135F1DB6C76775D5DCBAB7A783E48A203C19CA25C22F60AE62B37DE8E40578E3A7787EB429730D95C9E1944288EB3E2E747D8216A4785507A137B413CD690C

最后八行代码,对flag,它做了一百次循环,每次循环内都嵌套了8位的循环来产生一个结果字符,并将这个结果写到key里面去,所以key里面总共有一百个ASCII字符,共两百个16进制数。(4位为1个16进制数,1个字符byte是8位)

补充:

题目之所以会出现 100 个ASCII字符是因为 4 循环次加内嵌的 8 位一次共 32 位循环往后产生的 4 个flag生成的加密字符共 8 个 16 进制数后,继续用这 4 个加密后的 flag 字符继续新一轮加密,就是多层加密。所以我们取 32 位即可,结果 flag 也是 4 个ASCII字符拆分出的 8 个 16 进制数。

显然,lastbit和R之间满足线性关系,那么接下来我们就可以开始求解了:

而且从这里我们可以知道,这种移位的CTF题目类型要反推32位的初始值要多少位输出序列呢,答案就是32位,因为这种移位的题目是32位为一个循环,这就和我们前面说的2^32-1的循环不太同了,因为这里是移位操作。

32位Key值:00100000111111011110111011111000

解题的关键是发现在明文只剩最后一位时,可以通过最后的结果来求出排在第32位的第一位,然后就可以反推回去了。

我们想象这样一个场景,当即将输出第32位lastbit时,此时R已经左移了31位,根据上面的数学表达式,我们有:

这样我们就可以求出R的第1位,同样的方法,我们可以求出R的第2位:

以此类推,R的全部32位我们都可以依次求出了。

最终脚本,这里注意小端顺序的反序取位:

key1="00100000111111011110111011111000" #lastbit全部值,就是反馈函数生成的值,32位的key1

key2=key1

flag=[]

for i in range(32):

output='?'+key1[:31] #?0100000111111011110111011111000,因为后面有key1=str(lastbit)+key1[:31],key1不断填补,output不断取前31位,所以这里output每次把?定在第i位上,注意output和key1是独立的分开的。

flag.append(str(int(key2[-1-i])^int(output[-3])^int(output[-5])^int(output[-8])^int(output[-12])^int(output[-20])^int(output[-27])^int(output[-30])))

#这里之所以取负数是因为我们截取是从左往右取,而在计算机中是小端顺序,应该从右往左取才对,这里的key2[-1-i]就是小端左到右的第i位,也就是前面分析的反馈函数生成值的第i位。flag值的原第i位,现在在第32位,可以通过⊕的可逆性来求,就是R32=lastbit ⊕ R3 ⊕ R5 ⊕ R8 ⊕ R12 ⊕ R20 ⊕ R27 ⊕ R30

key1=str(flag[i])+key1[:31] #不断填补key1,让key1向右推进,

print("flag{"+hex(int(''.join(flag[::-1]),2)).replace('0x','')+"}") #这里是经过一系列操作,首先把flag变成小端顺序的[::-1],然后就是转十六进制。

结果:

解密工具、脚本积累

Ciphey工具:

Ciphey 是一个使用自然语言处理和人工智能的全自动解密/解码/破解工具,只需要输入加密文本,它就能给你返回解密文本。

Ciphey 基本使用:

文件输入:

ciphey -f encrypted.txt

# 或

python -m ciphey -f encrypted.txt

不规范的方法:

ciphey -- "Encrypted input"

# 或

python -m ciphey -- "Encrypted input"

正常方式:

ciphey -t "Encrypted input"

# 或

python -m ciphey -t "Encrypted input"

要去除进度条、概率表和所有噪音,请使用安静模式:

ciphey -t "encrypted text here" -q

Ciphey 支持解密的密文和编码多达51种,下面列出一些基本的选项基本密码:

Caesar Cipher

ROT47 (up to ROT94 with the ROT47 alphabet)

ASCII shift (up to ROT127 with the full ASCII alphabet)

Vigenère Cipher

Affine Cipher

Binary Substitution Cipher (XY-Cipher)

Baconian Cipher (both variants)

Soundex

Transposition Cipher

Pig Latin

现代密码学:

Repeating-key XOR

Single XOR

编码:

Base32

Base64

Z85 (release candidate stage)

Base65536 (release candidate stage)

ASCII

Reversed text

Morse Code

DNA codons (release candidate stage)

Atbash

Standard Galactic Alphabet (aka Minecraft Enchanting Language)

Leetspeak

Baudot ITA2

URL encoding

SMS Multi-tap

DMTF (release candidate stage)

UUencode

Braille (Grade 1)

Ciphey 的功能不仅于本文介绍的这些,本文所介绍的只是冰山一角,它还可以添加属于你自己的解码器:

https://github.com/Ciphey/Ciphey/wiki/Adding-your-own-ciphers

CTF-RSA-tool工具:

RSA前景知识:

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制 。

在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK [2] 。

RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥 [4] 。

RSA脚本工具使用说明:

usage: solve.py [-h]

用法:solve.py[-h] (--decrypt DECRYPT | -c DECRYPT_INT | --private | -i INPUT | -g)

[--createpub] [-o OUTPUT] [--dumpkey] [--enc2dec ENC2DEC] [-k KEY] [-N N] [-e E] [-d D] [-p P] [-q Q] [--KHBFA KHBFA][--pbits PBITS]

[-v]

It helps CTFer to get first blood of RSA-base CTF problems 它有助于CTFer获得RSA基础CTF问题的第一滴血

-v, --verbose print details 详细的打印细节

optional arguments:可选参数(注意!!!这里之间只可选一个,且必选一个!):

-h, --help show this help message and exit --帮助显示此帮助消息并退出

--decrypt DECRYPT decrypt a file, usually like "flag.enc" 解密文件,通常类似于“flag.enc”

(通常搭配k的.pem或.pub一起使用)

-c DECRYPT_INT,

--decrypt_int DECRYPT_INT 解密长整形数

--private Print private key if recovered 打印私钥(如果已解密)

-i INPUT input a file with all necessary parameters (see examples/input_example.txt)

输入包含所有必要参数的文件(请参见示例/输入(示例.txt)

-g, --gadget Use some gadgets to pre-process your data first 使用一些小工具先预处理数据

some gadgets:一些小工具预处理数据(全部可选):

--createpub Take N and e and output to file specified by "-o" or just print it

获取N和e并输出到由“-o”指定的文件或者直接打印出来就行了

-o OUTPUT, --output OUTPUT 输出 Specify the output file path in --createpub mode.

在--createpub模式下指定输出文件路径。

--dumpkey Just print the RSA variables from a key - n,e,d,p,q

只打印一个key-n、e、d、p、q中的RSA变量

--enc2dec ENC2DEC get cipher (in decimalism) from a encrypted file

从加密文件中获取密码(十进制)

the RSA variables:RSA变量:Specify the variables whatever you got指定您得到的变量:(全部可选,实验中发现输入时只能用N、e参数进行命令行输入)

-k KEY, pem file, usually like ".pub" or ".pem", and it begins with "-----BEGIN"

pem文件,通常类似于“.pub”或“.pem”,并以“-----BEGIN”开始

-N N the modulus 模量

-e E the public exponent 公共指数

-d D the private exponent 私人指数

-p P one factor of modulus 模量的一个因子

-q Q one factor of modulus 模量的一个因子

extra variables:额外变量:Used in some special methods 在一些特殊的方法中使用:

--KHBFA KHBFA use Known High Bits Factor Attack, this specify the High Bits of factor

使用已知的高位因子攻击,这指定因子高位

--pbits PBITS customize the bits lenth of factor, default is half of n`s bits lenth

自定义因子的位长度,默认值为n's比特长度

多组n,e,c在解题时长这个样子:

可以看到特征真的就是多个n,e,c,甚至还有d,且不管这里的n,e,c是大还是小,长还是短,都列入多组n,e,c类型里。

一组n,e,c的题目样式:

从这里可以看到一组,n,e,c里面甚至可以没有c,这里的n,e,c也不管大小,长短,这里最后一个hbop的解题要用到前面说得sagemath,这里暂且不说。

不同情景下工具运行示例:

补充:

单个n,e,c,q,p,的时候最好用单个参数输入的方式,不要用文本读取的方式,因为文本读取的时候DEBUG显示的十六进制的d有时并不是我们想要的

# 只需要一组密钥的

# wiener_attack

python2 solve.py --verbose -i examples/wiener_attack.txt

# 或者通过命令行,只要指定对应参数就行了

python2 solve.py --verbose --private -N 460657813884289609896372056585544172485318117026246263899744329237492701820627219556007788200590119136173895989001382151536006853823326382892363143604314518686388786002989248800814861248595075326277099645338694977097459168530898776007293695728101976069423971696524237755227187061418202849911479124793990722597 -e 354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619

# factordb.com

python2 solve.py --verbose -k examples/jarvis_oj_mediumRSA/pubkey.pem --decrypt examples/jarvis_oj_mediumRSA/flag.enc

# Boneh and Durfee attack

# TODO: get an example public key solvable by boneh_durfee but not wiener

# small q attack

python2 solve.py --verbose --private -k examples/small_q.pub

# 2017强网杯线上赛 RSA 费马分解(p&q相近时)

python2 solve.py --verbose -i examples/closed_p_q.txt

# Common factor between ciphertext and modulus attack

python2 solve.py --verbose -k examples/common_factor.pub --decrypt examples/common_factor.cipher

# small e

python2 solve.py --verbose -k examples/small_exponent.pub --decrypt examples/small_exponent.cipher

# rabin method when e == 2

python2 solve.py --verbose -k examples/jarvis_oj_hardRSA/pubkey.pem --decrypt examples/jarvis_oj_hardRSA/flag.enc

# Small fractions method when p/q is close to a small fraction

python2 solve.py --verbose -k examples/smallfraction.pub --private

# Known High Bits Factor Attack

python2 solve.py --verbose -i examples/KnownHighBitsFactorAttack.txt

# 需要多组密钥的

# 第三届上海市大学生网络安全大赛--rrrsa d泄漏攻击

python2 solve.py --verbose -i examples/d_leak.txt

# 模不互素

(模不互素是给你两个单独分解不了的大数级n,方便让你求公因子。然后,只用一个n来加密,对,只用一个n。)

python2 solve.py --verbose -i examples/share_factor.txt

# 共模攻击

python2 solve.py --verbose -i examples/share_N.txt

# Basic Broadcast Attack(低加密指数广播攻击)

python2 solve.py --verbose -i examples/Basic_Broadcast_Attack.txt

RSA通用的简单脚本:(已知p、q、e、c值)

import libnum

from Crypto.Util.number import long_to_bytes

q = int(

"0xa6055ec186de51800ddd6fcbf0192384ff42d707a55f57af4fcfb0d1dc7bd97055e8275cd4b78ec63c5d592f567c66393a061324aa2e6a8d8fc2a910cbee1ed9",

16)

p = int(

"0xfa0f9463ea0a93b929c099320d31c277e0b0dbc65b189ed76124f5a1218f5d91fd0102a4c8de11f28be5e4d0ae91ab319f4537e97ed74bc663e972a4a9119307",

16)

e = int(

"0x6d1fdab4ce3217b3fc32c9ed480a31d067fd57d93a9ab52b472dc393ab7852fbcb11abbebfd6aaae8032db1316dc22d3f7c3d631e24df13ef23d3b381a1c3e04abcc745d402ee3a031ac2718fae63b240837b4f657f29ca4702da9af22a3a019d68904a969ddb01bcf941df70af042f4fae5cbeb9c2151b324f387e525094c41",

16)

c = 0x7fe1a4f743675d1987d25d38111fae0f78bbea6852cba5beda47db76d119a3efe24cb04b9449f53becd43b0b46e269826a983f832abb53b7a7e24a43ad15378344ed5c20f51e268186d24c76050c1e73647523bd5f91d9b6ad3e86bbf9126588b1dee21e6997372e36c3e74284734748891829665086e0dc523ed23c386bb520

n = q * p

d = libnum.invmod(e, (p - 1) * (q - 1)) #invmod(a, n) - 求a对于n的模逆,这里逆向加密过程中计算ψ(n)=(p-1)(q-1),对ψ(n)保密,也就是对应根据ed=1modψ(n),求出d

m = pow(c, d, n) # pow(x, y[, z])--函数是计算 x 的 y 次方,如果 z 在存在,则再对结果进行取模,其结果等效于 pow(x,y) %z,对应前面解密算法中M=D(C)=C^d(mod n)

#print(m) #明文的十进制格式

string = long_to_bytes(m) # m明文,用长字节划范围

print(string.decode())

ECC加密:

介绍:

椭圆曲线密码学(英语:Elliptic curve cryptography,缩写为 ECC),一种建立公开密钥加密的算法,基于椭圆曲线数学。

ECC的主要优势是在某些情况下它比其他的方法使用更小的密钥——比如RSA加密算法——提供相当的或更高等级的安全。ECC的另一个优势是可以定义群之间的双线性映射,基于Weil对或是Tate对;双线性映射已经在密码学中发现了大量的应用,例如基于身份的加密。其缺点是同长度密钥下加密和解密操作的实现比其他机制花费的时间长 [1] ,但由于可以使用更短的密钥达到同级的安全程度,所以同级安全程度下速度相对更快。一般认为160比特的椭圆曲线密钥提供的安全强度与1024比特RSA密钥相当。

关键总结:

设私钥、公钥分别为k、K,即K = kG,其中G为G点。

  公钥加密:

  选择随机数r,将消息M生成密文C,该密文是一个点对,即:

  C = {rG, M+rK},其中K为公钥

  私钥解密:

  M + rK - k(rG) = M + r(kG) - k(rG) = M

  其中k、K分别为私钥、公钥。

题目样式举例:

ECC脚本积累(解出最后的公钥和私钥即可):

import collections

import random

EllipticCurve = collections.namedtuple('EllipticCurve', 'name p a b g n h')

curve = EllipticCurve(

'secp256k1',

# Field characteristic.

p=int(input('p=')),

# Curve coefficients.

a=int(input('a=')),

b=int(input('b=')),

# Base point.

g=(int(input('Gx=')),

int(input('Gy='))),

# Subgroup order.

n=int(input('k=')),

# Subgroup cofactor.

h=1,

)

# Modular arithmetic ##########################################################

def inverse_mod(k, p):

"""Returns the inverse of k modulo p.

This function returns the only integer x such that (x * k) % p == 1.

k must be non-zero and p must be a prime.

"""

if k == 0:

raise ZeroDivisionError('division by zero')

if k < 0:

# k ** -1 = p - (-k) ** -1 (mod p)

return p - inverse_mod(-k, p)

# Extended Euclidean algorithm.

s, old_s = 0, 1

t, old_t = 1, 0

r, old_r = p, k

while r != 0:

quotient = old_r // r

old_r, r = r, old_r - quotient * r

old_s, s = s, old_s - quotient * s

old_t, t = t, old_t - quotient * t

gcd, x, y = old_r, old_s, old_t

assert gcd == 1

assert (k * x) % p == 1

return x % p

# Functions that work on curve points #########################################

def is_on_curve(point):

"""Returns True if the given point lies on the elliptic curve."""

if point is None:

# None represents the point at infinity.

return True

x, y = point

return (y * y - x * x * x - curve.a * x - curve.b) % curve.p == 0

def point_neg(point):

"""Returns -point."""

assert is_on_curve(point)

if point is None:

# -0 = 0

return None

x, y = point

result = (x, -y % curve.p)

assert is_on_curve(result)

return result

def point_add(point1, point2):

"""Returns the result of point1 + point2 according to the group law."""

assert is_on_curve(point1)

assert is_on_curve(point2)

if point1 is None:

# 0 + point2 = point2

return point2

if point2 is None:

# point1 + 0 = point1

return point1

x1, y1 = point1

x2, y2 = point2

if x1 == x2 and y1 != y2:

# point1 + (-point1) = 0

return None

if x1 == x2:

# This is the case point1 == point2.

m = (3 * x1 * x1 + curve.a) * inverse_mod(2 * y1, curve.p)

else:

# This is the case point1 != point2.

m = (y1 - y2) * inverse_mod(x1 - x2, curve.p)

x3 = m * m - x1 - x2

y3 = y1 + m * (x3 - x1)

result = (x3 % curve.p,

-y3 % curve.p)

assert is_on_curve(result)

return result

def scalar_mult(k, point):

"""Returns k * point computed using the double and point_add algorithm."""

assert is_on_curve(point)

if k < 0:

# k * point = -k * (-point)

return scalar_mult(-k, point_neg(point))

result = None

addend = point

while k:

if k & 1:

# Add.

result = point_add(result, addend)

# Double.

addend = point_add(addend, addend)

k >>= 1

assert is_on_curve(result)

return result

# Keypair generation and ECDHE ################################################

def make_keypair():

"""Generates a random private-public key pair."""

private_key = curve.n

public_key = scalar_mult(private_key, curve.g)

return private_key, public_key

private_key, public_key = make_keypair()

print("private key:", hex(private_key))

print("public key: (0x{:x}, 0x{:x})".format(*public_key))

CTF密码学总结(二)相关推荐

  1. CTF密码学题目初探(二)

    CTF密码学题目初探(二) 密码学总结(一) 1.换位加密 2.替换加密 密码学总结(一) 在上一篇文章里写了12种常见的编码,这一篇文章主要总结换位加密和替换加密. 1.换位加密 栅栏密码(Rail ...

  2. [转]CTF密码学——常见编解码及加解密总结

    做了一些CTF密码学的题目,阅读了很多大神的博客,现在做个总结,不全面的之后补充. 目录 编码 进制表示 ASCII码对照表 unicode编码 URL编码 Escape/Unescape Base6 ...

  3. [CTF密码学]RSA相关题目解题方法与python脚本总结(附例题)

    目录 RSA算法概述 思路一.分解n得到p,q 例题:BUUCTF:[WUSTCTF2020]babyrsa 思路二.低加密指数攻击(e很小) 例题:BUUCTF DangrousRSA 思路三.低指 ...

  4. CTF密码学-编码基础知识点总结

    CTF密码学-编码基础知识点总结 0x01 目录 常见编码: 1.ASCII编码 2.Base64/32/16编码 3.shellcode编码 4.Quoted-printable编码 5.XXenc ...

  5. Bugku CTF 密码学刷题

    Bugku CTF 密码学刷题 前言 一.抄错的字符 二./.- 三.聪明的小羊 四.ok 五.[+-<>] 六.把猪困在猪圈里 七.你喜欢下棋吗 八.小山丘的秘密 九.EN-气泡 十.你 ...

  6. 格理论与密码学(二)

    格理论与密码学(二) Babai最近向量算法 高斯格基约简算法 LLL格基约简算法 Babai最近向量算法 设 L ⊂ R n L\subset\R^n L⊂Rn是一个格, v 1 , v 2 , . ...

  7. CTF密码学总结(一)

    目录 CTF 密码学总结 题目类型总结: 简单密码类型: 复杂密码类型: 密码学脚本类总结: 单独的密文类型(优先使用ciphey工具) 多层传统加密混合: Bugku的密码学的入门题/.-:(摩斯密 ...

  8. CTF密码学·置换密码,栅栏密码,曲路密码

    CTF密码学·置换密码,栅栏密码,曲路密码 1.置换密码 列置换 周期置换 2.栅栏密码 3.曲路密码 1.置换密码 置换密码(Permutation Cipher)又叫换位密码(Transposi- ...

  9. 杭电CTF 密码学(1)

    杭电CTF 密码学(1) 1.拿到 BAABAABBAAAAAAAABABBABABBBAABABAABBABBBAABBABAABAA 显而易见的培根密码,直接拿去翻译. 传说,丘比龙是丘比特的弟弟 ...

最新文章

  1. oracle数据库结束进程后怎么重启,Oracle数据库的启动与关闭方法
  2. python定义x_Python 定义函数(示例代码)
  3. 15款提高工作效率的工具分享
  4. 针对SAP OData 模型Addresssable属性的不同处理
  5. ARP-地址解析协议(在实践中深入理解ARP协议)
  6. Confluence 6 € 欧元字符集不能正常显示
  7. 集成测试:固定装置多于自动装置
  8. linux下用grep命令根据文件内容进行关键字搜索[linux ubuntu grep] -转
  9. C/C++浮点数在内存中的存储方式《转》
  10. 190407每日一句
  11. 计算机拓展名cad,CAD用到的各种文件格式有哪些
  12. 从零开始微信小游戏(cocos creator)
  13. 有些东西还得记下来,看过了又忘了,找起来又难找 (fluxbox, ab, seige)
  14. 冬至幻灵怎么修改服务器名字,冬至幻灵如何给自己加元宝
  15. STM32单片机扩展下的IPUS SQPI PSRAM应用领域
  16. 使用Google Colab对PUBG的玩家死亡数据集进行可视化分析
  17. 快手福虎迎春季短视频涨粉活动规则[快手获取商品详情]
  18. Java实现图片格式转换
  19. JAVA中JVM的重排序详细介绍(写得很明白)
  20. Macadam自然语言处理(NLP)工具包(TextClassification, SequenceLabeling, RelationExtraction)

热门文章

  1. 手机和PC连接同一热点,捕获TCP流
  2. uniapp开发APP实现导航栏顶部搜索功能
  3. Excel Vba无法连接 远程 Mysql数据库问题的解决方法
  4. HTML(3):IE浏览器编程
  5. vue全家桶+Echarts+百度地图,搭建数据可视化系统
  6. C++用snap7库对PLC数据块进行读写
  7. #离散#ssl 1747 登山机器人问题
  8. 电话销售技巧和话术(转)
  9. MySql免安装配置教程
  10. java 打成war_JAVA语言之Springboot打成war包并在tomcat中运行的部署方法