RC4算法对文件进行加密解密

RC4算法对文件进行加密解密

在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。RC4是有线等效加密(WEP)中采用的加密算法,也曾经是TLS可采用的算法之一。

RC4序列密码是美国RSA数据安全公司设计的一种序列密码。其实最开始这家公司并没有公布RC4算法的设计细节,在人们已经通过逆向分析得到了算法之后,在97年RSA公司才公布了RC4密码算法。
RC4算法的优点就是算法简单、高效,适合软件实现。

RC4算法的加密解密流程

RC4加解密相当于是对合运算,所以只要输入密钥相同,那么执行相同的操作即可对数据实现加密和解密。
而RC4和基于以为寄存器的序列密码不同,它是基于非线性数据表变换的序列密码,它以一个足够大的数据表为基础,对表进行非线性变化,从而产生非线性的密钥序列。
基本流程如下:
首先,RC4取一个256字节构成的S表,并引入一个256字节的辅助表R

  1. 对S表进行线性填充
    即初始化S表,另,S[n] = n; (0<=n<=255)

    	for(int i = 0;i < ROOM;i++)//初始化S表
    		S[i] = i;
    
  2. 用种子密钥填充R表,如果种子密钥的长度小于R表的长度(256),则依次重复填充,直至将R表填满
    其实依次重复填充的弊端十分明显:

    例如用户输入了密钥a,那么重复填充之后R表中全部为a
    而用户输了密钥aa,那么重复填充之后R表也是全部为a
    这样显然不是一个好的结果

    还有一种做法是做Padding,即若密钥长度小于R表长度时,用固定格式的 padding来填充剩下的部分。

  3. 用R表对S表进行随机化处理
    其操作算法如下:
    ①J = 0;
    ②对于I = 0 : 255
    J = J + S[i] + R[j] mod 256;
    swap(S[i],S[j]);//交换S[i]与S[j]
    代码实现:

    	void random(unsigned char *S,std::string R,int length)//随机化S表 {
    		int i;
    		unsigned char temp;
    		unsigned char j = 0;	
    		//R表长度肯定小于等于256,注意模其长度使得不超过其下标并达到重复效果 
    		for( i = 0 ; i < ROOM ; i++ ){
    			j = j + S[i] + R[i % length];
    			temp = S[j];
    			S[j] = S[i];
    			S[i] = temp; 
    		}
    	}
    
  4. 加密解密核心功能
    生成了随机化S表之后,就可以对数据执行加密或解密算法了。
    RC4在加密解密时可以看成一个有限状态自动机,通过不断产生新的状态来产生出密钥字节。
    RC4的下一状态函数定义如下:
    ①I = 0 ,J = 0;//初始化状态
    ②I = I + 1 mod 256;
    ③J = J + S[i] mod 256
    ④swap(S[i],S[j]);//交换S[i]与S[j]
    而RC4的输出函数定义为:
    ①h = S[i] + S[j] mod 256;
    ②k = S[h];
    输出函数的输出k即产生出的密钥字节,让RC4有限状态自动机一个一个运转,便输出密钥字节序列。

    在加密时,将密钥字节k与明文字节模二加便完成了加密,解密时将密钥字节k与密文字节模二加就完成了解密。

    代码实现:

    	for( num = 0 , i = 0 , j = 0 ; num < size ; num++ ) //逐位生成序列 
    	{			
    		temp = S[i];
    		j = j + temp;
    		S[i] = S[j];
    		S[j] = temp;
    		temp = temp + S[i];
    		data[num] ^= S[temp];//data即加密或解密出的结果
    		i += 1;
    	}
    

总结

通过以上流程,RC4算法就基本完成了,而我们对一些功能和流程进行稍许加工,例如读取文件大小,满足用户加密解密的流程控制等。
最后一个小demo如下:

#include <string>
#include <stdlib.h>
#include <iostream>
#include <windows.h> 

#define ROOM 256

void random(unsigned char *S,std::string R,int length);//随机化S表 
bool Encryption(unsigned char *S,long size,char *file_name,int mode);
//加解密文件 因为是对合运算,所以只需要一个函数,用mode控制加密还是解密  
long file_size(char* filename);              //读取文件长度

