C语言课程设计实习报告封面.docx

上传人:b****7 文档编号:26028166 上传时间:2023-06-17 格式:DOCX 页数:35 大小:703.15KB
下载 相关 举报
C语言课程设计实习报告封面.docx_第1页
第1页 / 共35页
C语言课程设计实习报告封面.docx_第2页
第2页 / 共35页
C语言课程设计实习报告封面.docx_第3页
第3页 / 共35页
C语言课程设计实习报告封面.docx_第4页
第4页 / 共35页
C语言课程设计实习报告封面.docx_第5页
第5页 / 共35页
点击查看更多>>
下载资源
资源描述

C语言课程设计实习报告封面.docx

《C语言课程设计实习报告封面.docx》由会员分享,可在线阅读,更多相关《C语言课程设计实习报告封面.docx(35页珍藏版)》请在冰豆网上搜索。

C语言课程设计实习报告封面.docx

C语言课程设计实习报告封面

信息安全基础课程设计

 

 

姓名:

范相地学号:

20111004304

专业:

192112班学号:

192112—28

院(系):

信息安全指导教师:

宋军、杨帆、余林琛

 

 

2014年3月

 

第一部分数学基础与密码学部分实验内容

第一章信息安全数学基础实验部分

1、题目:

使用VC++编程语言编写一个可测定不超过1,000,000的素数判定程序。

2、定理:

设n是一个正整数,如果对所有的素数p≤,都有płn,则n一定是素数。

注:

古希腊数学家埃拉托斯散(Eratosthenes,公元前275—公元前194)发明了求比某给定数小的素数的筛法技巧。

方法如下:

对于任意给定的正整数N,要求出所有不超过sqrt(N)的素数。

我们列出N个整数,从中删除小于等于的所有素数p1,…,pk的倍数。

然后依次删除,

p1的倍数:

2p1,…,p1

……

pk的倍数:

2pk,…,pk

余下的整数(不包括1)就是所要求的不超过N的素数。

3、代码设计:

首先要求出sqrt(n)以内的素数,创建一个函数进行调用来判断是否为素数。

intis_Prime(intq)

{

intsq;

intflag=1;

inti;

sq=sqrt(q);

for(i=2;i<=sq;i++)

{

if(q%i==0)

{

flag=0;

break;

}

}

returnflag;

}

当求出sqrt(n)以内的素数,并存储于数组a[i]中,则对于要判定的素数n,只需判断

是否n%a[i]==0。

for(i=0;i

{

if(n%a[i]==0)

{

cout<

break;

}

}

if(i==j)

cout<

4、源码:

#include

#include

usingnamespacestd;

intmain()

{

intn,k;

inti;

intj=0;

intp=0;

inta[200];

cout<<"输入数n=";

cin>>n;

intis_Prime(int);

k=sqrt(n);

///////////////////////////////////////////////////////

for(i=2;i<=k;i++)

{

if(is_Prime(i)==1)

{cout<

a[j]=i;

j++;}}

cout<

////////////////////////////////////////////////////////////

for(i=0;i

{

if(n%a[i]==0)

{

cout<

break;

}

}

if(i==j)

cout<

cout<

return0;

}

////////////////////////////////////////////

intis_Prime(intq)

{

intsq;

intflag=1;

inti;

sq=sqrt(q);

for(i=2;i<=sq;i++)

{

if(q%i==0)

{

flag=0;

break;

}

}

returnflag;

}

第二章密码学基础实验部分

题目:

1999年3月22日第二次AES会议上,将候选算法名单减少为5个,这5个

算法是RC6,Rijndael,SERPENT,Twofish和MARS。

使用VC++编程语言编写

一个程序:

(五选一)以Rijndael为例

关于Rijndael算法:

Rijndael算法首先是一个密钥分组加密的算法,通过置换(permutations)和替换(substitutions)迭代加密,进过多轮操作形成密文。

AES算是Rijndael算法的一种特殊实现,选的分组为128bit(16字节),密钥可以使用128、192和256bit三种。

分组

上面已经说了AES分组为16个字节,下面说说他的排列,其实就是一个4x4的矩阵,不过要注意是竖着排的。

AES原文:

a1a2a3a4a5a6a7a8a9a10a11a12a13a14a15a16...

a1   a5   a9   a13

a2   a6   a10 a14

a3   a7   a11 a15

a4   a8   a12 a16

密钥

AES的密钥虽然有三种,但是并不意味着这三种密钥的AES差异很大,相反加密过程其实完全一样,只是种子密钥是128,192,256bit三种而已。

密钥在AES与分组数据并没有做非常复杂的变化,其实只是简单的&(与)操作而已。

不过又因为AES算法有很多轮,所有单单的种子密钥是不够的,所有AES有自己的扩展密钥的方法。

还要提一下,密钥扩展后也是竖着排成方阵的。

key:

k1k2k3k4k5k6k7k8k9k10k11k12k13k14k15k16...

k1   k5   k9   k13

k2   k6   k10 k14

k3   k7   k11 k15

k4   k8   k12 k16

轮数

轮数主要跟种子密钥长度有关。

一般习惯用Nk表示密钥所含的数据字数,一字表示32bit,也就是4字节,也就是一竖排。

128,192,256bit对应Nk=4,6,8

一般习惯用Nr表示轮数

Nr=Nk+6也就是10,12,14

密钥扩展(KeyExpansion)

对与密钥扩展其实只要关心两点:

一是扩展成多长,这个其实跟加密过程有关,暂时只要知道密钥总长度为(分组大小=16个字节)*(Nr+1),也就是4*(Nr+1)字,下面讲过程的时候就会明白为什么要这么长。

二是密钥扩展的算法,密钥的算法其实比较复杂,但是却不难理解。

注:

Nk密钥字数,字为4字节也就是一竖排。

算法步骤如下:

Nk≤6的密钥扩展

1)最前面的Nk个字是由种子密钥填充的。

2)之后的每一个字W[j]等于前面的字W[j-1]的与Nk个位置之前的字W[j-Nk]的异或。

