目录
一、实验目的
二、实验内容
三、实验过程
1.概要设计
(1)随机全排列生成程序
(2)程序逻辑图
2.详细设计
(1)密钥字法
(2)洗牌法
(3)公式法
(4)自设计随机16全排列
(5)生成密码本(unsigned char *KeyGen)
(6)源代码
3.测试结果
(1)替换密码
(2)移位密码
4.遇到问题
四、实验体会
五、思考题
密码学实验一、二
随机全排列生成程序极其应用开发
两种基本古典密码设计与实现
一、实验目的
该实验为验证性实验。
通过本实验,使学生对于两种基本的古典密码编码方法(“代替”与“移位”)产生深刻的感性认识,体验清楚二者之间的本质差异,为理解和掌握现代密码的相应知识打下良好基础。
二、实验内容
1. 设计一个周期3的多表代替密码并予以实现,要求:第1个表由密钥字法产生(密钥字自拟),第2个表由洗牌法产生(注意,字母a~z与数字0~25对应,洗牌法即相当于实验一的方法1(n=25)),第三个表由公式法产生(数学公式自拟,注意它须是Z26上的一个一一变换)。
2.设计一个周期5的16-置换移位密码并予以实现,要求:5个16-置换至少有一个是由实验一(n=15)提供的两个方法以外、自行设计的其它方法产生。
三、实验过程
1.概要设计
说明本程序中用到的所有数据结构的定义、主程序的流程以及程序模块之间的层次(调用)关系。可用流程图等图形化工具描述,并辅以对各模块功能的必要说明。
(1)随机全排列生成程序
方法1:读取一个随机文件中n+1字节数据存入d,对0~n的自然排列,从i=n开始,计算j=(d[i-1]+d[i])%i ,并交换P[i]与P[j]的值。
程序设计:
unsigned char *full_array1(int n) { int i,j; char filename[20]; FILE *fp; static unsigned char d[256],P[256],temp; start: printf("\n 请输入随机数据采样文件名:\n"); scanf("%s",filename); if( (fp=fopen(filename,"rb"))==NULL ) { printf("没有找到文件:%s\n",filename); goto start; } fread(d,n+1,1,fp); fclose(fp); for(i=0;i<=n;i++) { P[i] = i ; //形成自然排列 } for(i=n;i>0;i--) { j=(d[i-1]+d[i])%i ; temp = P[i] ; P[i] = P[j]; P[j] = temp; //交换 } return(P); }
方法2:随机函数生成一串,依次mod n,并入排列,并将重复的删去,直到生成0~n的随机全排列。
程序设计:
unsigned char *full_array2(int n) { int m, i, j, k, l=0, flag; static unsigned char P[256]; start: printf("\n请输入不小于%d的所用随机数个数:\n", n+1); scanf("%d",&m); if(m<=n) { printf("\n输入数%d比%d小,须重新输入!\n", m, n+1); goto start; } srand((unsigned)time(NULL)); for(i=0;i<m;i++) { P[l++]=(unsigned char)(rand()%(n+1)); for(j=0;j<l-1;j++) { if(P[j]==P[l-1]) { l--; break; } } } k=l; for(i=0;i<=n;i++) { flag=0; for(j=0;j<k;j++) { if(P[j]==i) { flag=l; break; } } if(!flag) { P[l]=i; l++; } } return (P); }
(2)程序逻辑图
主函数(题目一):
(题目二相似)
KeyGen_s函数(生成密码本):
2.详细设计
(1)密钥字法
原理:首先选择一个便于记忆的字母串作为密钥字,然后删去密钥字中重复字母,接下来用余下字母顺序添加至密钥之后,形成全新26字母排序。
举例:以密钥为hello为例,下图为该密钥生成密码本。
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
h |
e |
l |
o |
a |
b |
c |
d |
f |
g |
i |
j |
k |
m |
n |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
以密钥为abcabc为例,下图为该密钥生成密码本。
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
程序设计:
printf("\n请输入密钥字:\n"); gets(KeyWords); strcat(KeyWords,"abcdefghijklmnopqrstuvwxyz"); k=0; l=strlen(KeyWords); ChoiceWords[k]=tolower(KeyWords[0]); for(i=1;i<l;i++) { if(letter_to_digit(KeyWords[i])==-1) { continue; } ChoiceWords[++k]=tolower(KeyWords[i]); for(j=0;j<k;j++) { if(ChoiceWords[j]==ChoiceWords[k]) { k--; break; } } } for(i=0;i<26;i++) { KeyTab[i]=(unsigned char)letter_to_digit(ChoiceWords[i]); }
(2)洗牌法
原理:就是将写有0~(n-1)的n张纸牌打乱次序后重新排列。打乱次序的方式利用(1)随机全排列生成程序。
程序设计:
p=full_array1(25); //生成随机全排列 for(i=0;i<26;i++)KeyTab[26+i]=p[i]; //密码本27~52(抽牌法)
(3)公式法
原理:利用公式生成密码表。公式为(11*i+3)mod 26
程序设计:
for(i=0;i<26;i++) KeyTab[52+i]=(unsigned char)((11*i+3)%26);//密码本53~78
(4)自设计随机16全排列
原理:
unsigned char *full_array16_pickout(){ //自己写的创建随机16全排列,抽牌法 int i,j,l; static unsigned char p[256]; while(l<16){ p[l++]=(unsigned char)(rand()%16); for(j=0;j<l-1;j++){ if(p[j]==p[l-1]){ l--; break; } } } static unsigned char pout[256]; l=15,i=0; while(l>=0){ j=rand()%16; pout[i++]=p[j]; p[j]=p[l--]; } return pout; }
(5)生成密码本(unsigned char *KeyGen)
原理:该函数生成密码本本质上是一个78长的数组。前26位存储密钥字法生成的字母序列;中间26位存储抽牌法生成的字母序列;最后26位储存公式法生成序列。
以下为周期3替代密码表。
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
密钥字 |
|||||||||||||||||||||||||
抽牌 |
|||||||||||||||||||||||||
公式 |
生成五组随机数,构成5-16置换密码表。
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
(6)源代码
在编写代码过程中,部分函数参考实验指导书,主函数
题目一:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h> #include <unistd.h> unsigned char *KeyGen_s(); unsigned char *full_array1(int n); int letter_to_digit(char c); char digit_to_letter(int n); void Encrypt_s(unsigned char *key); int main() { unsigned char *key; key=KeyGen_s(); printf("\n以下为生成密码本:\n"); for(int i=0;i<3;i++){ for(int j=0;j<26;j++){ putchar(digit_to_letter(key[i*26+j])); printf(" "); } printf("\n"); } Encrypt_s(key); return 0; } int letter_to_digit(char c) //字母——数字 { int i; char alphabet[26]; for(int i=0;i<26;i++)alphabet[i]='a'+i; for(i=0;i<26;i++) { if(tolower(c)==alphabet[i]) { return (i); } } return(-1); } char digit_to_letter(int n)//数字-——字母 { char alphabet[26]; for(int i=0;i<26;i++)alphabet[i]='a'+i; if(n<0 || n>25) { return (0); } return (alphabet[n]); } unsigned char *KeyGen_s() //用于生成密码本 { char KeyWords[106]; char ChoiceWords[26]; unsigned char *p; static unsigned char KeyTab[26*3];//创建密码本 int i, j, k, l; printf("\n请输入密钥字:\n"); gets(KeyWords); strcat(KeyWords,"abcdefghijklmnopqrstuvwxyz"); k=0; l=strlen(KeyWords); ChoiceWords[k]=tolower(KeyWords[0]); for(i=1;i<l;i++) //密钥字法后续删除重复字母 { if(letter_to_digit(KeyWords[i])==-1) { continue; } ChoiceWords[++k]=tolower(KeyWords[i]); for(j=0;j<k;j++) { if(ChoiceWords[j]==ChoiceWords[k]) { k--; break; } } } for(i=0;i<26;i++) { KeyTab[i]=(unsigned char)letter_to_digit(ChoiceWords[i]); //密码本前26 (密钥字法) } p=full_array1(25); //生成随机全排列 for(i=0;i<26;i++) { KeyTab[26+i]=p[i]; //密码本27~52(抽牌法) } for(i=0;i<26;i++) { KeyTab[52+i]=(unsigned char)((11*i+3)%26); //密码本53~78 公式为11*i+3(mod 26) } return(KeyTab); } void Encrypt_s(unsigned char *key) // 读取文件,输出密文 { int i; FILE *fp; char filename[20], c; start: printf("\n请输入待加密文本文件名:\n"); scanf("%s", filename); if((fp=fopen(filename,"rt"))==NULL) { printf("没有找到文件:%s\n",filename); goto start; } printf("\n密文如下:\n"); i=0; while((c=fgetc(fp))!=EOF) { if(letter_to_digit(c)==-1) { putchar(c); continue; } isupper(c)?putchar(toupper(digit_to_letter(key[(int)((i%3)*26+letter_to_digit(c))]))):\ putchar(digit_to_letter(key[(int)(i%3)*26+letter_to_digit(c)])); i++; if(i>=26*3)i=0; } fclose(fp); } unsigned char *full_array1(int n) { int i,j; char filename[20]; FILE *fp; static unsigned char d[256],P[256],temp; start: printf("\n 请输入随机数据采样文件名:\n"); scanf("%s",filename); if( (fp=fopen(filename,"rb"))==NULL ) { printf("没有找到文件:%s\n",filename); goto start; } fread(d,n+1,1,fp); fclose(fp); for(i=0;i<=n;i++) { P[i] = i ; //形成自然排列 } for(i=n;i>0;i--) { j=(d[i-1]+d[i])%i ; temp = P[i] ; P[i] = P[j]; P[j] = temp; //交换 } return(P); }
题目二:
#include <stdio.h> #include <time.h> #include <stdlib.h> unsigned char *full_array2(int n); unsigned char *KeyGen_p(); void Encrypt_p(unsigned char *key); int main() { unsigned char *key; key=KeyGen_p(); for(int i=0;i<5;i++){ for(int j=0;j<16;j++){ printf(" %d",key[i*16+j])) } printf("\n"); } Encrypt_p(key); return 0; } unsigned char *KeyGen_p() { unsigned char *p; static unsigned char KeyTab[16*5]; int i, j; for(i=0;i<5;i++) { p=full_array2(15); for(j=0;j<16;j++) { KeyTab[16*i+j]=p[j]; } } return(KeyTab); } void Encrypt_p(unsigned char *key) { int i, j; FILE *fp; char filename[26], c; char d[16]; start: printf("\n请输入待加密文本文件名:\n"); scanf("%s", filename); if((fp=fopen(filename,"rt"))==NULL) { printf("没有找到文件:%s\n",filename); goto start; } printf("\n密文如下:\n"); i=0; while((c=fgetc(fp))!=EOF) { d[i%16]=c; i++; if(i%16!=0) { continue; } for(j=0;j<16;j++) { putchar(d[key[(int)(((i-1)/16)*16+j)]]); } if(i>=16*5) { i=0; } } if(i%16!=0) { for(j=i%16;j<16;j++) { d[j]='*'; } for(j=0;j<16;j++) { putchar(d[key[(int)((i/16)*16+j)]]); } } putchar('\n'); } unsigned char *full_array2(int n) { int m, i, j, k, l=0, flag; static unsigned char P[256]; start: printf("\n请输入不小于%d的所用随机数个数:\n", n+1); scanf("%d",&m); if(m<=n) { printf("\n输入数%d比%d小,须重新输入!\n", m, n+1); goto start; } srand((unsigned)time(NULL)); for(i=0;i<m;i++) { P[l++]=(unsigned char)(rand()%(n+1)); for(j=0;j<l-1;j++) { if(P[j]==P[l-1]) { l--; break; } } } k=l; for(i=0;i<=n;i++) { flag=0; for(j=0;j<k;j++) { if(P[j]==i) { flag=l; break; } } if(!flag) { P[l]=i; l++; } } return (P); }
3.测试结果
密文:
(1)替换密码
运行结果:
检验:密码本如下
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
j |
y |
k |
a |
b |
c |
d |
e |
f |
g |
h |
i |
l |
m |
n |
o |
p |
q |
r |
s |
t |
u |
v |
w |
x |
z |
c |
w |
n |
v |
g |
t |
x |
a |
e |
f |
s |
y |
b |
o |
p |
j |
d |
l |
i |
u |
k |
z |
h |
q |
m |
r |
d |
o |
z |
k |
v |
g |
r |
c |
n |
y |
j |
u |
f |
q |
b |
m |
x |
i |
t |
e |
p |
a |
l |
w |
h |
s |
检验前六位:
明文 |
Q |
i |
s |
a |
s |
y |
密文 |
P |
e |
t |
j |
i |
h |
检验结果正确。
(2)移位密码
运行结果:
检验:密码本如下
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
0 |
6 |
7 |
8 |
3 |
10 |
1 |
11 |
4 |
9 |
13 |
12 |
14 |
2 |
5 |
15 |
3 |
2 |
0 |
8 |
14 |
9 |
11 |
5 |
10 |
1 |
6 |
15 |
7 |
12 |
4 |
13 |
6 |
14 |
8 |
7 |
2 |
12 |
0 |
1 |
5 |
13 |
3 |
4 |
15 |
9 |
10 |
11 |
0 |
4 |
5 |
8 |
11 |
14 |
15 |
6 |
9 |
3 |
1 |
10 |
2 |
12 |
7 |
13 |
7 |
12 |
1 |
4 |
13 |
9 |
0 |
14 |
3 |
8 |
6 |
10 |
2 |
5 |
11 |
15 |
检验前16位:
明 |
Q |
i |
s |
a |
|
s |
y |
m |
m |
e |
t |
r |
i |
c |
||
密 |
Q |
|
s |
y |
s |
m |
|
e |
m |
r |
t |
i |
i |
a |
c |
检验结果正确。
4.遇到问题
在实验过程中部分代码参考实验指导书,因此在实验过程中,发现实验指导书上存在的一些问题
(1)程序报错
程序在运行此行代码时报错,原因与长度有关。
解决方法:改进代码,如下。
char alphabet[i];
for(int i=0;i<26;i++)alphabet[i]=’a’+i;
(2)实验指导书关于题目一代码错误
按照次代码,会将明文前26个用密钥字法加密;第二个26用抽牌法加密……。与要求周期3不符。
解决方法:修改代码,将i除26修改为i模3;
正在上传…重新上传取消
四、实验体会
本次是密码学的第一次实验,主要是两种基本古典密码设计与实现,在操作之中逐渐熟悉了他们的使用方法并了解了两种密码的差异。
本次实验的函数对我相对困难,因此部分函数借鉴了实验指导书,在对实验指导书的学习过程中,我也发现了实验指导书上面存在一些问题,并通过自己的理解修改了函数,并得到了老师的肯定。
能发现问题,源自于我对题目的深刻理解,这次实验之前的预习必不可少,投入的时间终究会有回报。
五、思考题
思考题:“代替表”与“置换”的不动点、逆等是否一致?
不一致。
代替密码的实质是从明文空间通过一定的映射关系到密文空间,已经不再是原来的集合了。移位密码的实质是在明文空间内部,通过移动明文位置,使明文乱序,从而达到加密的目的。两者的不动点和逆只有在统一集合变换时才可能一样。
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/147618.html