int main (int argc, char *argv[])
{
	int Option;       //功能选择 
	unsigned char S[ROOM];      //S核心表 
	long file_length; //文件字节大小
	char R_temp[ROOM + 1];	//R表的备份表,预留一个'\0' 
	std::string R;    		//R表  
	
	while(1)
	{
		R.clear();        //清空数据 
		file_length = 0; 
		R_temp[0] = '\0';
		Option = -1;
		
		std::cout << "Welcome! Please choose the Option below:" << std::endl;//模式选择 
		std::cout << "input 1:encrption;" << std::endl;
		std::cout << "input 2:decrption;" << std::endl;
		std::cout << "input 0:exit." << std::endl;
		std::cin >> Option;
		
		while( std::cin.fail() )//输入出错处理 
	    {
	        std::cin.clear();   //复位标志位
	        std::cout << "数据类型不对,请重新输入:";    
	        fflush(stdin);      //清空缓冲区 
	        std::cin >> Option;        
	    }
	    
	    if(Option == 0) break;  //0则直接退出
	    else if(Option != 1 && Option != 2)
		{	
			std::cout << "输入选择有误,请重新输入:" << std::endl; //其他数字
			continue;
		}
		
		for(int i = 0;i < ROOM;i++)//初始化S表
			S[i] = i;
		
		std::cout << "请输入您的种子密钥" <<std::endl;
		fflush(stdin);             //清空之前的输入缓冲区
		std::cin.get(R_temp,ROOM); //保证忽略输入中的空格
		R = R_temp; 
		
		int R_length = R.length(); //定义length为R表中字符个数 
		random(S,R,R_length);      //随机化S表 
		
		if(Option == 1)
		{
			char file_name[16];         //定义加密文件名 
			
			std::cout << "请输入您要加密的文件" << std::endl;
			fflush(stdin);              //清空之前的输入缓冲区
			std::cin.get(file_name,16); //保证忽略输入中的空格
			file_length = file_size(file_name);//计算文件字节大小 
			
			if(Encryption(S,file_length,file_name,Option))   //加密成功 
			{
				std::cout << "退出请输入0,输入其他将回到初始界面" << std::endl; 
				std::cin >> Option; 
			}
			else											//加密失败,3s后返回主页面
			{
				std::cout << "加密失败!" << std::endl;
				for( int temp = 3 ; temp > 0 ; temp-- )
				{
					std::cout << temp << "s后将回到初始界面" << std::endl; 
					Sleep(1000);
				}
			}
		}
		else if(Option == 2)
		{
			char file_name[16];         //定义解密文件名 
			
			std::cout << "请输入您要解密的文件" <<std::endl;
			fflush(stdin);              //清空之前的输入缓冲区
			std::cin.get(file_name,16); //保证忽略输入中的空格
			file_length = file_size(file_name);//计算文件字节大小 
			
			if(Encryption(S,file_length,file_name,Option))   //解密成功 
			{
				std::cout << "退出请输入0,输入其他将回到初始界面" << std::endl; 
				std::cin >> Option; 
			}
			else											//解密失败,3s后返回主页面 
			{
				std::cout << "解密失败!" << std::endl;
				for( int temp = 3 ; temp > 0 ; temp-- )
				{
					std::cout << temp << "s后将回到初始界面" << std::endl; 
					Sleep(1000);
				}
			}
		}
		
		if(Option == 0)
			break; 
	}
	
	std::cout << "Thanks" << std::endl;
	return 0;
}

void random(unsigned char *S,std::string R,int length)//随机化S表 
{
	int i;
	unsigned char temp;
	unsigned char j = 0;	
	//R表长度肯定小于等于256,注意模其长度使得不超过其下标并达到重复效果 
	for( i = 0 ; i < ROOM ; i++ )
	{
		j = j + S[i] + R[i % length];
		temp = S[j];
		S[j] = S[i];
		S[i] = temp; 
	}
}

bool Encryption(unsigned char *S,long size,char *file_name,int mode)//加解密文件 因为是对合运算,所以只需要一个函数,用mode控制加密还是解密 
{
	FILE *pr;                      //定义读文件指针pr 
	pr = fopen(file_name,"rb");    //只读 	
	if(pr == NULL)                 //如果打开文件错误,则退出
   	{
	   	std::cout << "用户输入文件打开失败!" << std::endl;
	   	return false;
	} 
		
	FILE *pw;                      //定义写文件指针pw
	unsigned char *data;			           //存储原始文件数据,并在运算过程中充当输出序列与原序列的异或结果    
	unsigned char i,j,temp;             
	long num;
	data = (unsigned char *)malloc(size * sizeof(unsigned char));//分配内存 
	
	if(mode == 1)
		pw = fopen("encryption.txt","wb");    //模式为只写且刷新文件 
	else
		pw = fopen("decryption.txt","wb");    //模式为只写且刷新文件
		
	if(pw == NULL)                            //如果打开文件错误,则退出
   	{
	   std::cout << "输出文件时出错!" << std::endl;
	   	return false;
	} 
	fread(data,sizeof(char),size,pr);//读取二进制流(需要加/解密的文件) 
	for( num = 0 , i = 0 , j = 0 ; num < size ; num++ ) //逐位生成序列 
	{			
		temp = S[i];
		j = j + temp;
		S[i] = S[j];
		S[j] = temp;
		temp = temp + S[i];
		data[num] ^= S[temp];
		i += 1;
	}
	
	if(mode == 1)
		std::cout << "功能完成,生成encryption.txt文件" << std::endl;
	else
		std::cout << "功能完成,生成decryption.txt文件" << std::endl;
			
    fwrite(data,sizeof(unsigned char),size,pw);//写入二进制流 
    fclose(pw);//关闭文件流 
    fclose(pr);
    free(data);//释放内存 
    return true;
} 

long file_size(char *filename) //读取文件长度 
{    
	FILE *fp = fopen(filename,"r");   
	if(!fp) 
		return -1;    
	fseek(fp,0L,SEEK_END);    //利用fseek函数将指针定位在文件结尾的位置
	long size = ftell(fp);    //利用ftell函数返回指针相对于文件开头的位置,以字节计算 
	fclose(fp);        
	return size;
}
  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值