目录

一、实验目的

二、实验内容

三、实验过程

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语言—随机全排列应用相关推荐

  1. 【MATLAB实验】数学实验实验求根问题三种方法、积分画图及古典密码设计(二分法、牛顿法、不动点迭代法)

    目录 特征值与特征向量 求最简型 编程题 求积分问题(quad.trapz.int) 求根问题(二分法.不动点迭代法.牛顿法) 1.二分法: 2.不动点迭代法 3.牛顿切线法 画图题 画螺旋曲线图 画 ...

  2. 最实用最简单,两种清除cmos密码的方法

    最近公司搬家找出来一个之前的电脑,打开之后需要dos密码,由于密码设置的人已经离职,现在是忘记cmos密码无法进入bios.开机之后直接出现密码界面,这个问题该怎么处理呢?今天小编就来教大家最简单的两 ...

  3. [现代密码学] Crypto 知识点总结(古典密码对称加密hash函数)

    文章目录 一 . 常见加解密 SM1-4 二. 古典密码 代换密码 置换密码 Hill密码 转轮密码 代换密码的唯密文攻击 例题 例题 三. 对称加密算法 分组密码 DES算法(数据加密标准) 1. ...

  4. 【CTF】实验吧 传统知识+古典密码

    对照顺序写下: 根据对应的干支得到 28 30 23 8 17 10 16 30   +甲子 所有的数加60 得到 88 90 83 68 77 70 76 90 找到ASCII码对照表可得到XZSD ...

  5. 26两种主界面的设计

    两种均模仿了微信6.0底部菜单栏的效果,第一种在左右滑动的时候有动画,第二种没有,首先看第一种: 布局: <LinearLayout xmlns:android="http://sch ...

  6. javaweb基于SSM开发房屋租赁管理系统(房东 租客两种用户) 课程设计 大作业源码 毕业设计

    基于SSM开发房屋租赁管理系统(房东 租客两种用户)(大作业/毕业设计) 开发工具:Eclipse+Jdk+Tomcat+MySQL数据库 演示视频: 基于SSM开发房屋租赁管理系统(房东 租客两种用 ...

  7. 密码学(二):古典密码之维吉尼亚密码的破解

    维吉尼亚密码的破解 一.引言   上一章我们介绍了维吉尼亚密码的原理,是通过移位替换的加密方法进行加密,但是因为概率论的出现这种简单的移位或替换就容易破解了,其原理很简单,英文中字母出现的频率是不一样 ...

  8. 密码学实验一、凯撒密码

    实验内容 1.利用k=7时的kaiser密码加密明文:cryptography 2.利用k=4时的kaiser密码解密密文:QEXLIQEXMG 3.用kaiser密码获得秘文kddkmu,试所有可能 ...

  9. 正则表达式验证六位数以上数字,符号,字母任意两种混合的密码验证策略

    ^(?![0-9]+$)(?![a-zA-Z]+$)(?!([^(0-9a-zA-Z)]|[\(\)])+$)([^(0-9a-zA-Z)]|[\(\)]|[a-zA-Z]|[0-9]){6,}$ 这 ...

最新文章

  1. python非贪婪、多行匹配正则表达式例子[转载]
  2. [MATLAB]从已知矩阵中取出子阵
  3. Tomcat绿色版启动startup.bat一闪问题的解决方法!
  4. 22/100. Find All Anagrams in a String
  5. android 静态广播无效,Android8.0静态广播接收静态注册无效,并实现全局网络监听...
  6. 【Transformer】PoolFormer: MetaFormer is Actually What You Need for Vision
  7. mysql 表名通配符导出,mysqldump只有某些前缀/ Mysqldump通配符的表?
  8. CSS 居中 可随着浏览器变大变小而居中
  9. Elasticsearch添加拼音搜索支持
  10. vba打开html文件,VBA调用浏览器打开指定网页的几种方法
  11. 教你用GoldWave进行基础的混音准备
  12. 可以通过格式化硬盘清除计算机病毒吗,电脑中毒,完全格式化硬盘可以吗?
  13. java截取图片截图画框
  14. 探索Selenium打开浏览器加载慢的原因
  15. 互联网产品用户体验设计方法和用户体验优化方法
  16. 简单html开源游戏案例,基于CreatejsHTML5游戏案例(看你有多色游戏案例)
  17. python能在ipad上运行吗_如何用iPad运行Python代码?
  18. Kvm与webvirtmgr虚拟化安装
  19. 学会Nginx优化与防盗链预防坏蜀黍
  20. 关于设定校园二手租赁系统的计划、功能及建议

热门文章

  1. 微服务设计指导-通过一个生产事故的具体例子来看微服务
  2. 基于C语言库windows.h的轰炸程序
  3. C语言windows.h库的常用函数(三)
  4. 智慧教学工具在操作系统课程教学中的应用研究
  5. 神经网络结构如何确定,神经网络的神经元结构
  6. 中医号脉根据什么原理
  7. 权威专家推荐的最佳安全图书
  8. 用程序无法启动0x7b
  9. 一个人下班后,如何高质量提升自己
  10. 北京重点中学一览表(2009小升初)