目录

解析 RC4 加密算法(C语言、python):

RC4加密算法是一种对称加密算法:

加密(解密)原理:

RC4算法中的几个关键变量:

RC4代码介绍:

rc4初始化介绍:

包含三个参数:

RC4加密:

包含三个参数:

代码实现:(已注释)

C语言代码:

Python代码:

三丶RC4的逆向小技巧

1:逆向特征

2:魔改RC4


解析 RC4 加密算法(C语言、python):

RC4加密算法是一种对称加密算法:

对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。

RC4于1987年提出,和DES算法一样,是一种对称加密算法,也就是说使用的密钥为单钥(或称为私钥)。但不同于DES的是,RC4不是对明文进行分组处理,而是字节流的方式依次加密明文中的每一个字节,解密的时候也是依次对密文中的每一个字节进行解密。

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

加密(解密)原理:

RC4由伪随机数生成器和异或运算组成。RC4的密钥长度可变,范围是[1,255]。RC4一个字节一个字节地加解密。给定一个密钥,伪随机数生成器接受密钥并产生一个S盒。S盒用来加密数据,而且在加密过程中S盒会变化。

由于异或运算的对合性,RC4加密解密使用同一套算法。

RC4算法中的几个关键变量:

1:S-Box 也就是所谓的S盒,是一个256长度的char型数组,每个单元都是一个字节,算法运行的任何时候,S都包括0-255的8比特数的排列组合,只不过值的位置发生了变换。

2:密钥K char key[256] 密钥的长度keylen与明文长度、密钥流的长度没有必然关系

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

RC4代码介绍:

rc4初始化介绍:

1:初始化存储0-255字节的Sbox(其实就是一个数组)

2:填充key到256个字节数组中称为Tbox(你输入的key不满256个字节则初始化到256个字节)

3:交换s[i]与s[j] i 从0开始一直到255下标结束. j是 s[i]与T[i]组合得出的下标。

包含三个参数:

参数1是一个256长度的char型数组,定义为: unsigned char sBox[256];

参数2是密钥,其内容可以随便定义:char key[256];

参数3是密钥的长度,Len = strlen(key);

RC4加密:

RC4加密其实就是遍历数据,将数据与sbox进行异或加密,而在此之前还需要交换一次sbox的数据

交换完之后 再把s[i] + s[j]的组合当做下标再去异或.

包含三个参数:

参数1是上边rc4_init函数中,被搅乱的S-box;

参数2是需要加密的数据data;

参数3是data的长度.

代码实现:(已注释)

C语言代码:

#include<stdio.h>

/*
程序实现时,需要注意的是,状态向量数组S和临时向量数组T
的类型应设为unsigned char,而不是char。因为在一些机器
下,将char默认做为signed char看待,在算法中计算下标i,j的
时候,会涉及char转int,如果是signed的char,那么将char的8
位拷贝到int的低8位后,还会根据char的符号为,在int的高位补
0或1。由于密钥是随机产生的,如果遇到密钥的某个字节的高
位为1的话,那么计算得到的数组下标为负数,就会越界。
*/
typedef struct _RC4INFO
{
	unsigned char s_box[256];
	unsigned char t_box[256];
}RC4_INFO,*PRC4_INFO;			//定义 RC4 中要用到的 S-Box 和临时向量 T,封装在结构体中并给正常别名和指针别名。 


/*
初始化函数 需要传入key 以及 keylen
主要有几个步骤
1.初始化Sbox
2.将key填充到Tbox中
3.组合sbox[i] 与 tbox[i] 然后进行交换
*/
void rc4_init(PRC4_INFO prc4,unsigned char key[],unsigned int keylen)
{
	int i=0;
	int j=0;
	unsigned char tmp;
	if(prc4==NULL)
	{
		return;
	}
	
	/*
	初始化存储0-255字节的Sbox(其实就是一个数组)
	填充key到256个字节数组中称为Tbox(你输入的key不满256个字节则初始化到256个字节)
	*/ 
	for(i=0;i<256;i++)
	{
		prc4->s_box[i] = i;
		prc4->t_box[i] = key[i % keylen];	//如果密钥的长度是256字节,就直接把密钥的值赋给k,否则,轮转地将密钥的每个字节赋给k 
	}
	
	//交换s[i]与s[j]   i 从0开始一直到255下标结束. j是 s[i]与T[i]组合得出的下标
	for(i=0;i<256;i++)
	{
		j=(j+prc4->s_box[i]+prc4->t_box[i])%256;
		//开始交换
		tmp=prc4->s_box[i];
		prc4->s_box[i]=prc4->s_box[j];
		prc4->s_box[j]=tmp;
	}
 } 

