当前位置:   article > 正文

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

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;
    
    • 1
    • 2
  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; 
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

总结

通过以上流程,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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/600339
推荐阅读
相关标签
  

闽ICP备14008679号