3)而且对于Nk的整数倍的位置处的字,在异或之前,对W[j-1]的进行如下变换:

     .字节的循环移位RotByte->即当输入字为(a,b,c,d)时,输出字为(b,c,d,a)

     .用S盒进行变换次位元组

     .异或轮常数Rcon[i/Nk]

伪代码

KeyExpansion(byteKey[4*Nk],W[Nb*(Nr+1)])

{

   for(i=0;i

      W[i]=(Key[4*i],Key[4*i+1],Key[4*i+2],Key[4*i+3]);

//扩展密钥的前面4个字由种子密钥组成

   for(i=Nk;i

   {

      temp=W[i-1];

      if(i%Nk==0)         

   temp=SubByte(RotByte(temp))^Rcon[i/Nk];

      //i是NK的整数倍是要特殊处理

      W[i]=W[i-Nk]^temp;

   }

}

Nk>6的密钥扩展

KeyExpansion(byte Key[4*Nk],W[Nb*(Nr+1)])

{for(i=0;i

      W[i]=(Key[4*i],Key[4*i+1],Key[4*i+2],Key[4*i+3]);

 //扩展密钥的前面4个字由种子密钥组成

for(i=Nk;i

   {temp=W[i-1];

      if(i%Nk==0)

         temp=SubByte(RotByte(temp))^Rcon[i/Nk];

    //i是NK的整数倍是要特殊处理

        elseif(i%Nk==4)

                temp=SubByte(temp);

     //i是4的整数倍是要特殊处理

       W[i]=W[i-Nk]^temp;}

异或轮常数Rcon[i/Nk]:

Rcon[i/Nk]=(RC[i/Nk]],’00’,’00’,’00’)(i一定会大于Nk) RC[1]=‘01’RC[x]=2⊙RC[x-1]

RC[1]=(01,00,00,00),RC[2]=(02,00,00,00),

RC[3]=(04,00,00,00),RC[4]=(08,00,00,00),

RC[5]=(10,00,00,00),RC[6]=(20,00,00,00),

RC[7]=(40,00,00,00),RC[8]=(80,00,00,00),

RC[9]=(1b,00,00,00),RC[10]=(36,00,00,00))

每一轮分组(源数据)都要经过4种变换,分别是ByteSubShiftRowMixColumnAddRoundKey

ByteSub(字节代换)

这个比较简单,就是查表替代。

对于分组的16字节都进行字节代换就行,还有字节一般写成16进制的也就是如FF这种。

sbox如下图:

 

ShiftRow(行移位)

对于分组4x4有4行,进行如下规则位移

第0行不移位,

第1行左移1字节,

第2行左移2字节,

第3行左移3字节。

MixColumn(列混合)

列混合其实比较难理解。

原理是数学矩阵相乘,如下图s为原数据,s‘为加密后数据。

 

不过这里的乘法和加法都是数学域操作,说白了就是一种新的运算。

加法

a+b=a^b

加法就是做两者的异或操作

乘法

0x01*b=b

0x02*b只要b小于0x80,b<<1。

如果b大于或等于0x80,(b<<1)^0x1b

对于大于0x02可以分解成0x02和0x01的算法,这牵扯到数学域GF(2^8),可以分解成2的幂次方,在这不多做介绍,其实是本文作者能力有限,讲不清楚。

b*0x03=b*(0x02+0x01)

=(b*0x02)+(b*0x01)

b*0x0d=b*(0x08+0x04+0x01)

=(b*0x08)+(b*0x04)+(b*0x01)

=(b*0x02*0x02*0x02)+(b*0x02*0x02)+(b*0x01)

b*0x09=b*(0x08+0x01)

=(b*0x02*0x02*0x02)+(b*0x01)

b*0x0b=b*(0x08+0x02+0x01)

=(b*0x02*0x02*0x02)+(b*0x02)+(b*0x01)

b*0x0e=b*(0x08+0x04+0x02)

=(b*0x02*0x02*0x02)+(b*0x02*0x02)+(b*0x02)

AddRoundKey

就是4x4的原数据与4x4的扩展密钥做异或运算

 

下面是加密流程的伪代码,到此aes算法就介绍完了

Encryption(State,CipherKey)

 {   KeyExpansion(CipherKey,RoundKey)

     AddRoundKey(State,RoundKey)//第0轮只做AddRoundKey

     For(i=1;i

     Round(State,RoundKey)

         {ByteSub(State);

           ShiftRow(State);

           MixColumn(State);

           AddRoundKey(State,RoundKey)}

      FinalRound(State,RoundKey)//最后一轮不做mixcolumn

         {

ByteSub(State);

            ShiftRow(State); 

            AddRoundKey(State,RoundKey);

}

 

第二部分信息论基础实验部分

题目一算术编码

1﹑题目要求

算术编码是把一个信源表示为实轴上0和1之间的一个区间,信源集合中的每一个元素都用来缩短这个区间。

算法流程

(1)输入信源符号个数,信源概率分布,还有需要编码的符号序列,

(2)根据概率可以算出初始编码间隔,

High——当前编码的上限,

Low——当前编码的下限,

high——中间变量,用来计算下一个编码符号的当前间隔的上限,

low——中间变量,用来计算下一个编码符号的当前间隔的下限,

d——当前间隔之间的距离。

(3)扫描需编码的符号序列,确定编码空间

第1个编码符号的当前间隔为其初始的编码间隔,

第i个编码符号的当前间隔为第i-1个编码后的[Low,High),

第i+1个编码符号的当前间隔算法如下:

high=Low+d*第i+1个初始编码符号对应的上限,low=Low+d*第i+1个编码符号对应的下限,然后High=high,Low=low,d=d*第i个编码符号的概率。

 

2.设计

其算法的主要算法基本思想:

首先就是构造一个结构体用于存储信源的相关信息(包括信源符号,信源概率,编码的上下限);接着就是初始化信源的相关信息,如初始化编码间隔;利用算术编码的原理构造编码方法,最后实现编码

3.调试分析:

此算法主要就是算术编码方法的构造,初始化以后,根据初始化间隔完成编码序列的编码。

在调试的过程中经常遇到一些小问题,通过一步步的调试以及修改,问题一个的解决了。

同时也遇到比较大的问题,就是编码方法过程的实现,最大的体会就是必须深入理解次编码方法的原理。

4.流程图

4.测试结果:

7.源程序清单:

#include

#include

#include

usingnamespacestd;

typedefstructNode

{

charname;

doublepi;

doublefi;

};

intmain()

{

inti,j;

doubleps=1;

doublefs;

intlength;//码字s1的长度

Nodenode[20];

intn;//信源符号个数n元

cout<<"输入信源个数n=";

cin>>n;

//////////////////////////////////////////

cout<<"输入信源符号及其概率"<

for(i=0;i

{

cin>>node[i].name;

cin>>node[i].pi;

}

node[0].fi=0;

for(i=1;i

node[i].fi=node[i-1].fi+node[i-1].pi;

////////////////////////////////////////////////////

chars[20];//所要编码符号序列

chars1[20];//码字结果

cout<<"输入需要编码序列s:

";

cin>>s;

cout<

 

intls=strlen(s);//编码序列s的长度

 

///////////////////////////////////

doubleHigh=1;

doubleLow=0;

doubled=1;

//////////////////////////////////////////

//求出码字长度

for(i=0;i

{

for(j=0;j

{

if(node[j].name==s[i])

{

Low=Low+d*node[j].fi;

d=d*node[j].pi;

High=Low+d;

break;

}

}

ps*=node[j].pi;

}

length=log(1/ps)/log

(2)+1;

fs=Low;

cout<<"码字长度为"<

cout<<"累计概率fs="<

/////////////////////////////////////////

intk[20];

for(i=0;i

{

fs=fs*2.0;

if(fs<1.0)

k[i]=0;

else

{

k[i]=1;

fs=fs-1.0;

}

}

////////////////////////////////////

if(fs!

=0)

for(i=length-1;i>=0;i--)

{

if(k[i]==0)

{

k[i]=1;

break;

}

else

k[i]=0;

}

///////////////////////////////////////////

cout<<"码字为:

";

for(i=0;i

cout<

cout<

}

题目二Huffman编码对文本的压缩和解压缩

1﹑题目要求

根据信源压缩编码——Huffman编码的原理,制作对英文文本进行压缩和解压缩的软件。

要求软件有简单的用户界面,软件能够对运行的状态生成报告,分别是:

字符频率统计报告、编码报告、压缩程度信息报告、码表存储空间报告。

2.设计

设计思想:

首先构造一个结构体用于统计字符频率,然后把统计后的结果当作信源;接着用Haffman编码的方法对其编码,编码后对输入的英语文本进行编码的转换,即用Haffman编码的每一个字符的编码代替输入的英语文本每一字符,输入的英语文本就变成了01代码流,最后利用这01代码流每八位压缩成相对应的字符。

压缩流程:

读取扫描文本文件——〉统计字符频率——〉生成码字——〉保存压缩文件

解压缩流程:

读取扫描压缩文件——〉提取字符频率——〉生成码树——〉保存文本文件

3.调试分析:

本算法可以分成四个部分即统计字符概率,Huffman编码,压缩文件和解压文件四部分,也就是次算法中函数stati(),函数HCode()和函数compress()的构建,用于压缩后的字符出现了乱码,所以对解压文件这部分难以实现,这也是此算法失败的地方。

经过不断的调试和修改还是只完成统计字符概率,Huffman编码和压缩文件这三部分。

4.流程图

5测试结果:

6.源程序清单:

#include

#include

#defineMaxValue1000//设定权值最大值

#defineMaxBit10//设定的最大编码位数

#defineMaxN1000//设定的最大结点个数

#include"Huffman.h"

floatComNum=0;//用于计算压缩后的字符个数

structstatistics//统计字符频率

{

chara[100];//出现的字符

doublep[100];//字符出现的概率

inttag[100];//每一个字符出现次数

intnum;//总计出现的字符种类个数

floatn;//总计字符出现的次数

}TJ;

charcc[100];

voidraplace(myHaffCode);

stati()//统计字符

{

FILE*fp;

FILE*fp1;

charch,filename[10];

inti=0,k;

printf("请输入用于保存字符文本的文件名,如file.txt\n");

scanf("%s",filename);

getchar();

printf("请输入英语文本:

");

gets(cc);

fp=fopen(filename,"w+");

fprintf(fp,"%s",cc);

fclose(fp);

TJ.num=1;

TJ.n=0;

if((fp1=fopen(filename,"r"))==NULL)

{

printf("文件无法打开!

");

exit(0);

}

ch=fgetc(fp1);

TJ.a[i]=ch;

while(ch!

=EOF)//统计字符出现的次数,并计算起概率。

{

intj;

for(j=i;j>=0;j--)

{

if(TJ.a[j]==ch)

{

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 远程网络教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1