加密代码如下
from random import randrange
text_list=' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t\n'
key=[randrange(1,97) for i in range(randrange(15,30))]
print('key = '+str(key))
def encrypt(s,k):
out=''
for i in range(len(s)):
index=text_list.index(s[i])
index*=k[i%len(k)]
index%=97
out+=text_list[index]
return out
plain=open('plain.txt','r').read() # TOEFL reading passage
cipher=encrypt(plain,key)
open('cipher.txt','w').write(cipher)
可以发现 对每个单词做了一下映射
我们需要知道秘钥的长度 解密的秘钥 手上只有密文 看起来不可读 怎么分析?
- 首先最关键的是要发现空格不会变 这样就可以猜测单词长度了
- 间隔重复秘钥 按照长度找 比如每三个长度取出来一串 最后计数 发现{gY出现的最多 猜测是the 得到秘钥对应位置的值 (解密秘钥和加密秘钥不同,长度一致)
- 找key长度 对每个{yG找到在ciphertext中的位置
[3, 61, 612, 1105, 1279, 1656, 2091]
考虑到第一个{yG出现在第一个key长度中
那么对每个数-3
得到
[0, 58, 609, 1102, 1276, 1653, 2088]
发现他们有个共同的倍数29
linux下可以输入命令 factor 58 以此类推 或者手动gcd搞
所以keylen=29
还有一个关键是第一个单词长度为2
所以可能为
In
By
At
As
如何确定
每29个算一下看出来的结果 ※※※※※
不是a-zA-Z0-9,.:-
基本就不是了 对每个我们猜的结果 都可以用这个验证
上面这个解密可以自己实现一下
就是个逆元
ab mod 97=c mod 97
已知a,c求b
b = c (a在97意义下的逆元) %97
哦对了
当你找出来较多的单词 就可以百度啦! - 题目做完发现可以用 ※※※※※处的方法来暴力破解= = 问题不大…
混乱的解密脚本
import gmpy2
import sys
from random import randrange
import re
from collections import Counter
text_list=' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t\n'
cipherText = open('cipher.txt','r').read()
print sys.argv[1]
def inv(x):
return gmpy2.invert(x,97)
def repeat():
c = Counter()
for i in range(len(cipherText)):
s = cipherText[i:i+int(sys.argv[1])]
c[s] = c[s] + 1
print sorted(c.items(),key = lambda eachItem:eachItem[1],reverse=True)
def brute():
for keylen in range(15,30):
num = 0
if len(cipherText)%keylen==0:
num = len(cipherText)/keylen
else:
num = len(cipherText)/keylen+1
L = []
for i in range(num):
start = i*keylen
end = (i+1)*keylen
s = cipherText[start:end]
L.append(s)
for start in range(keylen):
for length in range(1,keylen-start):
if length ==3 :
c = Counter()
ans = []
for mylist in L:
ans.append(mylist[start:start+length])
Max = 0
poss = ''
for a in ans:
c[a] = c[a] + 1
if c[a] > Max:
Max = c[a]
poss = a
print "_______________"
# print (keylen,start,length,sorted(c.items(),key = lambda eachItem:eachItem[1],reverse=True))
print (keylen,start,length,poss,Max)
def findonekey(s,to):
indexto=text_list.index(to)
indexs=text_list.index(s)
return inv(indexs)*indexto%97
def splitInto():
cnt = 0
fuckthistext = open('this_is_21.txt','r').read()
for i in range(len(fuckthistext)):
if i%29==0:
print "012345678901234567890123456789here is the line {0}".format(cnt)
print fuckthistext[i:i+29]
cnt += 1
splitInto()