古典密码有哪些破解方法?

2026-05-05 23:561阅读0评论SEO资源
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2062个文字,预计阅读时间需要9分钟。

古典密码有哪些破解方法?

一系列古典密码+Vigenere在线解密:[链接](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) 加密时,明文与key的每个元素对应相加。

一系列古典密码 Vigenere

在线解密: www.guballa.de/vigenere-solver
已知密钥: 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()) 单表替换

在线解密: quipqiup.com/

栅栏解密
  • 千千解密

    不会出现@,不支持批量

www.qqxiuzi.cn/bianma/zhalanmima.php

  • bugku

    支持批量解密,有些存在@

polybius

波利比奥斯方阵密码

  • 加密

    两个密文替换一个明文

    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: 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

在线解密: practicalcryptography.com/ciphers/hill-cipher/

  • 该网站使用注意事项
    1️⃣密钥输入统一为加密矩阵,不为逆矩阵 --> a11,a12,a21,a22
    2️⃣除字母外的数据均忽略,大小写不管 --> 手动补充特殊字符、数字等,大小写对应
四方密码
  • 密钥生成

    两个密钥,单词去重后,按照字母表排序,去除Q

  • 加密

    两个字母一组

    找出第一个字母在左上角矩阵的位置;
    同样道理,找第二个字母在右下角矩阵的位置;
    找右上角矩阵中,和第一个字母同行,第二个字母同列的字母;
    找左下角矩阵中,和第一个字母同列,第二个字母同行的字母;

本文共计2062个文字,预计阅读时间需要9分钟。

古典密码有哪些破解方法?

一系列古典密码+Vigenere在线解密:[链接](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) 加密时,明文与key的每个元素对应相加。

一系列古典密码 Vigenere

在线解密: www.guballa.de/vigenere-solver
已知密钥: 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()) 单表替换

在线解密: quipqiup.com/

栅栏解密
  • 千千解密

    不会出现@,不支持批量

www.qqxiuzi.cn/bianma/zhalanmima.php

  • bugku

    支持批量解密,有些存在@

polybius

波利比奥斯方阵密码

  • 加密

    两个密文替换一个明文

    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: 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

在线解密: practicalcryptography.com/ciphers/hill-cipher/

  • 该网站使用注意事项
    1️⃣密钥输入统一为加密矩阵,不为逆矩阵 --> a11,a12,a21,a22
    2️⃣除字母外的数据均忽略,大小写不管 --> 手动补充特殊字符、数字等,大小写对应
四方密码
  • 密钥生成

    两个密钥,单词去重后,按照字母表排序,去除Q

  • 加密

    两个字母一组

    找出第一个字母在左上角矩阵的位置;
    同样道理,找第二个字母在右下角矩阵的位置;
    找右上角矩阵中,和第一个字母同行,第二个字母同列的字母;
    找左下角矩阵中,和第一个字母同列,第二个字母同行的字母;