文档库 最新最全的文档下载
当前位置:文档库 › 流密码与分组密码编程

流密码与分组密码编程

流密码与分组密码编程
流密码与分组密码编程

上机一:流密码与分组密码编程

【上机目的】

熟悉流密码和分组密码加密/解密算法的基本原理,通过编程/开源代码分析分别了解一种标准流密码算法和一种标准分组密码算法的运行原理。

【上机环境】

1、硬件PC机一台。

2、系统配置:操作系统windows XP以上。

3、编程语言:C/C++/C#/Java/Python

【上机容及要求】

1、分别利用RC4算法(或其它任一种标准流密码算法)和DES算法(或AES算法等其它任

一种标准分组密码算法)对数据进行加解密操作

2、代码分析及注释

3、代码调试

4、代码修改及测试(选做)

备注:可借鉴网上相关算法的开源代码进行编程实现,编程语言不限。

【上机报告】

1、提交关键功能有注释的源码。

2、提交运行测试结果(运行截图及说明)。

3、运行测试结果分析。

4、上机总结(任务完成情况、出现或待解决的问题、收获、体会等)。

流密码

流密码就是使用较短的一串数字(叫它密钥吧),来生成无限长的伪随码流,当然事实上只需要生成和明文长度一样的密码流就够了。一个非常简单的流密码算法是,用6个比特位101100做密钥,将它不断重复得到密码流0. ...直到和明文长度相等,然后将密码流和明文“相加”就得到密文了,解密就是将这个密码流和密文“相加”。流密码算法有个特殊的名称——维吉尼亚密码,当然这里密钥长度可以不是6。用较短的密钥产生无限长的密码流的方法非常多,其中有一种就叫做RC4。

把明文的信息限制在ascii码字符集(它已经能表示所有的英文资料了哈哈),每个字符是一个比特,占8位。假设明文是abc,a、b、c的ascii值分别为97、98、99。二进制形式为01100001、01100010、01100011。密钥流和明文长度一样,假设是sdf,同样可以得到二进制流01110011、01100100、01100110,让他们在对应位做异或运算就可以得到密文了,c语言有^运算符来实现“相加”的操作。我们就直接对字符进行“相加”即a^s, b^d, c^f。得到的结果的二进制形式为00010010、00000110、00000101,它们分别表示ascii码值为18、6、5的字符

RC4用两步来生成密码流

首先你指定一个短的密码,储存在key[MAX]数组里,还有一个数组S[256],令S[i]=i。然后利用数组key来对数组S做一个置换,也就是对S数组里的数重新排列,排列算法为

for i from 0 to 255

S[i] := i

endfor

j := 0

for i from 0 to 255

j := (j + S[i] + key[i mod keylength]) mod 256

swap values of S[i] and S[j]

endfor

第二步利用上面重新排列的数组S 来产生任意长度的密钥流,算法为

i := 0

j := 0

while GeneratingOutput:

i := (i + 1) mod 256

j := (j + S[i]) mod 256

swap values of S[i] and S[j]

K := S[(S[i] + S[j]) mod 256]

output K

endwhile

output K 一次产生一字符长度(8bit)的密钥流数据,一直循环直到密码流和明文长度一样为止。

产生密钥流之后,对信息进行加密和解密就只是做个“相加”的运算。

RC4算法的特点是算法简单,运行速度快,而且密钥长度是可变的,可变围为1-256字节(8-2048比特),在如今技术支持的前提下,当密钥长度为128比特时,用暴力法搜索密钥已经不太可行,所以可以预见RC4的密钥围任然可以在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,如今也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。

在介绍RC4算法原理之前,先看看算法中的几个关键变量:

1、密钥流:RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节,因为密文第i字节=明文第i字节^密钥流第i字节;

2、状态向量S:长度为256,S[0],S[1].....S[255]。每个单元都是一个字节,算法运行的任何时候,S都包括0-255的8比特数的排列组合,只不过值的位置发生了变换;

3、临时向量T:长度也为256,每个单元也是一个字节。如果密钥的长度是256字节,就直接把密钥的值赋给T,否则,轮转地将密钥的每个字节赋给T;

4、密钥K:长度为1-256字节,注意密钥的长度keylen 与明文长度、钥流的长度没有必然关系,通常密钥的长度趣味16字节(128比特)。

RC4的原理分为三步:

1、初始化S和T

for i=0 to 255 do

S[i] =i;

T[i]=K[ imodkeylen ];

2、初始排列S

for i=0 to 255 do

j= ( j+S[i]+T[i])mod256;

swap(S[i],S[j]);

3、产生密钥流

for r=0 to len do //r为明文长度,r字节

i=(i+1) mod 256;

j=(j+S[i])mod 256;

swap(S[i],S[j]);

t=(S[i]+S[j])mod 256;

k[r]=S[t];

下面给出RC4加密解密的C++实现:

加密类:

/*

加密类

*/

class RC4 {

public:

/*

构造函数,参数为密钥长度

*/

RC4(int kl):keylen(kl) {

srand((unsigned)time(NULL));

for(int i=0;i

int tmp=rand()%256;

K.push_back(char(tmp));

}

}

/*

由明文产生密文

*/

void encryption(const string &,const string &,const string &); private:

unsigned char S[256]; //状态向量,共256字节

unsigned char T[256]; //临时向量,共256字节

int keylen;//密钥长度,keylen个字节,取值围为1-256 vector K;//可变长度密钥

vector k;//密钥流

/*

初始化状态向量S和临时向量T,供keyStream方法调用

*/

void initial() {

for(int i=0;i<256;++i){

S[i]=i;

T[i]=K[i%keylen];

}

}

/*

初始排列状态向量S,供keyStream方法调用

*/

void rangeS() {

int j=0;

for(int i=0;i<256;++i){

j=(j+S[i]+T[i])%256;

//cout<<"j="<

S[i]=S[i]+S[j];

S[j]=S[i]-S[j];

S[i]=S[i]-S[j];

}

}

/*

生成密钥流

len:明文为len个字节

*/

void keyStream(int len);

};

void RC4::keyStream(int len) {

initial();

rangeS();

int i=0,j=0,t;

while(len--){

i=(i+1)%256;

j=(j+S[i])%256;

S[i]=S[i]+S[j];

S[j]=S[i]-S[j];

S[i]=S[i]-S[j];

t=(S[i]+S[j])%256;

k.push_back(S[t]);

}

}

void RC4::encryption(const string &plaintext,const string &ks,const string &ciphertext) { ifstream in;

ofstream out,outks;

in.open(plaintext);

//获取输入流的长度

in.seekg(0,ios::end);

int lenFile=in.tellg();

in.seekg(0, ios::beg);

/生产密钥流

keyStream(lenFile);

outks.open(ks);

for(int i=0;i

outks<<(k[i]);

}

outks.close();

//明文容读入bits中

unsigned char *bits=new unsigned char[lenFile];

in.read((char *)bits,lenFile);

in.close();

out.open(ciphertext);

//将明文按字节依次与密钥流异或后输出到密文文件中

for(int i=0;i

out<<(unsigned char)(bits[i]^k[i]);

}

out.close();

delete []bits;

}

解密类:

/*

解密类

*/

class RC4_decryption{

public:

/*

构造函数,参数为密钥流文件和密文文件

*/

RC4_decryption(const string ks,const string ct):keystream(ks),ciphertext(ct) {} /*

解密方法,参数为解密文件名

void decryption(const string &);

private:

string ciphertext,keystream;

};

void RC4_decryption::decryption(const string &res){

ifstream inks,incp;

ofstream out

inks.open(keystream);

incp.open(ciphertext);

//计算密文长度

inks.seekg(0,ios::end);

const int lenFile=inks.tellg();

inks.seekg(0, ios::beg);

//读入密钥流

unsigned char *bitKey=new unsigned char[lenFile];

inks.read((char *)bitKey,lenFile);

inks.close();

//读入密文

unsigned char *bitCip=new unsigned char[lenFile];

incp.read((char *)bitCip,lenFile);

incp.close();

//解密后结果输出到解密文件

out.open(res);

for(int i=0;i

out<<(unsigned char)(bitKey[i]^bitCip[i]);

out.close();

}

程序实现时,需要注意的是,状态向量数组S和临时向量数组T的类型应设为unsigned char,而不是char。因为在一些机器下,将char默认做为signed char看待,在算法中计算下标i,j的时候,会涉及char转int,如果是signed的char,那么将char的8位拷贝到int的低8位后,还会根据char的符号为,在int的高位补0或1。由于密钥是随机产生的,如果遇到密钥的某个字节的高位为1的话,那么计算得到的数组下标为负数,就会越界。

程序运行示例

main函数:

int main(){

RC4 rc4(16); //密钥长16字节

rc4.encryption("明文.txt","密钥流.txt","密文.txt");

RC4_decryption decrypt("密钥流.txt","密文.txt");

decrypt.decryption("解密文件.txt");

}

明文:我爱卜俊杰!

密文:'柀L &t餥6洲

密钥流:镈膺嚬3屽u

解密文件:我爱卜俊杰!

验证成功

实验心得与困难:c代码,编译得到encrypt可执行文件,在命令行下运行encrypt 命令(后面必须跟一个纯文本文件名FILE作为参数),然后输入密钥,可将文件FILE进行加密,再次运行并输入相同的密钥可以进行解密,如果前后密钥不同,就不是解密而是进行二次加密了,哈我可以用自己理解的方式来加密信息了:) 这个程序本是针对纯英文文件来加密的,但是文件里有中文时一样可以加解密。

相关文档