RC4加密
RC4加密
一. 介绍
在密码学中,RC4(来自Rivest Cipher 4的缩写)是一种流加密算法(基于bit进行加密) ,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。所谓对称加密,就是加密和解密的过程是一样的。RC4是有线等效加密(WEP)中采用的加密算法,也曾经是TLS可采用的算法之一。
RC4已经成为一些常用的协议和标准的一部分,如1997年的WEP和2003/2004年无线卡的WPA; 和1995年的SSL,以及后来1999年的TLS。让它如此广泛分布和使用的主要因素是它不可思议的简单和速度,不管是软件还是硬件,实现起来都十分容易。
二. 加密过程
1. 初始化s表
- s表大小为256个字节,对s表进行顺序填充,从0到255。
- 用种子密钥填充k表(256个字节),种子密钥的长度随意,循环填充。
- 用K表对S表进行初始非线性置换。这里其实就说初始化s表的核心步骤。
int i = 0;
for (i = 0; i < 256; i++) {
S[i] = i;//填充S表
K[i] = puc_key[i % key_length];//填充K表
}
for (i = 0; i < 256; i++) {
j = (j + S[i] + K[i]) % 256;
swap_uchar(&S[i], &S[j]); //初始化S表
}
2. 生成密钥流
为每个待加密字符生成伪随机数,用于进行异或。
int i = 0;
int j = 0;
int t = 0;
unsigned long k = 0;
for (k = 0; k < ul_data_length; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap_uchar(&S[i], &S[j]);
t = (S[i] + S[j]) % 256;
puc_key_stream[k] = S[t];
}
三. 解密过程
由于是对称加密,所以可以直接模拟执行得到一个相同的S表,在得到S表之后再得到相同的密钥流,利用密钥流对结果字符进行异或即可得到原始数据。
整体步骤:
#include<stdio.h>
#include<string.h>
#define SBOX_LEN 256
#define rc4_encrypt rc4_crypt
#define rc4_decrypt rc4_crypt
static inline void swap_uchar(unsigned char *puc_x, unsigned char *puc_y)
{
*puc_x = *puc_x ^ *puc_y;
*puc_y = *puc_x ^ *puc_y;
*puc_x = *puc_x ^ *puc_y;
}
/*
* 利用Key生成S盒
* the Key-Scheduling Algorithm
*/
static void rc4_ksa(unsigned char *puc_sbox, unsigned char *puc_key, int key_length)
{
int i = 0;
int j = 0;
char tmp[SBOX_LEN] = {0};
for (i = 0; i < SBOX_LEN; i++) {
puc_sbox[i] = i;
tmp[i] = puc_key[i % key_length];
}
for (i = 0; i < SBOX_LEN; i++) {
j = (j + puc_sbox[i] + tmp[i]) % SBOX_LEN;
swap_uchar(&puc_sbox[i], &puc_sbox[j]); //交换puc_sbox[i]和puc_sbox[j]
}
}
/**
* 利用S盒生成密钥流
* The pseudo-random generation algorithm(PRGA)
*/
static void rc4_prga(unsigned char *puc_sbox, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
int i = 0;
int j = 0;
int t = 0;
unsigned long k = 0;
for (k = 0; k < ul_data_length; k++) {
i = (i + 1) % SBOX_LEN;
j = (j + puc_sbox[i]) % SBOX_LEN;
swap_uchar(&puc_sbox[i], &puc_sbox[j]);
t = (puc_sbox[i] + puc_sbox[j]) % SBOX_LEN;
/* 为了更清晰理解rc4算法流程,此处保存keystream,不直接进行XOR运算 */
puc_key_stream[k] = puc_sbox[t];
}
}
/* 加解密 */
void rc4_crypt(unsigned char *puc_data, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
unsigned long i = 0;
/* 把PRGA算法放在加解密函数中可以不需要保存keystream */
for (i = 0; i < ul_data_length; i++) {
puc_data[i] ^= puc_key_stream[i];
}
}
int main(int argc, char *argv[])
{
unsigned char sbox[SBOX_LEN] = {0};
char key[SBOX_LEN] = {"abcdefghijklmnopqrstuvwxyz"}; //秘钥内容随便定义
char data[512] = "lsRJ@.0 lvfvr#9527";
unsigned char puc_keystream[512] = {0};
unsigned long ul_data_length = strlen(data);
printf("key=%s, length=%d\n\n", key, strlen(key));
printf("Raw data string:%s\n", data);
printf("Raw data hex:\n");
//hexdump(data, ul_data_length);
/* 生成S-box */
rc4_ksa(sbox, (unsigned char *)key, strlen(key));
/* 生成keystream并保存,S-box也会被更改 */
rc4_prga(sbox, puc_keystream, ul_data_length);
printf("S-box final status:\n");
//hexdump(sbox, sizeof(sbox));
printf("key stream:\n");
//hexdump(puc_keystream, ul_data_length);
/* 加密 */
rc4_encrypt((unsigned char*)data, puc_keystream, ul_data_length);
printf("cipher //hexdump:\n");
//hexdump(data, ul_data_length);
/* 解密 */
rc4_decrypt((unsigned char*)data, puc_keystream, ul_data_length);
printf("decypt data:%s\n", data);
return 0;
}