密码学—Kasiski测试法Python程序
Kasiski
Kasiski是辅助破解Vigenere的前提工作,Kasiski是猜测加密者使用Vigenere密码体系的密钥的长度,Kasiski只是猜测长度而已,所以说是辅助破解Vigenere
若密文中出现两个相同的密文段(密文段的长度m>2),则它们对应的明文(及密钥)将以很大的概率相同(后文有一个该概率的计算)。
针对多表密码,首要的是得到秘钥字的长度,进一步判断密钥字的长度是否为:m=gcd(d1,d2,…,di) d:为密文片段直接的距离。
我们可以猜测秘钥字的长度m可能是d1,d2,…,di 最大公因子。
这就是Kasiski测试法。
——出自我的密码学老师PPT原文
我的理解
Kasiski的主要功劳即使帮助破解Vigenere密码找到密钥长度,具体如何找的- 找相同的密文片段(片段当然是两个以上才算,这个具体找多少个自己写算法的时候自己确认,或者设置一个参数手动输入)
- 记录相同片段出现的位置(记录的是片段第一个字母出现的位置作为整个片段出现的位置)
- 当然考虑到的肯定就是出现次数最多的了(这个算法实现还是比较费脑子)
- 当然在找的过程中还要记录下每个出现的位置,然后用这个位置求最大公因数,那么这个最大公因数就是最有可能的密钥长度
为什么最大公因数就是有可能是密钥长度
因为在Vigenere加密中,使用的是多表加密,每一个表都是凯撒密码,使用的都是同一个字母加密,不同表只是在密钥串中的不同字母加密而已。所以假如说有相同的片段出现,就可以推断出相同密钥字母出现的周期,然后周期就是这个密钥的长度,因为Vigenere就是周期性的使用密钥对明文进行加密,下面我密码学老师的PPT对这个说法有一个很好的解释,一眼就看出是周期性的时候密钥加密。
这也很明显的点名了为啥Vigenere中要分组加密,因为分好组之后每一组第一个字母使用的都是同一个密钥加密,所以也就所谓的单表对应凯撒密码加密,Vigenere使用多个凯撒加密表。
找到出现相同片段
- 算法实现
- 困难:如何找到出现次数最多的片段(字母串)?
Python真是帮了很大的一个忙了,因为有find内置函数省了我很多工作,因为只要用好下标就能够找到所有出现过的单词 - 我的想法
首先是传入一个字符串,然后a参数代表找的最短连续出现的片段长度,b代表最长的出现片段长度。
为什么要这么做呢:因为如果不设置一个参数人为的介入这个程序会无限制的找下去,直到整个字符串都会find一遍,这样式毫无意义的,还很浪费性能与时间。
由于find内置函数返回的值就是要找的片段第一个字母出现的下标,因此我甚至省去写如何找下标的步骤(在此特地感谢Python开发者们)- 找到下标之后我将其存进一个字典,字典的键是字符片段,值就是该片段在文本中出现的位置的各个下标,然后如果要记录出现此处就计算该列表的长度就是出现的次数了。
- 这里我配合find内置函数采用了切片的方式进行找同片段,从给出的a参数最短的片段作为开头,那么在文本中开头0~a长度的就不用找,以此为第一个单词,然后用这个单词在后面find如果find到了表示OK找到的,存find函数返回的出现的下标,全部找完之后,使用a长度跨越a个步数,意思是这个片段已经全部找到了,往后的就是该片段之后的要重复上述操作。
- 这里我当时想了一个我自认为很妙的方法:我遍历的是传入的ab参数,因为是人为介入的,所以我应该是从a长度的开始找,这里我的目的是给出一个步长变量step,为的就是让第二层遍历在找完某个step长的单词片段之后跨越step长度继续往后找,然后这个step还给当找到一个之后继续往后找的时候就从找到的片段的下标再加一个step然后就可以将其继续往后找,这里我认为是减少了再次遍历的次数,我个人是觉得优化了一下
- index = mess.find(mess[i:i + step], index + 1)解读
这个一个就是我认为写的很好的一点,mess是全部文本,首先mess[i:i+step]是表示当前要找的片段,由于是while是确保了后面会有相同片段的,然后index+1代表找第二次的时候,index已经记录第一次找到的下标,这里第二次找就是从已经找到的片段的后面找起。
- 困难:如何找到出现次数最多的片段(字母串)?
def findSameWords(self, mess, a, b):
# 找出现次数最多的字符,返回他所有下标和字符本身
dit_wordCount = {} # 保存不同长度的字符出现次数最多的,键:'字符',值:[出现的次数, [每次出现的下标]]
for step in range(a, b + 1):
for i in range(len(mess) - step):
# 每一次进入if都是全局搜索,如果之前判断过存放在字典中没有该字符串就继续全局文本中去find
if mess[i:i + step] not in dit_wordCount.keys():
'''
意思是mess从step+i开始找有没有和mess[i:i+step]该字符串相同的字符串
同时保证了i是递增,并且mess截串是从一开始的下标0开始找,
整个mess文本里面又是从i+step开始往后findmess截串
↓
'''
#这里是先试探一下是否存在,存在就做初始化操作,否则-1的话就不用继续进入
index = mess.find(mess[i:i + step], i + step)
if index != -1: dit_wordCount[mess[i:i + step]] = [1, [i + 1]] # 当该字符不止出现一次的时候就初始化该字符的字典键
while index != -1: # 找到了
dit_wordCount[mess[i:i + step]][0] += 1
dit_wordCount[mess[i:i + step]][1].append(index + 1)
index = mess.find(mess[i:i + step], index + 1) # 继续找
return dit_wordCount
找到相同长度不同片段中出现次数最多的片段
- 解释:这里使用的是上面存的字典,然后进行这下面的操作
在这里说的是找到相同长度片段中出现次数最多的,意思就是在一篇文本中相同片段的很多,然后片段长度相同的也很多,这里要找的就是从这些不同片段但是长度相同的片段中找到频率最多的,这里就相当于打擂台操作了。
然后由于字典中已经完成了大部分工作,在这一步中只需要将其遍历然后将所需的数据放进另一个字典中即可。
在本步骤中要找的数据:[(片段, [出现次数,[每次出现的下标]]) , … ]
- 第一步是先统计每个片段出现频率并找出最大的那个(这里会出现很多,因此需要有之后的第二步)
代码如下:满满的注释,感谢自己。
def caltFrequence(self, dit_wordCount):
selectWord = [] # 保存挑选出来符合条件的单词
last_len = 0 # 字典中字符串长度相同中最后一个 ,用于保存每一次循环中字符长度,利用字符长度改变来判断是否进行完成一轮该字符长度的筛选操作
maxcount = 0 # 该字符长度的字典里面出现最大次数
temp = None
for item in dit_wordCount.items(): # 感谢开发者们让字典从Python3.6版本开始变得可以有顺序了,节省了我写代码再次区分字符串长度不同的
if len(item[0]) > last_len and temp != None and self.sb_MaxKeyCurrtime.value() <= temp[1][0]:
# 判断是否在该字符长度内出现次数最多,比如字符串长度为3中,出现次数最多的为CHR那么该字符就保存下来,其他就丢掉
# len(item[0]) > last_len 假如字符串长度发生变化就表示进入了下一个不同的字符串长度的域,需要把上一个temp存下来的数据加进去
# temp != None判断是否是第一次进入
# self.sb_MaxKeyCurrtime.value() <= temp[1][0]控制至少出现的次数
selectWord.append(temp)
if item[1][0] > maxcount and len(item[0]) == last_len or len(item[0]) > last_len:
# 假如该item中出现次数比之前相同字符的还要多,就存入该字符的数据 。
# len(item[0]) > last_len控制是否是字符长度有所改变,或者是否是第一次进入
last_len = len(item[0])
maxcount = item[1][0]
temp = item
# print(selectWord)
return selectWord
# 每一项的结构就是: [('CHR', [5, [1, 166, 236, 276, 286] ] ),......]
# 字符 出现次数 对应字符在密文中出现的下标位置
- 第二步
我是通过一个类中一个变量接收的猜测的最长长度 - 可能会有疑惑:刚刚不是找最短出现的次数吗,现在怎么又是最长了。
当我们在最短中往后找的时候,可能会出现很长的出现片段,由于我们找的不仅仅是一个长度的片段的,我还找了其他不同长度的片段,那么就可能会导致找到一个很长的,但同时又满足最短出现的次数,然后又是在该片段中相同长度的不同片段中出现的次数最多,那么就是属于符合条件的了。
那么在这一步中就是人为的介入,将认为没有必要的比如:很长一段片段,然后出现次数刚好满足最短的出现次数,并且你觉得我们的加密方没有闲到用这么长的密钥加密的时候你就可以切除掉这个隐患。
代码如下:
def getMaxNumList(self, selectData): # 每一项的结构就是: [('CHR', [5, [1, 166, 236, 276, 286] ] ),......]
# num_list = []
keymaxlen = self.sb_choiceMaxKeylen.value() # 允许猜测密钥的最长长度,也就是最大公因数
ch_maxnum = []
for item in selectData:
# 拆包,提取出计算最大公因数的距离数字
ch, date = item
count, index_list = date
# if self.sb_MaxKeyCurrtime.value() > count-1: continue
print(index_list)
distance_list = []
for j in range(len(index_list) - 1):
distance_list.append(index_list[j + 1] - index_list[0])
num = distance_list[0]
for j in range(1, len(distance_list)):
num = math.gcd(num, distance_list[j])
# num_list.append(num)
if num > keymaxlen:
selectData.remove(item)
else:
ch_maxnum.append([ch, num])
return ch_maxnum
到这一步Kasiski测试法基本就结束了,测试法顾名思义测试的,还不是很有力的证据,因此在这里使用的定义仅仅是找到出现次数最多的相同片段然后将其位置下标做一个gcd求最大公因数即猜测为密钥长度(如果是很普通的明文与密钥加密的Vigenere一般到这一步基本可以确认长度了),如果是一篇很乱的,基本没有出现重复的或者很短一篇文章这个测试法就很局限了,很容易就失效的一个方法,而且出现的频次相同但是计算出来的gcd不同更难搞,因为密钥长度这时候就有两种方案了
如果说有两种方案的密钥猜测出来,这时候就需要另一个方法了,那就是计算重合指数(这个重合指数靠的纯纯是已知的一般文章中的字母概率进行统计,但是对于一般的但是有两种密钥方案的就可以很好的区分出到底哪一个更接近真实的密钥长度。)
所以Kasiski测试法测试出来的长度是否真的是密钥长度还需要重合指数来进一步验证
密码学—Kasiski测试法Python程序的更多相关文章
- 运行python程序
1 在windows下运行python程序 1)从DOS命令行运行python脚本 用python解释器来执行python脚本,在windows下面python解释器是python.exe,我的pyt ...
- 【python之路2】CMD中执行python程序中文显示乱码
在IDLE中执行下面代码,中文显示正常: # -*- coding:utf-8 -*- st=raw_input("请输入内容")print st 但在CMD中执行e:\hello ...
- Python程序高效地调试
现在我在debug python程序就只是简单在有可能错误的地方print出来看一下,不知道python有没像c++的一些IDE一样有单步调试这类的工具?或者说各位python大神一般是怎么debug ...
- python学习笔记-python程序运行
小白初学python,写下自己的一些想法.大神请忽略. 安装python编辑器,并配置环境(见http://www.cnblogs.com/lynn-li/p/5885001.html中 python ...
- python程序一直在后台运行的解决办法
刚写了个python程序,要一直在后台运行,即使断开ssh进程也在,下面是解决办法: 假如Python程序为test.py 编写shell脚本start.sh #!/bin/bash python t ...
- 第一个python程序
一个python程序的两种执行方式: 1.第一种方式是通过python解释器: cmd->python->进入python解释器->编写python代码->回车. 2.第二种方 ...
- Python程序的首行
>问题 >>在一些python程序中的首行往往能够看见下面这两行语句中的一句 >>>#!/usr/bin/Python >>>#!/usr/bin ...
- Python程序员的进化史
各种程序员所写的阶乘算法代码 # -*- coding: utf-8 -*- #新手程序员(递归) def factorial(x): if x == 0: return 1 else: return ...
- Python程序的常见错误(收集篇)
关于Python Python是一门解释性的,面向对象的,并具有动态语义的高级编程语言.它高级的内置数据结构,结合其动态类型和动态绑定的特性,使得它在快速应用程序开发(Rapid Applicatio ...
- 完成一段简单的Python程序,使用函数实现用来判断输入数是偶数还是奇数
#!/bin/usr/env python#coding=utf-8'''完成一段简单的Python程序,使用函数实现用来判断偶数和奇数'''def number_deal(a): if a%2==0 ...
随机推荐
- 如何在现实场景中随心放置AR虚拟对象?
随着AR的发展和电子设备的普及,人们在生活中使用AR技术的门槛降低,比如对于不方便测量的物体使用AR测量,方便又准确:遇到陌生的路段使用AR导航,清楚又便捷:网购时拿不准的物品使用AR购物,体验更逼真 ...
- 试用阿里云GPU服务器进行深度学习模型训练
试用阿里云GPU服务器进行深度学习模型训练 最近在用PyTorch时发现在本地训练模型速度一言难尽,然后发现阿里云可以白嫖gpu服务器,只要没有申请过PAI-DSW资源的新老用户都可以申请5000CU ...
- 顺通家用电器生产工厂ERP管理系统
顺通家用电器生产工厂ERP管理系统是一款面向中小制造企业,以智能制造与精益管理为核心的一体化管理软件,符合行业特性的管理流程,与经营特征,形成行业化管理应用软件,为企业提供各方面信息化的管理应用与支持 ...
- Java工具篇之Disruptor高性能队列
简介: disruptor适用于多个线程之间的消息队列,`作用与ArrayBlockingQueue有相似之处`,但是disruptor从功能.性能都远好于ArrayBlockingQueue,当多个 ...
- 真正的HTAP对用户和开发者意味着什么?
简介: Gartner 2016 年首次提出 HTAP(Hybrid Transaction / Analytical Processing,混合事务分析处理)并给出明确的定义:即同时支持 OLTP ...
- Dubbo 3.0 前瞻系列 | 2020双11,Dubbo3.0 在考拉的超大规模实践
很多开发者一直以来好奇:阿里自己有没有在用Dubbo,会不会用Dubbo?在刚刚结束的双11,我们了解到阿里云今年提出了"三位一体"的理念,即将"自研技术".& ...
- 快手基于RocketMQ的在线消息系统建设实践
简介: 快手需要建设一个主要面向在线业务的消息系统作为 Kafka 的补充,低延迟.高并发.高可用.高可靠的分布式消息中间件 RocketMQ 正是我们所需的. 作者:黄理 黄理,10多年软件开发和架 ...
- 实时 OLAP, 从 0 到 1
简介: BTC.com 团队在实时 OLAP 方面的技术演进过程及生产优化实践. 作者|高正炎 本文主要介绍 BTC.com 团队在实时 OLAP 方面的技术演进过程及生产优化实践,内容如下: 业务背 ...
- DevOps 能力提升模型
简介: DevOps 能力反映的是技术研发响应业务变化的能力.随着组织规模的增加和业务复杂性增长,DevOps 能力会变得越来越重要.持续提升 DevOps 的能力成为技术研发的共同挑战. 编者按:本 ...
- 2018-2-13-win10-uwp-修改CalendarDatePicker图标颜色
title author date CreateTime categories win10 uwp 修改CalendarDatePicker图标颜色 lindexi 2018-2-13 17:23:3 ...