本文主要是了解RC4和清楚RC4步骤。重点是算法步骤。
了解RC4 #
RC4(Rivest Cipher 4)是一种流加密算法,由Ron Rivest在1987年设计。 它通过生成密钥流字节与明文进行异或操作来实现加密,它加解密使用相同的密钥,因此也属于对称加密算法。 RC4使用可变长度的密钥,长度范围为1到256个字节。
RC4算法主要代码是如何生成密钥流。 分为两步:
- 初始化阶段 KSA(Key-Scheduling Algorithm)
- 密钥流生成阶段 PRGA (pseudo-random generation algorithm)
KSA主要步骤如下:
- 初始化 S 盒:创建一个256长度的数组
S
,初始化为S[i] = i
- 初始化临时数组 T进行密钥填充:如果RC4密钥(key)长度为key_len,密钥重复填充到长度为 256 的数组
T
中,T[i] = key[ i % key_len]
- 打乱 S 盒:使用密钥对 S 盒进行置换。 伪代码:
for i from 0 to 255:
S[i] = i
T[i] = key[i % key_len]
j = 0
for i from 0 to 255:
j = (j + S[i] + T[i]) % 256
swap(S[i], S[j])
PRGA主要步骤如下: 密钥流生成阶段的目的是生成伪随机的密钥流字节,用于与明文或密文进行异或操作。 伪代码如下:
i = 0, j = 0
while (需要生成密钥流字节长度):
i = (i + 1) % 256
j = (j + S[i]) % 256
swap(S[i], S[j])
k = S[(S[i] + S[j]) % 256]
输出 k
k就是密钥流字节。这是一个字节。这个字节用于和明文异或。
我生成一个数组keystream存储密钥流字节,这个keystream应该是和明文长度一致的。加解密的时候按字节进行异或。
我写的简单代码。
#include <stdio.h>
#include <string.h>
// 将字符数组转换为十六进制格式并打印
void charArrayToHex(const unsigned char *array, int length) {
for (int i = 0; i < length; i++) {
printf("%02X ", array[i]);
}
printf("\n");
}
int main() {
// 密钥和明文
unsigned char key[] = "secret";
unsigned char plaintext[] = "flag{Congratulation!}";
// 计算密钥和明文的长度
int key_len = strlen((char *)key);
int plaintext_len = strlen((char *)plaintext);
// 输出密钥和明文信息
printf("加密明文: %s\n", plaintext);
printf("密钥: %s\n", key);
printf("密钥长度: %d\n", key_len);
printf("明文长度: %d\n", plaintext_len);
// 初始化变量
unsigned char ciphertext[256] = {0}; // 密文
unsigned char decryptedtext[256] = {0}; // 解密后的明文
unsigned char S[256]; // S盒
unsigned char T[256]; // 临时数组
unsigned char keystream[256] = {0}; // 密钥流
// KSA阶段(Key-Scheduling Algorithm)
printf("KSA阶段...\n");
for (int i = 0; i < 256; i++) {
S[i] = i; // 初始化S盒
T[i] = key[i % key_len]; // 用密钥填充T数组
}
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + S[i] + T[i]) % 256; // 打乱S盒
unsigned char temp = S[i];
S[i] = S[j];
S[j] = temp;
}
printf("KSA阶段完成!\n");
// PRGA阶段(Pseudo-Random Generation Algorithm)
printf("PRGA阶段...\n");
int i = 0;
j = 0;
for (int k = 0; k < plaintext_len; k++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
unsigned char temp = S[i];
S[i] = S[j];
S[j] = temp;
keystream[k] = S[(S[i] + S[j]) % 256]; // 生成密钥流
}
printf("PRGA阶段完成!\n");
// 加密阶段
printf("加密阶段...\n");
for (int k = 0; k < plaintext_len; k++) {
ciphertext[k] = plaintext[k] ^ keystream[k]; // 异或操作加密
}
printf("加密完成! 密文: ");
charArrayToHex(ciphertext, plaintext_len); // 输出密文的十六进制
// 解密阶段
printf("解密阶段...\n");
for (int k = 0; k < plaintext_len; k++) {
decryptedtext[k] = ciphertext[k] ^ keystream[k]; // 异或操作解密
}
printf("解密完成! 明文: %s\n", decryptedtext); // 输出解密后的明文
printf("明文 HEX: ");
charArrayToHex(decryptedtext, plaintext_len); // 输出明文的十六进制
return 0;
}
但是我这代码有个缺陷,keystream数组长度只有256。明文超过256应该就出毛病了。理论应该是和明文长度一致的。 可以不用keystream数组,直接在PRGA阶段对明文进行加解密。
我这份代码只是展示了最简单的流程,没有使用函数封装。
再来看一份DeepSeek的代码:
#include <stdio.h>
#include <string.h>
// RC4 上下文结构体
typedef struct {
unsigned char S[256]; // S盒
unsigned char T[256]; // 临时数组
int i, j; // 状态变量
} RC4_CTX;
// 初始化 RC4 上下文
void rc4_init(RC4_CTX *ctx, const unsigned char *key, int key_len) {
int i, j = 0;
// 初始化 S 盒
for (i = 0; i < 256; i++) {
ctx->S[i] = i;
ctx->T[i] = key[i % key_len];
}
// 打乱 S 盒
for (i = 0; i < 256; i++) {
j = (j + ctx->S[i] + ctx->T[i]) % 256;
// 交换 S[i] 和 S[j]
unsigned char temp = ctx->S[i];
ctx->S[i] = ctx->S[j];
ctx->S[j] = temp;
}
// 初始化状态变量
ctx->i = 0;
ctx->j = 0;
}
// 生成密钥流字节
unsigned char rc4_keystream_byte(RC4_CTX *ctx) {
ctx->i = (ctx->i + 1) % 256;
ctx->j = (ctx->j + ctx->S[ctx->i]) % 256;
// 交换 S[ctx->i] 和 S[ctx->j]
unsigned char temp = ctx->S[ctx->i];
ctx->S[ctx->i] = ctx->S[ctx->j];
ctx->S[ctx->j] = temp;
// 计算密钥流字节
unsigned char k = ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256];
return k;
}
// RC4 加密/解密函数
void rc4_crypt(RC4_CTX *ctx, const unsigned char *input, unsigned char *output, int len) {
for (int i = 0; i < len; i++) {
// 生成密钥流字节并与输入异或
output[i] = input[i] ^ rc4_keystream_byte(ctx);
}
}
int main() {
// 示例密钥和明文
unsigned char key[] = "secret_key";
unsigned char plaintext[] = "Hello, RC4!";
int len = strlen((char *)plaintext);
// 加密后的密文和解密后的明文
unsigned char ciphertext[256];
unsigned char decryptedtext[256];
// 初始化 RC4 上下文
RC4_CTX ctx;
rc4_init(&ctx, key, strlen((char *)key));
// 加密
rc4_crypt(&ctx, plaintext, ciphertext, len);
printf("Ciphertext: ");
for (int i = 0; i < len; i++) {
printf("%02x ", ciphertext[i]);
}
printf("\n");
// 重新初始化 RC4 上下文(因为状态变量已经改变)
rc4_init(&ctx, key, strlen((char *)key));
// 解密
rc4_crypt(&ctx, ciphertext, decryptedtext, len);
decryptedtext[len] = '\0'; // 添加字符串结束符
printf("Decrypted text: %s\n", decryptedtext);
return 0;
}
文章有错误欢迎在评论区指正。 有疑问也可以在评论区讨论。