RE-RC4加密分析

RC4加密原理

流密码RC4

在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种串流加密法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法
整体加密流程:
在这里插入图片描述
RC4的加密核心主要是一步异或(明文与秘钥流进行逐字节异或),主要算法在秘钥流的生成方面。首先初始化一个S盒(一个无符号字符型,大小为256的数组),根据秘钥key(可自定,也可用伪随机数生成)生成一个T向量(同样为无符号字符型256大小)

	unsigned char s[256];
	unsigned char t[256];
	for(int i=0;i<256;i++){ //初始化S盒和t向量 
		s[i]=i;
		t[i]=key[i%keylen]; //秘钥key及其长度
	}

通过T向量打乱S盒

	int j = 0;
	for(int i=0;i<256;i++){
		
		j=(j+s[i]+t[i])%256;
		
		swap(s[i],s[j]);  //根据t向量打乱s盒 ,交换是s[i]和是[j]  循环256次 S盒内大部分顺序被打乱
	}

下一步,生成秘钥流,可以将秘钥流与明(密)文直接异或 ,或者存放到一个大小为mlen的无符号字符型数组中。

 unsigned char k[mlen];//保存秘钥流,或者直接进行异或 
	
	int i=0; j=0; int tmp;
	
	for(int index=0;index<mlen;index++){   //生成与明文长度一致的秘钥流 
		
		i=(i+1)%256;   //明文长度可能超过256,不能直接i++
		j=(j+s[i])%256;
		swap(s[i],s[j]);
		
		tmp=(s[i]+s[j])%256;
		
		k[index]=s[tmp];//保存秘钥 
	} 

最后将生成的秘钥流与明文进行逐字节异或

for(i=0;i<mlen;i++)
	    m[i]=m[i]^k[i];//主要进行了一步异或

分析上述过程,在生成秘钥流的过程中只有KEY参与,所以相同key生成的秘钥流一致,而最终只是秘钥流与明文进行了逐字节异或,根据异或的特征,故加密和解密公用一套算法。

同时,RC4加密的安全性与key的长度也有着关系,key太短,则容易被爆破,key太长(>256)则多余字节根本没有参与加密,一般key的选择在128字节左右就够用并且是安全的。

整体流程代码:

int main(){  //加密的主函数
	unsigned char flag[]="需要加密的数据";
	char key[]="秘钥";
    RC4_encrypt(flag,key,sizeof(flag)-1,strlen(key));
    for(int i=0;i<sizeof(flag)-1;i++)
    cout<<(int)flag[i]<<",";
	return 0;
} 

void RC4_encrypt(unsigned char *m, char *key,int mlen,int keylen){
	unsigned char s[256];
	unsigned char t[256];
	for(int i=0;i<256;i++){ //初始化s和t向量 
		s[i]=i;
		t[i]=key[i%keylen];
	}
	
	int j = 0;
	for(int i=0;i<256;i++){
		
		j=(j+s[i]+t[i])%256;
		
		swap(s[i],s[j]);  //根据t向量打乱s盒 
	}
	
	unsigned char k[mlen];//保存秘钥流,或者直接进行异或 
	
	int i=0; j=0; int tmp;
	
	for(int index=0;index<mlen;index++){   //生成与明文长度一致的秘钥流 
		
		i=(i+1)%256;
		j=(j+s[i])%256;
		swap(s[i],s[j]);
		
		tmp=(s[i]+s[j])%256;
		
		k[index]=s[tmp];//保存秘钥 
	} 
	
	for(i=0;i<mlen;i++)
	{    
	   m[i]=m[i]^k[i];//主要进行了一步异或,加密的逆过程就是解密 
	}
	
}

c++/c中int和char类隐式转换十分方便(通过ASCII码),这样方便统计长度和进行格式转换。

C++代码中问题解决

在代码实现中可能的问题:

为什么要用unsigned char,与char同为 1个字节大小,但是整数的范围不同 unsigned char的范围才是我们要的0~255 而 单纯char的话第一位为符号位 所以为 -128 到 127,这里最好要用无符号char

