在线解密: https://www.guballa.de/vigenere-solver
已知密钥: http://www.atoolbox.net/Tool.php?Id=856
周期性的移位密码
以 key = cipher 为例 a:0,b:1
key = (2,8,15,7,4,17)
加密时,明文6个一组,对应移位
解释时,反向移位
重合指数在某个密文中随机无放回地抽取其中的两位,这两位字母相同的概率
1️⃣利用重合指数可以计算密钥的长度
2️⃣利用在某一取值下的重合指数可以计算密钥
payload [XNUCA2018]baby_crypto为例
from gmpy2 import *
best_index=0.065
sum=0
dic_index={'a': 0.08167,'b': 0.01492,'c': 0.02782,'d':0.04253,'e': 0.12702,'f':0.02228,'g': 0.02015,'h':0.06094,'i':0.06966,'j':0.00153,'k':0.00772,'l':0.04025,'m':0.02406,'n':0.06749,'o':0.07507,'p':0.01929,'q':0.00095,'r':0.05987,'s':0.06327,'t':0.09056,'u':0.02758,'v':0.00978,'w':0.02360,'x':0.00150,'y':0.01974,'z':0.00074}
#计算重合指数
def index_of_coincidence(s):
'''
计算字符串的重合指数(所有字母出现频率的平方和)
:param s: 给定字符串
:return: 重合指数
'''
alpha='abcdefghijklmnopqrstuvwxyz'#给定字母表
freq={}#统计字母频率(frequency)
for i in alpha:
freq[i]=0
#先全部初始化为0
for i in s:
freq[i]=freq[i]+1
#统计频率
index=0
for i in alpha:
index = index + (freq[i] * (freq[i] - 1)) / (len(s) * (len(s) - 1))
return index
# 在某一取值下的重合指数
def index_of_coincidence_m(s):
'''
计算明文s中的各字母的频率与英文字母中的频率的吻合程度.
:param s:明文s
:return:吻合程度
'''
alpha = 'abcdefghijklmnopqrstuvwxyz' # 给定字母表
freq = {} # 统计字母频率(frequency)
for i in alpha:
freq[i] = 0
# 先全部初始化为0
for i in s:
freq[i] = freq[i] + 1
# 统计频率
index = 0
for i in alpha:
index = index + freq[i] / len(s) * dic_index[i]
return index
def get_cycle(c):
'''
求出最符合统计学的m,n的最小公共周期,方法为通过爆破足够大的周期样本,观察成倍出现的周期.
计算方法为解出每一个子密文段的重合指数和然后求平均值 再与最佳重合指数相减 误差在0.01以内.
:param c: 密文
:return: 公共周期列表
'''
cycle=[]
for i in range(1,100):
average_index=0#平均重合指数初始化为0
for j in range(i):
s = ''.join(c[j+i*x] for x in range(0,len(c)//i))
index=index_of_coincidence(s)
average_index+=index
average_index=average_index/i-best_index
if abs(average_index)<0.01:
cycle.append(i)
return cycle
#修改密钥数量,加密方式
def decrypt(c,i,j):
'''
通过i,j解出与之相对应的密文段
:param c: 密文段
:param i:与明文相乘的key
:param j: 位移j(维吉尼亚密码)
:return: 明文段
'''
alpha = 'abcdefghijklmnopqrstuvwxyz'
m=''
for x in c:
m += alpha[((alpha.index(x)-j) * invert(i,26))%26]
return m
#修改此处 decrypt 传参
def get_key(c):
'''
得到某一密文段的单个字符key i j
方法为暴力枚举所有的可能性,找到最符合统计学规律的 i,j 即该密文段的重合指数与最佳重合指数误差小于0.01
:param c: 密文段
:return: i,j
'''
for i in range(26):
if (gcd(i,26)!=1):#i对26的逆元不只一个,造成明文不唯一,因此不符合条件.
continue
for j in range(26):
m=decrypt(c,i,j)
index=index_of_coincidence_m(m)
if abs(index-0.065)<0.01:
return (i,j)
# 得到密钥
def get_all_key(s,cycle):
'''
得到一个周期内的所有的密文段的key
:param s: 原密文
:param cycle: 周期
:return: 无
'''
for i in range(cycle):
temps=''.join([s[i+x*cycle] for x in range(0,len(s)//cycle)])
print(get_key(temps))
'''
c 中特殊字符,换行符去掉,仅为一行字符串文本
'''
c=open('../file/encrypted_message','r').read()
cycle=get_cycle(c)
print(cycle) #[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]
cycle_select = 6
get_all_key(c,cycle_select)
曼彻斯特密码
manchester
01
--->1
10
--->0
标准曼彻斯特编码
01
--->0
10
--->1
差分曼彻斯特编码
0:有跳变
1:无跳变
跳变: 0->1 或者 1->0
是否逆序
[::-1]
payload
def manchester(cipher):
'''
曼彻斯特编码
//8位逆序
'''
tmp=''
for i in range(len(cipher)):
a=bin(eval('0x'+cipher[i]))[2:].zfill(4)
tmp=tmp+a[1]+a[3]
# print(tmp)
plain=[hex(int(tmp[i:i+8][::-1],2))[2:] for i in range(0,len(tmp),8)]
print(''.join(plain).upper())
单表替换
在线解密: https://quipqiup.com/
-
千千解密
不会出现@,不支持批量
https://www.qqxiuzi.cn/bianma/zhalanmima.php
-
bugku
支持批量解密,有些存在@
波利比奥斯方阵密码
-
加密
两个密文替换一个明文
i/j
占一个格子
1-5
可用随机5个字母代替
payload
from itertools import permutations
def polybius(alphabet,cipher):
'''
aphabet:5个字母/数字
cipher:密文
'''
keypossible = []
numlist = []
for i in permutations(alphabet,5):
keypossible.append(''.join(i))
for i in keypossible:
t = ""
for j in cipher:
t+=str(i.index(j)+1)
numlist.append(t)
for i in numlist:
r = ""
r2 = ""
flag = 0
for j in range(0,len(i),2):
v = (int(i[j])-1)*5+int(i[j+1])-1+ord('a') #采用小写,根据情况进行修改
if(chr(v)=='i'):
r+='i' #只加i
r2+='j' #只加j
flag = 1
continue
if(v>ord('i')):
v+=1
r+=chr(v)
r2+=chr(v)
if(flag):
print(r,r2)
else:
print(r)
playfair
playfair Cipher: http://rumkin.com/tools/cipher/playfair.php
双字母单表替换
以key = playfair 为例
-
根据key生成5x5的矩阵,i/j 为一个元素,key去重后写在前面,其余按顺序摆在后面
p l a y f i/j r b c d e g h k m n o q s t u v w x z -
明文两个字母一组,相同字母插入事先约定的字母 例如 x,不足偶数,填充事先约定的字母
-
p1,p2
同行,各自取右边
同列,各自取下边
不同行不同列,各自取围成的矩阵对角
-
解密为加密的逆过程
替换密码
只要两个不同的属性,代表0和1
#example
..-.-.-.--.......--..-...-..-...--.-.-....-..-..--.-.-..-.-..----
aababababbaaaaaaabbaabaaabaabaaabbababaaaabaabaabbababaababaabbbb
希尔密码
\[C_{n*1}\ =\ K_{n*n}*M_{n*1}\\
M_{n*1}\ =\ K^{'}_{n*n}*C_{n*1}
\]payload
#暴力求解 n = 2 的密钥矩阵
def hill_n_2(m,c):
m=m.lower()
c=c.lower()
m_data=[]
c_data=[]
for i in m:
m_data.append(ord(i) - ord('a'))
for i in c:
c_data.append(ord(i) - ord('a'))
for a in range(26):
for b in range(26):
if(((a*m_data[0]+b*m_data[1])%26==c_data[0]) and (a*m_data[2]+b*m_data[3])%26==c_data[2]):
for c in range(26):
for d in range(26):
if (((c * m_data[0] + d * m_data[1]) % 26 == c_data[1]) and ((c * m_data[2] + d * m_data[3]) % 26 == c_data[3])):
print(a,b,c,d)
return a,b,c,d
在线解密: http://practicalcryptography.com/ciphers/hill-cipher/
- 该网站使用注意事项
1️⃣密钥输入统一为加密矩阵,不为逆矩阵 -->a11,a12,a21,a22
2️⃣除字母外的数据均忽略,大小写不管 -->手动补充特殊字符、数字等,大小写对应
-
密钥生成
两个密钥,单词去重后,按照字母表排序,去除Q
-
加密
两个字母一组
找出第一个字母在左上角矩阵的位置;
同样道理,找第二个字母在右下角矩阵的位置;
找右上角矩阵中,和第一个字母同行,第二个字母同列的字母;
找左下角矩阵中,和第一个字母同列,第二个字母同行的字母;