2015-01-18-Rc4
Table of Contents
1 前言
这段时间弄了一下加密算法RC4,一开始感觉这个算法很简单,就试着弄了一下,结果自己写了一下代码,调试了很久,都没通过,又用了网上的开源的代码,结果还是调试不通过,后来经过别人的提醒,才发现自己错在了那里,事后一想感觉自己太不应该了,所以想写一篇blog出来,总结一下自己为什么会出现这么幼稚的问题,再顺便把RC4算法的实现记录一下。
2 RC4算法介绍
关于RC4算法的历史的介绍,这里不再多介绍了,如果你感兴趣,可以点这里维基百科-rc4
2.1 算法原理的介绍
RC4算法有下面几个部分构成
- Sbox(S盒):256Byte(256个字节),Sbox是unsigned char类型的数据 该算法的关键的数据结构,构成加密操作的一个不可获取的结构.
- key(秘钥):长度范围是[1 Byte,255 Byte]. 加密数据输入的秘钥,任何加密数据里面都有秘钥的存在.为了是该算法的加密行更好一点,可以使秘钥长度大一点,当秘钥长度大于128位,就无法使用暴力破解的方式进行破解.
- inputByte/outputByte(要加密的数据/要解密的数据) 该算法的特殊之处就在于加密和解密使用同一个算法,所以输入的是明文,输出的就是密文,输入的密文,输出的就是明文.
该算法的核心就是两部分一个是伪随机数生成器,一个是异或操作.所以在我们实现的过程中,只需要实现这两个部分就可以了.
2.2 伪代码实现
该算法首先使用伪代码实现以下,然后再后边在使用c语言将伪代码实现出来.下面就是具体的伪代码的实现
- 构造Sbox 作为RC4算法的最重要的部分,该算法的第一部分就是构造Sbox,实现的伪代码如下所示
for i from 0 to 255 S[i] := i endfor j := 0 for( i=0 ; i<256 ; i++) j := (j + S[i] + key[i mod keylength]) % 256 swap values of S[i] and S[j] endfor
构造Sbox的第一步就是先将初始化长度为256的sbox,然后为了制造伪随机数,使用输入的key,Sbox[i]和j的值(每次都会改变),这三个项结合在一起,将初始化后的Sbox打乱.
- 对数据进行亦或运算 伪代码的实现如下所示:
i := 0 j := 0 while GeneratingOutput: i := (i + 1) mod 256 // 1 j := (j + S[i]) mod 256 // 2 swap values of S[i] and S[j] //3 k := inputByte ^ S[(S[i] + S[j]) % 256] //4 output K endwhile
对数据进行亦或操作主要在代码4处进行,代码1,2,3处的代码主要进行的工作也是对sbox进行处理,从这里看出,该算法的核心就是sbox.
3 算法实现
rc4的实现,网上有很多的版本,而且别的blog中,也有c和c++的版本实现.本人参考了一下,发现网上的c++版本的RC4实现,比较繁琐.C代码的实现主要是在Windows平台上,移植性差了点.所以我就想实现一个Linux平台上的RC4.本博客中,使用的是开源项目的代码,该代码的链接:点这里
一开始我是自己实现的上面的算法,但是发现自己实现的和开源组织的代码还是有一定差距的,所以这里直接使用开源的代码,并且学习一下别人的实现.
代码如下:
#ifndef _SYS_CRYPTO_RC4_RC4_H_ #define _SYS_CRYPTO_RC4_RC4_H_ struct rc4_state { u_char perm[256]; u_char index1; u_char index2; }; extern void rc4_init(struct rc4_state *state, const u_char *key, int keylen); extern void rc4_crypt(struct rc4_state *state, const u_char *inbuf, u_char *outbuf, int buflen); #endif
#include <sys/types.h> #include <crypto/rc4/rc4.h> static __inline void swap_bytes(u_char *a, u_char *b) { u_char temp; temp = *a; *a = *b; *b = temp; } /* * Initialize an RC4 state buffer using the supplied key, * which can have arbitrary length. */ void rc4_init(struct rc4_state *const state, const u_char *key, int keylen) { u_char j; int i; /* Initialize state with identity permutation */ for (i = 0; i < 256; i++) state->perm[i] = (u_char)i; state->index1 = 0; state->index2 = 0; /* Randomize the permutation using key data */ for (j = i = 0; i < 256; i++) { j += state->perm[i] + key[i % keylen]; swap_bytes(&state->perm[i], &state->perm[j]); } } /* * Encrypt some data using the supplied RC4 state buffer. * The input and output buffers may be the same buffer. * Since RC4 is a stream cypher, this function is used * for both encryption and decryption. */ void rc4_crypt(struct rc4_state *const state, const u_char *inbuf, u_char *outbuf, int buflen) { int i; u_char j; for (i = 0; i < buflen; i++) { /* Update modification indicies */ state->index1++; state->index2 += state->perm[state->index1]; /* Modify permutation */ swap_bytes(&state->perm[state->index1], &state->perm[state->index2]); /* Encrypt/decrypt next byte */ j = state->perm[state->index1] + state->perm[state->index2]; outbuf[i] = inbuf[i] ^ state->perm[j]; } }
该算法的比较有特色的地方就是将Sbox直接封装成一个结构体,而不是想我自己一样,直接就是一个长度为256的数组中.其余的就和伪代码一样了.
4 算法的优缺点
- 优点:
- 容易实现,不用依赖第三方库.
- 算法的输入和输出可以是同一个文件,也就是说可以在原地进行加密和解密.
- 根据目前的分析结果,没有任何的分析对于密钥长度达到128位的RC4有效,所以,RC4是目前最安全的加密算法之一.
- 缺点:
- 由于RC4算法加密是采用的xor,所以,一旦子密钥序列出现了重复,密文就有可能被破解.于如何破解xor加密,请参看Bruce Schneier的Applied Cryptography一书的1.4节Simple XOR.
5 需要注意的地方
在需要注意的这个地方就是在调用的时候,一定要注意构造Sbox,一开始在加密的时候,要初始化Sbox,在解密中,也要 初始化Sbox .我就是在解密的时候没有初始化Sbox,所以在解密的时候,就是不正确.
原因分析:该算法的加解密都是基于Sbox,当在加密的过程当中,对Sbox,进行初始化,然后对数据进行加密,会改变Sbox中数据的顺序.所以进行解密的时候,要重新初始化Sbox,在进行解密,这意味着,只要秘钥一样,每次初始化的Sbox,都是一样的.这个可以从算法中看出来.调用的代码如下所示:
int main(int argc, char* argv[]){ int dataLength = 8; int keyLength = 8; const unsigned char dataStream[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; printf("before\n"); for (int i = 0; i < dataLength ; i++) { printf("%x,",dataStream[i]); } printf("\n"); unsigned char encryp[dataLength]; unsigned char decryp[dataLength]; unsigned char key[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; struct rc4_state state; rc4_init(&state, key, keyLength);// this code is very important rc4_crypt(&state, dataStream, encryp, dataLength); printf("\nencrypt\n"); for (int i = 0; i < dataLength ; i++) { printf("%x,",encryp[i]); } printf("\nafter \n"); rc4_init(&state, key, keyLength);// this code is very important rc4_crypt(&state, encryp, decryp, dataLength); for (int i = 0; i < dataLength ; i++) { printf("%x,",decryp[i]); } printf("\n"); return 0; }
6 感悟
在实现RC4的过程中,遇到的问题到时不多,唯一一个问题就是在解密的时候,怎么都不能正常的解密,原因就是没有对Sbox进行重新初始化,究其原因就是对算法的原理没有搞明白.还有就是没有好好的对别人的代码进行深入的理解.总是停留在表面上.这样是难以提高自己的能力.以后的工作中,要注意两点:
- 静下心来研究代码.
- 做个有心人,多学习人家代码中实现的好的地方.