另外就是在主函数中的调用:

	unsigned char flag[]={109,0,85,138,95,219,19,35,59,20,97,8,73,15,81,201,242};
	char key[]="keykeykey";

	RC4_encrypt(flag,key,sizeof(flag),strlen(key));
    cout<<flag<<endl;
	return 0;

在解密过程中,密文数组中可能会有0,根据strlen的原理是遇到‘\0’就停止可能出现错误,并且密文数组定义为了unsigned char类型,不能用strlen函数来判断长度,所以这里用sizeof来代替,当然key数组最好也定义为unsigned char类型,这里便不再展示。
如果是{xx,xx}则sizeof表示正常大小,如果是“aaaa”,则sizeof表示长度为5(多了一个0)注意细节。

IDA逆向分析

完善主函数,生成的EXE文件拖入IDA64中分析。
在这里插入图片描述简单写了一个对输入进行一个RC4加密之后和v7(如果IDA给v7开辟的int型数组,注意小端序)串进行比较,key直接给了。
在这里插入图片描述初始化S盒和T盒与变异的RC4算法

RC4算法魔改

一般魔改的RC4主要是S盒和T盒的初始化方面,正常的初始化S盒是0-255 而T盒则是key循环填进去
曾经遇到过将S盒的初始化改为255-i,解密只需要以相同初始化方式即可

swap交换函数内部
在这里插入图片描述
接下来便是打乱S盒和生成秘钥流。
在这里插入图片描述在这里插入图片描述v8=v6有点诡异,但看他们在栈中的空间,v8是rsp+228h v6是rsp+20h,差值是208h为520故,v8和v6也是没有交集的空间,其余则是生成秘钥流和进行异或了。

IDA中的变量分配问题

在这里插入图片描述
在这里插入图片描述可知IDA反编译对数组的处理,一般开辟的空间要比原空间大,并且可能产生一些不同,比如v7也就是secret,我们自定义的是17大小,而开辟了32个大小,并且unsigned char型变成了char型,所以v7看起来会有一些负数值。同样,key数组的大小和flag数组的大小都开辟的了大了许多,但参与运算的数量并没有变化。

源代码

实现上可能有些不足或缺陷,还望指正。

#include<iostream>
#include<cstring>
using namespace std;
void swap(int &a,int &b); //flag{This_is_RC4}
void RC4_encrypt(unsigned char *m, char *key,int mlen,int keylen);
int main(){
	unsigned char flag[18];
	cout<<"tell me your secret:";
	cin>>flag; 
	int len=17;
	char key[]="keykeykey";
    RC4_encrypt(flag,key,len,strlen(key));
    unsigned char secret[17]={109,0,85,138,95,219,19,35,59,20,97,8,73,15,81,201,242};
	for(int i=0;i<len;i++){
		if(secret[i]!=flag[i]){
			cout<<"try again!"<<endl;
			return 0;
		}
	}
	cout<<"you get it!"<<endl;  
	return 0;
} 

void swap(int &a,int &b){
	int temp;
	temp=a;
	a=b;
	b=temp;
}

void RC4_encrypt(unsigned char *m, char *key,int mlen,int keylen){
	unsigned char s[256];
	unsigned char t[256];
	for(int i=0;i<256;i++){ //初始化s和t向量 
		s[i]=i;
		t[i]=key[i%keylen];
	}
	
	int j = 0;
	for(int i=0;i<256;i++){
		
		j=(j+s[i]+t[i])%256;
		
		swap(s[i],s[j]);  //根据t向量打乱s盒 
	}
	
	unsigned char k[mlen];//保存秘钥流,或者直接进行异或 
	
	int i=0; j=0; int tmp;
	
	for(int index=0;index<mlen;index++){   //生成与明文长度一致的秘钥流 
		
		i=(i+1)%256;
		j=(j+s[i])%256;
		swap(s[i],s[j]);
		
		tmp=(s[i]+s[j])%256;
		
		k[index]=s[tmp];//保存秘钥 
	} 
	
	for(i=0;i<mlen;i++)
	{    
	   m[i]=m[i]^k[i];//主要进行了一步异或,加密的逆过程就是解密 
	}
	
}

参考

流密码和RC4:https://www.cnblogs.com/block2016/p/5601925.html
密码学基础和RC4:https://www.jianshu.com/p/f22a98eb437f
维基百科-RC4

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值