RC4-c语言实现
参考:网络安全实验——RC4的实现#include<stdio.h>
//交换
void Swap(unsigned char *S1, unsigned char *S2) {
unsigned char tmp = *S1;
*S1 = *S2;
*S2 = tmp;
}
//获取字符串长度
int my_strlen(unsigned char *S) {
int i = 0;
int res = 0;
while(*S++ != '\0') {
res += 1;
i++;
}
return res;
}
//初始化S盒
void init_S_Box(unsigned char *S, unsigned char *Key, int len) {
int i = 0, j = 0;
unsigned char T;
unsigned char tmp = 0;
for (i = 0; i < 256; i++)
{
S = i; // S_box升序置为0~255
T = Key; // T使用key来进行填充的
}
//初始置换
for (i = 0; i<256; i++)
{
j = (j + S + T) % 256; // 取一个s+k+j的索引
//交换S和S
Swap(&S, &S);
}
}
//加解密函数,因为是异或的方式所以加密也是解密
void rc4(unsigned char *S, unsigned char *Str, int len) {
//PRGA(伪随机数生成)
int i = 0, j = 0, k = 0, t = 0;
for (k = 0; k < len; k++) {
i = (i + 1) % 256;
j = (j + S) % 256;
Swap(&S, &S);
t = (S + S) % 256;
Str = Str ^ S; //以活加密
}
}
int main(){
//用无符号字符型,因为一个char的大小刚好是一字节,无符号是为了防止出现负数
unsigned char S_box = {};
unsigned char Key = { "hello world"};
unsigned char Str = "hello world!";
int len = my_strlen(Key);
printf("*************原始信息*************\n");
printf("message = %s\n", Str);
printf("Key = %s \nKey_length = %d\n\n", Key, len);
init_S_Box(S_box, Key, len); //初始化
printf("*************加密*************\n");
rc4(S_box, Str, len);//加密
printf("cipher = %s\n\n", Str);
printf("*************解密*************\n");
init_S_Box(S_box, Key, len); //初始化
rc4(S_box, Str, len);
printf("message = %s\n\n", Str);
}
这个不懂是不是字节码的问题,有些编码一个汉字是三个字节,有的又是两个,数据编码的转换有点复杂,用C语言可能会好点 本帖最后由 爱飞的猫 于 2024-3-22 08:51 编辑
> 这个不懂是不是字节码的问题,有些编码一个汉字是三个字节,有的又是两个,数据编码的转换有点复杂,用C语言可能会好点
因为编码后的汉字是多字符的。UTF-8 的话是可以通过第一个字节的高位来判断长度,一个字符可以用多个字节来表示。
```c
int utf8_chr_len(char utf8_chr) {
// 最高位未设置,单字节长度
if ((utf8_chr & 0x80) == 0) {
return 1;
}
// 之后数高位有多少个 1 直到遇到 0。目前的标准,单字符最高 6 字节,即二进制的 "1111110?"
int result = {1};
for(int shifts = 6; shifts >= 1; shifts--) {
if (utf8_chr & (1 << shifts)) {
result ++;
} else {
break;
}
}
return result;
}
// 测试案例,输出 1 和 3
printf("utf8_chr_len: %d, %d\n", utf8_chr_len('A'), utf8_chr_len("中"));
```
---
- 可以引入 `string.h`,这样就能直接使用 `strlen` 函数了。
- `i` (不包括初始化时) 和 `j` 的类型其实可以使用 `uint8_t`,超过 `255` 会自动回到 0。
- 初始化 S 表的时候的 `i` 不可以,因为要表示 `256`。
- 从 C99 标准开始(即支持使用 `//` 注释的版本开始),不需要在函数头定义所有需要的变量了,可以在需要的地方直接插入。
另外 RC4 如果需要分段加解密,则需要记录 `i` 和 `j` 的值。例如加解密一个大文件,可以分批次读取到缓冲区操作。
最后,如果真的有加解密的使用需求,建议使用成熟的、测试过的库,例如 `openssl`。
---
修改后的代码:
```c
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// 交换
void Swap(uint8_t *S1, uint8_t *S2) {
uint8_t tmp = *S1;
*S1 = *S2;
*S2 = tmp;
}
struct rc4_ctx_t {
uint8_t i;
uint8_t j;
uint8_t S;
};
// 初始化S盒
void rc4_init(struct rc4_ctx_t *ctx, const uint8_t *key, int key_len) {
ctx->i = 0;
ctx->j = 0;
for (int i = 0; i < 256; i++) {
ctx->S = i;
}
uint8_t j = {0};
for (int i = 0; i < 256; i++) {
j = j + ctx->S + key;
Swap(&ctx->S, &ctx->S);
}
}
// RC4 随机数生成与加解密
void rc4_cipher(struct rc4_ctx_t *ctx, uint8_t *Str, int len) {
for (int k = 0; k < len; k++) {
ctx->i++;
ctx->j += ctx->S;
Swap(&ctx->S, &ctx->S);
// key 就是本轮生成的字节。
uint8_t key = ctx->S + ctx->S;
// 异或处理
Str ^= key;
}
}
// 摘抄自 https://stackoverflow.com/a/29865
void hexdump(void *ptr, int buflen) {
unsigned char *buf = (unsigned char *) ptr;
int i, j;
for (i = 0; i < buflen; i += 16) {
printf("%06x: ", i);
for (j = 0; j < 16; j++)
if (i + j < buflen)
printf("%02x ", buf);
else
printf(" ");
printf(" ");
for (j = 0; j < 16; j++)
if (i + j < buflen)
printf("%c", isprint(buf) ? buf : '.');
printf("\n");
}
}
int main() {
struct rc4_ctx_t rc4 = {};
const char* key = "hello world";
char message = {"hello world!"};
printf("*************原始信息*************\n");
printf("message = %s\n", message);
printf("Key = %s \n\n", key);
printf("*************加密*************\n");
rc4_init(&rc4, (const uint8_t*)key, strlen(key));
rc4_cipher(&rc4, message, sizeof(message));
hexdump(message, sizeof(message));
printf("*************解密*************\n");
rc4_init(&rc4, (const uint8_t*)key, strlen(key));
rc4_cipher(&rc4, message, sizeof(message));
hexdump(message, sizeof(message));
printf("*************结束*************\n");
}
```
上文中的 `hexdump` 方法渲染效果如下:
![](https://imgsrc.baidu.com/forum/pic/item/2f738bd4b31c8701029aaddd617f9e2f0708ffd9.png)
爱飞的猫 发表于 2024-3-22 08:49
> 这个不懂是不是字节码的问题,有些编码一个汉字是三个字节,有的又是两个,数据编码的转换有点复杂, ...
感谢指点{:1_893:}
页:
[1]