实验一:RSA公钥密码体制的实现
1.实验目的
RSA公钥密码体制的实现
2.实验工具
1)Windows 系列操作系统;
2) python 编程环境。
3. 实验方案
(说明:需要有流程图、原理等)
在 RSA 算法中,n=pq;φ( n)=(p-1)(q-1);1<e<φ(n),且 gcd(φ(n),e)=1;d*e ≡1 modφ(n)。这些参数中,公开的有 n 和 e,保密的有 p、q 和 d。 设明文分组 m,则加密算法为 c≡m^e mod n 对密文分组 c 的的解密算法为 m≡c^d mod n
4.实验步骤
(说明:具体步骤,后面的实验结果最好对应这里每步都能看到)
1、选择 p、q两个超级大的质数 ,都是1024位,显得咱们的程序货真价实。
2、令n = p * q。取 φ(n) =(p-1) * (q-1)。 计算与n互质的整数的个数。
3、取 e ∈ 1 < e < φ(n) ,( n , e )作为公钥对
4、令 ed mod φ(n) = 1,计算d,( n , d ) 作为私钥对。 计算d可以利用扩展欧几里的算法进行计算,非常简单,不超过5行代码就搞定。
5、销毁 p、q。密文 = 明文 ^ e mod n , 明文 = 密文 ^ d mod n。
具体的代码的实现:
def gcd(a, b): #求最大公因子
if b == 0:
return a
else:
return gcd(b, a % b)
def ext_gcd(a, b): #求逆元
if b % a == 0:
return 0
for i in range(2,int(b/2)):
if i * a % b == 1:
return i
return 0
def exp_mode(base, exponent, n):
bin_array = bin(exponent)[2:][::-1]
r = len(bin_array)
base_array = []
pre_base = base
base_array.append(pre_base)
for _ in range(r - 1):
next_base = (pre_base * pre_base) % n
base_array.append(next_base)
pre_base = next_base
a_w_b = __multi(base_array, bin_array)
return a_w_b % n
def __multi(array, bin_array):
result = 1
for index in range(len(array)):
a = array[index]
if not int(bin_array[index]):
continue
result *= a
return result
def gen_key(p, q):
n = p * q
fy = (p - 1) * (q - 1) # 计算与n互质的整数个数 欧拉函数
e = 3
# generate d
a = e
b = fy
x= ext_gcd(a, b)
d = x
# 返回: 公钥 私钥
return (n, e), (n, d)
##### 加密 m是被加密的信息 加密成为c
def encrypt(m, pubkey):
n = pubkey[0]
e = pubkey[1]
c = exp_mode(m, e, n)
return c
#解密 c是密文,解密为明文m
def decrypt(c, selfkey):
n = selfkey[0]
d = selfkey[1]
m = exp_mode(c, d, n)
return m
if __name__ == "__main__":
'''公钥私钥中用到的两个大质数p,q'''
p = int(input("请输入第一个大质数:"))
q = int(input("请输入第二个大质数:"))
'''生成公钥私钥'''
pubkey, selfkey = gen_key(p, q)
'''需要被加密的信息转化成数字,长度小于秘钥n的长度,如果信息长度大于n的长度,那么分段进行加密,分段解密即可。'''
m = int(input("请输入要加密的明文:"))
# m = decrypt(c, selfkey)
c = encrypt(m,pubkey)
print(c)
用两个大素数11和23,明文165测试,得到密文110 测试成功
反之输入密文110 得到明文,测试成功
实验二:DES
1.实验目的
1)熟悉分组密码加密/解密算法的基本原理,加深对所提供的部分源程序的理解。
2)分析源程序中密码算法的加密/解密和子密钥生成等典型模块的主要功能,并对源程序加上注释。
3)在已提供的部分源程序的基础上,添加源程序缺省的部分。
4)对给定的消息分组进行加密/解密运算和验证。
2.实验工具
1)Windows 系列操作系统;
2) python 编程环境。
3. 实验方案
(说明:需要有流程图、原理等)
分组密码将明文分成一组一组,在密钥的控制下,经过加密变换生产一组一组的密文。具体而言,分组密码就是将明文消息列m1,m2,···,mi,···划分成等长的消息组(m1,m2,···,mn),(mn+1,mn+2,···,m2n),···, 在密钥k1,k2,···,ki的控制下按固定的加密算法一组一组进行加密,输出一组一组密文(c1,c2,···cl),(cl+1,cl+2,···,c2l),···。
下面的实验以DES算法为例。DES算法明文分组长为64bit,加密后得到64bit密文,输入初始种子密钥为64bit,第8、16、24、32、40、48、56、64为奇偶校验位,实际的密钥长为56bit。DES加密过程由三个阶段来完成:
- 初始置换IP,用于重排明文分组的64bit数据。
- 相同结构的16轮迭代,每轮中都有置换和代换运算,第16轮变换的输出分为左、右两半,并交换次序。
- 逆初始置换IP-1(为IP的逆)后,产生64bit的密文。
4.实验步骤
(说明:具体步骤,后面的实验结果最好对应这里每步都能看到)
#include <string.h>
#include <stdio.h>
class DES{
public:
~DES() {} //析构函数
void set_key(const unsigned char *); //密钥扩展
void en_ctransform(const unsigned char *,unsigned char *); //加密变换
void de_ctransform(const unsigned char *,unsigned char *); //解密变换
private:
bool enckey[16][48];//存放加密子密钥
bool deckey[16][48];//存放解密子密钥
const static unsigned char IP_Table[64];
//初置换
const static unsigned char IPR_Table[64];
// 逆置换
const static unsigned char E_Table[48];
//E表
const static unsigned char P_Table[32];
//置换选择
const static unsigned char PC1_Table[56];
//置换选择1
const static unsigned char PC2_Table[48];
//置换选择2
const static unsigned char LOOP_Table[16];
// 密钥位移(左移次数)
const static unsigned char S_Box[8][4][16];
// S盒
};
const unsigned char DES::IP_Table[64] = {
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
};
// 初置换
const unsigned char DES::IPR_Table[64] = {
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
};
// 逆初始置换
const unsigned char DES::E_Table[48] = {
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
};
// E表
const unsigned char DES::P_Table[32] = {
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
};
// 置换选择
const unsigned char DES::PC1_Table[56] = {
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
};
//置换选择1
const unsigned char DES::PC2_Table[48] = {
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
};
//置换选择2
const unsigned char DES::LOOP_Table[16] = {
1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};
// 密钥位移(左移次数)
const unsigned char DES::S_Box[8][4][16] = {
// S1
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,
// S2
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,
// S3
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,
// S4
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,
// S5
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,
// S6
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,
// S7
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,
// S8
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
};
void chaifen(char byte,int a[64],int q){
int i;
for(i=0;i<8;i++){
a[7-i+q]=byte & 1;
byte>>=1;
//把byte右移一位的值赋值给byte
}
}
void DES::set_key( unsigned char const *yonghu_key/*用户输入的64位密钥首地址*/ ){
//密钥扩展算法
int arr[64];
int ary[56];
int i,curry=0;
for(i=0;i<8;i++){
chaifen(yonghu_key[i],arr,curry);
curry=curry+8;
}
for(i=0;i<56;i++){
ary[i]=arr[PC1_Table[i]-1];
}
for(i=0;i<16;i++){
if(i==0 || i==1 || i==8 || i==15){
int j,temp0,temp1;
temp0=ary[0];temp1=ary[28];
for(j=0;j<28;j++){
ary[j]=ary[j+1];
ary[j+28]=ary[j+29];
}
ary[27]=temp0;ary[55]=temp1;
}
else{
int j,temp0,temp1;
temp0=ary[0];temp1=ary[28];
for(j=0;j<28;j++){
ary[j]=ary[j+1];
ary[j+28]=ary[j+29];
}
ary[27]=temp0;ary[55]=temp1;
temp0=ary[0];temp1=ary[28];
for(j=0;j<28;j++){
ary[j]=ary[j+1];
ary[j+28]=ary[j+29];
}
ary[27]=temp0;ary[55]=temp1;
}
int j;
for(j=0;j<48;j++)
enckey[i][j]=(bool)ary[PC2_Table[i]-1];
}
}
void DES::en_ctransform( const unsigned char *In /*待解密的64位数据首地址*/,unsigned char *Out ){
//加密变换算法
int arr[64];
int ary[64];
int i,j,curry=0;
for(i=0;i<8;i++){
chaifen(In[i],arr,curry);
curry=curry+8;
}
for(i=0;i<64;i++){
ary[i]=arr[IP_Table[i]-1];
}
int larr[32];
int rarr[32];
for(i=0;i<32;i++){
larr[i]=ary[i];
rarr[i]=ary[i+32];
}
for(i=0;i<16;i++){
int temp[32];
for(j=0;j<32;j++){
temp[j]=larr[j];
larr[j]=rarr[j];
}
int i0,j0,q;
int e[48];
for(i0=0;i0<48;i0++)
e[i0]=rarr[E_Table[i0]-1];
int w;
for(w=0;w<48;w++){
e[w]=(e[w]+enckey[i][w])%2;
}
for(j0=0;j0<8;j0++){
int hang=e[j0*6]*2+e[j0*6+5];
int lie=e[j0*6+1]*8+e[j0*6+2]*4+e[j0*6+3]*2+e[j0*6+4];
int num=S_Box[j0][hang][lie];
for(q=0;q<4;q++){
rarr[j0*4+3-q]=num&1;
num>>=1;
}
}
int temp0[32];
for(j=0;j<32;j++){
temp0[j]=rarr[j];
}
for(j=0;j<32;j++){
rarr[j]=temp0[P_Table[j]-1];
}
for(j=0;j<32;j++){
rarr[j]=((rarr[j]+temp[j])%2);
}
}
int temp[32];
for(i=0;i<32;i++){
temp[i]=larr[i];
larr[i]=rarr[i];
rarr[i]=temp[i];
}
for(i=0;i<32;i++){
ary[i]=larr[i];
ary[i+32]=rarr[i];
}
for(i=0;i<64;i++){
arr[i]=ary[IPR_Table[i]-1];
}
for(i=0;i<8;i++){
Out[i]=arr[i*8]*128+arr[i*8+1]*64+arr[i*8+2]*32+arr[i*8+3]*16+arr[i*8+4]*8+arr[i*8+5]*4+arr[i*8+6]*2+arr[i*8+7];
}
}
void DES::de_ctransform( const unsigned char *In /*待加密的64位数据首地址*/, unsigned char *Out){
//解密变换算法
int arr[64];
int ary[64];
int i,j,curry=0;
for(i=0;i<8;i++){
chaifen(In[i],arr,curry);
curry+=8;
}
for(i=0;i<64;i++){
ary[i]=arr[IP_Table[i]-1];
}
int larr[32];
int rarr[32];
for(i=0;i<32;i++){
larr[i]=ary[i];
rarr[i]=ary[i+32];
}
for(i=0;i<16;i++){
int temp[32];
for(j=0;j<32;j++){
temp[j]=larr[j];
larr[j]=rarr[j];
}
int i0,j0,q;
int e[48];
for(i0=0;i0<48;i0++)
e[i0]=rarr[E_Table[i0]-1];
int w;
for(w=0;w<48;w++){
e[w]=(e[w]+enckey[15-i][w])%2;
}
for(j0=0;j0<8;j0++){
int hang=e[j0*6]*2+e[j0*6+5];
int lie=e[j0*6+1]*8+e[j0*6+2]*4+e[j0*6+3]*2+e[j0*6+4];
int num=S_Box[j0][hang][lie];
for(q=0;q<4;q++){
rarr[j0*4+3-q]=num&1;
num>>=1;
}
}
int temp0[32];
for(j=0;j<32;j++){
temp0[j]=rarr[j];
}
for(j=0;j<32;j++){
rarr[j]=temp0[P_Table[j]-1];
}
for(j=0;j<32;j++){
rarr[j]=((rarr[j]+temp[j])%2);
}
}
int temp[32];
for(i=0;i<32;i++){
temp[i]=larr[i];
larr[i]=rarr[i];
rarr[i]=temp[i];
}
for(i=0;i<32;i++){
ary[i]=larr[i];
ary[i+32]=rarr[i];
}
for(i=0;i<64;i++){
arr[i]=ary[IPR_Table[i]-1];
}
for(i=0;i<8;i++){
Out[i]=arr[i*8]*128+arr[i*8+1]*64+arr[i*8+2]*32+arr[i*8+3]*16+arr[i*8+4]*8+arr[i*8+5]*4+arr[i*8+6]*2+arr[i*8+7];
}
}
int main(){
unsigned int seq[8];
unsigned char key[9]; //密钥
unsigned char plain[9]; //明文
unsigned char cipher[9]; //密文
char shuruzi[17]; //键盘输入的字符
char choice=' ';
DES mydes; //类
int i,j;
int s;
while(true){
do{
printf("请选择:\n 1.加密\n 2.解密\n 3.退出\n");
scanf("\n%c",&choice);
}
while(choice != '1' && choice != '2' && choice != '3');
switch(choice){
case '1':
printf("请输入秘钥(长度=16):\n****************\n");
scanf("%s",shuruzi);
sscanf(shuruzi,"%2x%2x%2x%2x%2x%2x%2x%2x",&seq[0],&seq[1],&seq[2],&seq[3],&seq[4],&seq[5],&seq[6],&seq[7]);
for(i=0;i<8;i++)
key[i]=seq[i];
//将输入的字符一个一个存到密钥数组中
printf("\n");
printf("请输入明文(长度=16):\n****************\n");
scanf("%s",shuruzi);
printf("\n");
sscanf(shuruzi,"%2x%2x%2x%2x%2x%2x%2x%2x",&seq[0],&seq[1],&seq[2],&seq[3],&seq[4],&seq[5],&seq[6],&seq[7]);
for(j=0;j<8;j++)
plain[j]=seq[j];
//将输入的字符一个一个存到明文数组中
mydes.set_key(key);
mydes.en_ctransform(plain,cipher);
//调用加密算法函数完成加密
for(s=0;s<8;s++)
seq[s]=cipher[s];
printf("密文:\n%02x%02x%02x%02x%02x%02x%02x%02x\n",seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6],seq[7]);
//将密文数组中的字符存入缓存数组并输出
printf("\n");
break;
case '2':
printf("请输入秘钥(长度=16):\n****************\n");
scanf("%s",shuruzi);
sscanf(shuruzi,"%2x%2x%2x%2x%2x%2x%2x%2x",&seq[0],&seq[1],&seq[2],&seq[3],&seq[4],&seq[5],&seq[6],&seq[7]);
for(i=0;i<8;i++)
key[i]=seq[i];
//将输入的字符一个一个存到明文数组中
printf("\n");
printf("请输入密文(长度=16):\n****************\n");
scanf("%s",shuruzi);
printf("\n");
sscanf(shuruzi,"%2x%2x%2x%2x%2x%2x%2x%2x",&seq[0],&seq[1],&seq[2],&seq[3],&seq[4],&seq[5],&seq[6],&seq[7]);
for(j=0;j<8;j++)
cipher[j]=seq[j];
//将输入的字符一个一个存到密文数组中
mydes.set_key(key);
mydes.de_ctransform(cipher,plain);
//调用解密算法函数完成解密
for(s=0;s<8;s++)
seq[s]=plain[s];
printf("明文:\n%02x%02x%02x%02x%02x%02x%02x%02x\n",seq[0],seq[1],seq[2],seq[3],seq[4],seq[5],seq[6],seq[7]);
printf("\n");
break;
case '3':
return 0;
break;
}
}
}
实验三:维吉尼亚密码
1.实验目的
1) 编写 Vigenere 密码加密程序,在指定的目录下建立明文文件,输入任意选取的密钥, 加密后得到密文文件。
2) 编写 Vigenere 密码解密程序,在已知密钥的情况下将密文文件解密得到明文文件。
3) 给出一段密文,在不知密钥的情况下,破解该密文,恢复出明文
2.实验工具
1) Windows 系列操作系统。
2) VC6.0 编程环境
3. 实验方案
Vigenere 密码在加密/解密时,把英文字母映射为 0-25 的数字再进行计算,并按 n 个 字母一组进行变换。明文空间、密钥空间及密文空间都是长度为 n 的英文字母串的集合。 设密钥 k=(k1,k2,···, kn),明文 m=(m1,m2,···, mn),则加密算法为 Ek(m)=(c1,c2,···, cn) 其中,ci=(mi+ki)( mod 26), i=1,2,···, n。 对密文 c=(c1,c2,···, cn),解密算法为 Dk(c)=(m1,m2,···, mn) 其中,mi=(ci-ki)( mod 26), i=1,2,···, n
4.实验步骤
(说明:具体步骤,后面的实验结果最好对应这里每步都能看到)
1) Vigenere 密码加密程序步骤
- 读明文文件
- 通过加密公式得出密文
- 写入密文文件
具体代码如下:
clear_passwords = open('C:/Users/qqq/Desktop/clear.txt').read() #读文件
clear_password=list(clear_passwords)
secret_key=input("请输入密钥:")
secret_key=[int(x) for x in secret_key.split(" ")]
key_lengths=len(secret_key)
clear_lengths = len(clear_password)
ciphertext=[]
for i in range (clear_lengths):
ciphertext.append(0)
for i in range(clear_lengths):
k = i % key_lengths
if ord(clear_password[i]) > 96 :
ciphertext[i] = chr(((ord(clear_password[i]) - 97 + secret_key[k]) % 26) + 97) #核心算法
else:
ciphertext[i] = chr(((ord(clear_password[i]) - 65 + secret_key[k]) % 26) + 65)
file = open('C:/Users/qqq/Desktop/key.txt','w')
file.write(" ".join(str(i)for i in ciphertext)) #写文件
file.close()
print("Encrypt successful")
2) 已知密钥情况下解密
- 读密文文件
- 通过解密公式得出密文
- 写入明文文件
具体代码如下:
ciphertext = open('C:/Users/qqq/Desktop/key.txt').read() #读文件
ciphertext_list=list(ciphertext)
secret_key=input("请输入密钥:")
secret_key=[int(x) for x in secret_key.split(" ")]
key_lengths=len(secret_key)
ciphertext_lengths = len(ciphertext_list)
clearpassword=[]
for i in range (ciphertext_lengths):
clearpassword.append(0)
for i in range(ciphertext_lengths):
k = i % key_lengths
if ord(ciphertext_list[i]) > 96 :
clearpassword[i] = chr(((ord(ciphertext_list[i]) - 97 + 26 - secret_key[k]) % 26) + 97) #核心算法
else:
clearpassword[i] = chr(((ord(ciphertext_list[i]) - 65 + 26 - secret_key[k]) % 26) + 65)
for i in range(ciphertext_lengths):
print(clearpassword[i])
file = open('C:/Users/qqq/Desktop/clear.txt','w') #写文件
file.write(" ".join(str(i)for i in clearpassword))
file.close()
3) 未知密钥情况下,找到密钥,破解密文恢复明文
import math
def c_alpha(cipher): # 去掉非字母后的密文
cipher_alpha = ''
for i in range(len(cipher)):
if (cipher[i].isalpha()):
cipher_alpha += cipher[i]
return cipher_alpha
# 计算cipher的重合指数
def count_CI(cipher):
N = [0.0 for i in range(26)]
cipher = c_alpha(cipher)
L = len(cipher)
if cipher == '':
return 0
else:
for i in range(L): #计算所有字母的频数,存在数组N当中
if (cipher[i].islower()):
N[ord(cipher[i]) - ord('a')] += 1
else:
N[ord(cipher[i]) - ord('A')] += 1
CI_1 = 0
for i in range(26):
CI_1 += ((N[i] / L) * ((N[i]-1) / (L-1)))
return CI_1
# 计算秘钥长度为 key_len 的重合指数
def count_key_len_CI(cipher,key_len):
un_cip = ['' for i in range(key_len)] # un_cip 是分组
aver_CI = 0.0
count = 0
for i in range(len(cipher)):
z = i % key_len
un_cip[z] += cipher[i]
for i in range(key_len):
un_cip[i]= count_CI(un_cip[i])
aver_CI += un_cip[i]
aver_CI = aver_CI/len(un_cip)
return aver_CI
## 找出\秘钥长度
def pre_2(cipher):
M = [(1,count_CI(cipher))]+[(0,0.0) for i in range(49)]
for i in range(2,50):
M[i] = (i,abs(0.065 - count_key_len_CI(cipher,i))) #abs返回数字的绝对值
M = sorted(M,key = lambda x:x[1]) #按照数组第二个元素排序 (因为列表内部是一个元组所以需要用到 key=lambda隐函数,x指的是列表内的元组,x[1]指的是按照第一个数据排序,从0 开始
m = []
for x in range(1,3):
for i ,j in M:
m.append(i)
num = (math.gcd(m[1],m[2]))
return num
# 猜测单个秘钥得到的重合指数
def count_CI2(cipher,n): # n 代表我们猜测的秘钥,也即偏移量
N = [0.0 for i in range(26)]
cipher = c_alpha(cipher)
L = len(cipher)
F = [
0.0651738, 0.0124248, 0.0217339,
0.0349835, 0.1041442, 0.0197881,
0.0158610, 0.0492888, 0.0558094,
0.0009033, 0.0050529, 0.0331490,
0.0202124, 0.0564513, 0.0596302,
0.0137645, 0.0008606, 0.0497563,
0.0515760, 0.0729357, 0.0225134,
0.0082903, 0.0171272, 0.0013692,
0.0145984, 0.0007836
] # 英文字符频率。
for i in range(L): #计算所有字母的频数,存在数组N当中
if (cipher[i].islower()):
N[(ord(cipher[i]) - ord('a') - n)%26] += 1
else:
N[(ord(cipher[i]) - ord('A') - n)%26] += 1
CI_2 = 0
for i in range(26):
CI_2 += ((N[i] / L) * F[i])
return CI_2
def one_key(cipher,key_len):
un_cip = ['' for i in range(key_len)]
cipher_alpha = c_alpha(cipher)
for i in range(len(cipher_alpha)): # 完成分组工作
z = i % key_len
un_cip[z] += cipher_alpha[i]
key_list = []
for i in range(key_len):
key_list.extend(pre_key(un_cip[i])) ####这里应该将5个分组的秘钥猜测全部打印出来
return key_list
找出最可能的单个秘钥
def pre_key(cipher):
M = [(0,0.0) for i in range(26)]
for i in range(26):
M[i] = (i,abs(0.065 - count_CI2(cipher,i)))
M = sorted(M,key = lambda x:x[1]) #按照数组第二个元素排序
m = []
s = []
for x in range(1, 5):
for i, j in M:
m.append(i)
s.append(m[0])
return s
def decode(cipher): #解密
num = pre_2(cipher)
key_len = num
key = one_key(cipher, key_len)
cipher_list = list(cipher)
cipher_len = len(cipher_list)
plaintext = ['0'] * cipher_len
for i in range(cipher_len):
k = i % key_len
if ord(cipher_list[i]) > 96:
plaintext[i] = chr(((ord(cipher_list[i]) - 97 + 26 - key[k]) % 26) + 97)
else:
plaintext[i] = chr(((ord(cipher_list[i]) - 65 + 26 - key[k]) % 26) + 65)
for i in range(cipher_len):
print(plaintext[i], end='')
cipher ='Vvhqwvvrhmusgjgthkihtssejchlsfcbgvwcrlryqtfsvgahwkcuhwauglqhnslrljshbltspisprdxljsvee Ghlqwkasskuwepwqtwvspgoelkcqyfnsvwljsniqkgnrgybwlwgoviokhkazkqkxzgyhcecmeiujoqkwf wvefqhkijrclrlkbienqfrjljsdhgrhlsfqtwlauqrhwdmwlgusgikkflryvcwvspgpmlkassjvoqxeggveyggzm ljcxxljsvpaivwikvrdrygfrjljslveggveyggeiapuuisfpbtgnwwmuczrvtwglrwugumnczvile'
cipher = c_alpha(cipher)
print("秘钥长度为:")
print(pre_2(cipher))
print()
decode(cipher)