/*
RC4加密其实就是遍历数据,将数据与sbox进行异或加密,而在此之前还需要交换一次sbox的数据
交换完之后 再把s[i] + s[j]的组合当做下标再去异或. 
*/
void rc4_crypt(unsigned char data[],unsigned int datalen,unsigned char key[],unsigned int keylen)	//参数分别是要加密的数据、要加密的数据长度、加密数据所用的Key、加密数据所用的key长度
{
	int dn=0;	//data[n]的意思
	int i=0;
	int j=0;	//i j分别用于交换sbox[i] 和 sbox[j]
	int t=0;	//t = s[i] +s[j]
	unsigned char tmp;
	
	RC4_INFO rc4;		//这里定义前面的结构题 
	rc4_init(&rc4,key,keylen);		//在加密函数中调用初始化函数,就省去了其它代码中出现的要保存初始化 sBox 的现象了.
	
	for(dn=0;dn<datalen;dn++)
	{
		//i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。
		i=(i+1)%256;
		j=(j+rc4.s_box[i])%256;
		
		//交换 s_box[i] 和 s_box[j]
		tmp=rc4.s_box[i];
		rc4.s_box[i] = rc4.s_box[j];
		rc4.s_box[j] = tmp;
		
		//交换完之后 再把s[i] + s[j]的组合当做下标再去异或.
		t = (rc4.s_box[i] + rc4.s_box[j]) % 256;
		data[dn] ^= rc4.s_box[t];
	 } 
}

void EntryBuffer(unsigned char data[],unsigned int datalen)
{
	unsigned char key[]="pjrHeldsadf";
	rc4_crypt(data,datalen,key,sizeof(key)/sizeof(key[0]));
}

int main()
{
	char Hell[] = "黄河远上白云间";
    printf("加密前:pData=%s\n\n", Hell);
    EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0])); //加第一次调用就是加密 
    printf("加密后:pData=%s\n\n", Hell);
    EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0])); //由于异或运算的对合性,RC4加密解密使用同一套算法。
    printf("解密后:pData=%s\n\n", Hell);
    return 0;
}

Python代码:

# -*- coding: utf-8 -*-
import base64

def get_message():
	print("输入你的信息: ")
	s=input()
	return s

def get_key():
	print("输入你的密钥: ")
	key=input()
	if key=='':
		key="不要输入空的 key 值"
	return key

def init_box(key):
	"""
	S盒
	"""
	s_box=list(range(256))	#我这里没管秘钥小于256的情况,小于256应该不断重复填充即可,这里完成了 C 实现中的 for(i=0;i<256;i++) prc4->s_box[i] = i;
	j=0
	for i in range(256):
		j=(j+s_box[i] + ord(key[i % len(key)])) % 256	#这里把 C 实现中的 prc4->t_box[i] = key[i % keylen];和j=(j+prc4->s_box[i]+prc4->t_box[i])%256;合并在了一起。
		s_box[i],s_box[j] = s_box[j],s_box[i]
	#print(type(s_box)) #可以输出 s_box 来看是否随机混乱的
	return s_box

def ex_encrypt(plain,box,mode):
	"""
    利用PRGA生成秘钥流并与密文字节异或,加解密同一个算法
    """
	if mode == '2':
		while True:
			c_mode=input("输入你的解密模式:base64 or ordinary\n")
			if c_mode == 'base64':
				plain=base64.b64decode(plain)
				plain=bytes.decode(plain)				#因为返回的是解码过的  bytes,所以需要再用 decode 解码成字符串。
				break
			elif c_mode == 'ordinary':
				break
			else:
				print("输入不合法,请重新输入")
				continue
	
	res=[]
	i=j=0
	for s in plain:						#与 C 实现无太大差异
		i=(i+1)%256
		j=(j+box[i])%256
		box[i],box[j]=box[j],box[i]
		t=(box[i]+box[j]) % 256
		k=box[t]
		res.append(chr(ord(s)^k))

	cipher="".join(res)
    #print(cipher)

#根据选择进行输出,至于是明文还是密文得看用户决定
	if mode == '1':
        # 化成可视字符需要编码
		print("加密后的输出(没经过任何编码)")
		print(cipher)
        # base64的目的也是为了变成可见字符
		print("base64后的编码")
		print(str(base64.b64encode(cipher.encode('utf-8')),'utf-8'))
	if mode == '2':
		print("解密后的密文")
		print(cipher)

def get_mode():
	print("请选择加密或者解密")
	print("1.Encrypt")
	print("2.Decrypt")

	mode = input()

	if mode == '1':			#加密解密虽同源,但是由于不能直接用 =='1' or '2',所以还是得分开写
		message = get_message()
		key = get_key()
		box = init_box(key)
		ex_encrypt(message,box,mode)
	elif mode == '2':			#由于异或运算的对合性,RC4加密解密使用同一套算法。
		message = get_message()
		key = get_key()
		box = init_box(key)
		ex_encrypt(message,box,mode)
	else:
		print("输入有误! ")

if __name__ == '__main__':
	while True:
		get_mode()

三丶RC4的逆向小技巧

1:逆向特征

首先根据原理我们可以看到会初始化一个256字节的数组

其次会将一个key也填充到数组中

函数的话大概率都是两个参数,一个是key 一个是keylen

2:魔改RC4

其实RC4魔改还是比较难的,稍有改变,整个算法就完全不同了。因此,大多数赛题将rc4与其他算法进行组合来加密flag

常见变化位置:

密钥经过上一步的其他加密后传入

s盒内部数据固定

rc4加密后数据进行重加密

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