(密码学实验)两种基本古典密码设计与实现—C语言—随机全排列应用
目录
一、实验目的
二、实验内容
三、实验过程
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;
正在上传…重新上传取消
四、实验体会
本次是密码学的第一次实验,主要是两种基本古典密码设计与实现,在操作之中逐渐熟悉了他们的使用方法并了解了两种密码的差异。
本次实验的函数对我相对困难,因此部分函数借鉴了实验指导书,在对实验指导书的学习过程中,我也发现了实验指导书上面存在一些问题,并通过自己的理解修改了函数,并得到了老师的肯定。
能发现问题,源自于我对题目的深刻理解,这次实验之前的预习必不可少,投入的时间终究会有回报。
五、思考题
思考题:“代替表”与“置换”的不动点、逆等是否一致?
不一致。
代替密码的实质是从明文空间通过一定的映射关系到密文空间,已经不再是原来的集合了。移位密码的实质是在明文空间内部,通过移动明文位置,使明文乱序,从而达到加密的目的。两者的不动点和逆只有在统一集合变换时才可能一样。
(密码学实验)两种基本古典密码设计与实现—C语言—随机全排列应用相关推荐
- 【MATLAB实验】数学实验实验求根问题三种方法、积分画图及古典密码设计(二分法、牛顿法、不动点迭代法)
目录 特征值与特征向量 求最简型 编程题 求积分问题(quad.trapz.int) 求根问题(二分法.不动点迭代法.牛顿法) 1.二分法: 2.不动点迭代法 3.牛顿切线法 画图题 画螺旋曲线图 画 ...
- 最实用最简单,两种清除cmos密码的方法
最近公司搬家找出来一个之前的电脑,打开之后需要dos密码,由于密码设置的人已经离职,现在是忘记cmos密码无法进入bios.开机之后直接出现密码界面,这个问题该怎么处理呢?今天小编就来教大家最简单的两 ...
- [现代密码学] Crypto 知识点总结(古典密码对称加密hash函数)
文章目录 一 . 常见加解密 SM1-4 二. 古典密码 代换密码 置换密码 Hill密码 转轮密码 代换密码的唯密文攻击 例题 例题 三. 对称加密算法 分组密码 DES算法(数据加密标准) 1. ...
- 【CTF】实验吧 传统知识+古典密码
对照顺序写下: 根据对应的干支得到 28 30 23 8 17 10 16 30 +甲子 所有的数加60 得到 88 90 83 68 77 70 76 90 找到ASCII码对照表可得到XZSD ...
- 26两种主界面的设计
两种均模仿了微信6.0底部菜单栏的效果,第一种在左右滑动的时候有动画,第二种没有,首先看第一种: 布局: <LinearLayout xmlns:android="http://sch ...
- javaweb基于SSM开发房屋租赁管理系统(房东 租客两种用户) 课程设计 大作业源码 毕业设计
基于SSM开发房屋租赁管理系统(房东 租客两种用户)(大作业/毕业设计) 开发工具:Eclipse+Jdk+Tomcat+MySQL数据库 演示视频: 基于SSM开发房屋租赁管理系统(房东 租客两种用 ...
- 密码学(二):古典密码之维吉尼亚密码的破解
维吉尼亚密码的破解 一.引言 上一章我们介绍了维吉尼亚密码的原理,是通过移位替换的加密方法进行加密,但是因为概率论的出现这种简单的移位或替换就容易破解了,其原理很简单,英文中字母出现的频率是不一样 ...
- 密码学实验一、凯撒密码
实验内容 1.利用k=7时的kaiser密码加密明文:cryptography 2.利用k=4时的kaiser密码解密密文:QEXLIQEXMG 3.用kaiser密码获得秘文kddkmu,试所有可能 ...
- 正则表达式验证六位数以上数字,符号,字母任意两种混合的密码验证策略
^(?![0-9]+$)(?![a-zA-Z]+$)(?!([^(0-9a-zA-Z)]|[\(\)])+$)([^(0-9a-zA-Z)]|[\(\)]|[a-zA-Z]|[0-9]){6,}$ 这 ...
最新文章
- python非贪婪、多行匹配正则表达式例子[转载]
- [MATLAB]从已知矩阵中取出子阵
- Tomcat绿色版启动startup.bat一闪问题的解决方法!
- 22/100. Find All Anagrams in a String
- android 静态广播无效,Android8.0静态广播接收静态注册无效,并实现全局网络监听...
- 【Transformer】PoolFormer: MetaFormer is Actually What You Need for Vision
- mysql 表名通配符导出,mysqldump只有某些前缀/ Mysqldump通配符的表?
- CSS 居中 可随着浏览器变大变小而居中
- Elasticsearch添加拼音搜索支持
- vba打开html文件,VBA调用浏览器打开指定网页的几种方法
- 教你用GoldWave进行基础的混音准备
- 可以通过格式化硬盘清除计算机病毒吗,电脑中毒,完全格式化硬盘可以吗?
- java截取图片截图画框
- 探索Selenium打开浏览器加载慢的原因
- 互联网产品用户体验设计方法和用户体验优化方法
- 简单html开源游戏案例,基于CreatejsHTML5游戏案例(看你有多色游戏案例)
- python能在ipad上运行吗_如何用iPad运行Python代码?
- Kvm与webvirtmgr虚拟化安装
- 学会Nginx优化与防盗链预防坏蜀黍
- 关于设定校园二手租赁系统的计划、功能及建议