RC4算法是一种对称加密算法,所谓对称加密,就是加密和解密的过程是一样的,加密和解密均采用同一把密钥。RC4算法的特点是算法简单,执行速度快安全性比较高并且密钥长度是可变的,可变范围为1-256字节(8-2048比特)。让它如此广泛分布和使用的主要因素是它不可思议的简单和速度,不管是软件还是硬件,实现起来都十分容易。且该算法的运行速度很快,它大约是分块密码算法DES的5倍,是3DES的15倍,且比高级加密算法AES也快很多。RC4的安全保证主要在于输入密钥的产生途径,只要在这方面不出现漏洞,采用128bit的密钥是非常安全的。
简介
RC4加密算法是大名鼎鼎的 RSA三人组中的头号人物Ron Rivest在1987年设计的密钥长度可变的流加密算法簇。之所以称其为簇,是因为其核心部分的S-box长度可为任意长度,但一般为256字节。RC4算法是一种对称加密算法,所谓对称加密,就是加密和解密的过程是一样的,加密和解密均采用同一把密钥。对称加密算法是最常用的加密算法,优势在于算法公开,计算量小,加密效率高。常用的对称加密算法有DES、RC4、AES等。
RC4被用于为网络浏览器和服务器间通信而制定的SSL/TLS(安全套接字协议/传输层安全协议)标准中,以及作为IEEE 801.11无线局域网标准一部分的WEP(Wired Equivalent Privacy)协议和新的WiFi受保护访问协议(WAP)中。从这些应用来看,RC4构成了当今网络通信的非常重要的部分,因此这个算法非常重要。
RC4算法的特点
RC4算法的特点是算法简单,执行速度快安全性比较高并且密钥长度是可变的,可变范围为1-256字节(8-2048比特),在现在技术支持的前提下,当密钥长度为128bit时,用暴力法搜索密钥已经不太可行,所以能够预见RC4的密钥范围仍然能够在今后相当长的时间里抵御暴力搜索密钥的攻击。实际上,现在也没有找到对于128bit密钥长度的RC4加密算法的有效攻击方法。RC4的可变密钥长度,是面向字节操作的流密码(逐字节加密)。流密码也属于对称密码,但与分组加密算法不同的是,流密码不对明文数据进行分组,而是用密钥生成与明文一样长短的密码流对明文进行加密,加解密使用相同的密钥。该算法以随机置换作为基础,其密码周期很可能大于10100,且该算法的运行速度很快,它大约是分块密码算法DES的5倍,是3DES的15倍,且比高级加密算法AES也快很多。RC4的安全保证主要在于输入密钥的产生途径,只要在这方面不出现漏洞,采用128bit的密钥是非常安全的。
对称密码算法的工作方式有四种:电子密码本(ECB, electronic codebook)方式、密码分组链接(CBC, cipherblock chaining)方式、密文反馈(CFB, cipher-feedback)方式、输出反馈(OFB, output-feedback)方式。 RC4算法采用的是输出反馈工作方式,所以可以用一个短的密钥产生一个相对较长的密钥序列。
1.3 RC4的优点和缺陷
由于RC4算法加密是采用的xor,所以,一旦子密钥序列出现了重复,密文就有可能被破解。RC4算法生成的子密钥序列是否会出现重复呢?由于存在部分弱密钥,使得子密钥序列在不到100万字节内就发生了完全的重复,如果是部分重复,则可能在不到10万字节内就能发生重复,因此,推荐在使用RC4算法时,必须对加密密钥进行测试,判断其是否为弱密钥。其不足主要体现于,在无线网络中IV(初始化向量)不变性漏洞。
RC4已经成为一些常用的协议和标准的一部分,如1997年的WEP和2003/2004年无线卡的WPA; 和1995年的SSL,以及后来1999年的TLS。让它如此广泛分布和使用的主要因素是它不可思议的简单和速度,不管是软件还是硬件,实现起来都十分容易。
加密步骤
(1)S表、K表初始化
(2)数据表S的初始置换--密钥调度算法(KSA)
(3)密钥流生成--伪随机数生成方法(PGRA)
(4)加密---异或
(5)解密---异或
加密原理
以一个足够大的表S为基础,对表进行非线性变化,产生密钥流。
(1)初始化S表
首先对S表进行,一般为256个字节。先初始化状态向量S(256个字节,用来作为密钥流生成的种子)按照升序,给每个字节赋值0,1,2,3,4,5,6.....,254,255。即s[0]=0,S[1]=1,……,S[255]=255.
然后用种子密钥填充另一个256字节的K表。初始密钥(由用户输入),长度任意。如果输入长度小于256个字节,则进行轮转,直到填满,例如:输入密钥的是1,2,3,那么填入的是1,2,3,1,2,3,,1,2,3,......由上述轮转过程得到256个字节的K表(用来作为密钥流生成的种子2)
最后用K表对S表进行初始置换。(不同的密钥产生不同的S表,用来打乱初始种子)
因为对S的操作仅是交换,所以惟一的改变就是置换.S表仍然包含所有值为0到255的元素.
(2)密钥流的生成
密钥流:RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节,因为密文第i字节=明文第i字节^密钥流第i字节;
为每个待加密的字节生成一个伪随机数,用来异或(S表完成初始化后,种子密钥不再使用)每一个随机数的生成,都会导致S表的两个数字置换,故每一轮的S表都不相同。
代码如下,注释非常详细,可能有不正确的地方,欢迎指出。
package practice;
import java.util.Scanner; //加包,Scanner类
public class RC4 {
public static void main(String[] args) //定义主函数
{
RC4 rc4 = new RC4();//循环使用,加密和解密都用这一个方法。也就是说参数String plainResult可以传一个明文,
//,也可以传一个加密后的字符串,程序会自动的识别。然后执行加解密的响应操作;
do //询问循环,使用do while(true)语句;
{
System.out.print("输入明文为:");
Scanner scan = new Scanner(System.in); //等待输入明文,使用Scanner类;
Scanner sc = new Scanner(System.in);
String plainResult = scan.next(); //从scan接收输入的明文;
System.out.print("输入密钥为:");
Scanner scan2 = new Scanner(System.in); //等待输入密钥,使用Scanner类;
Scanner src = new Scanner(System.in);
String key = scan2.next();
String cipherResult = rc4.encrypt(plainResult, key); //cipher:执行加解密的操作对象; //调用encrypt算法;
String decryptResult = rc4.encrypt(cipherResult, key); //decrypt:解密后的结果;
System.out.print("如果加密请按1:n");
int num = sc.nextInt();
{
if(num==1)
{
System.out.print( "明文为:" + plainResult + "n" + "密钥为:" + key + "n" +"密文为:" + cipherResult + "nn" );
}
if(num!=1)
{
System.out.print( "咋不按规矩出牌呢" +"n"+ "不玩啦不玩啦");
System.exit(0); //如果不按指定执行数字,就结束程序;
}
}
System.out.print("如果解密请按2:n");
{
int num1 = sc.nextInt();
if(num1==2)
{
System.out.print( "解密后为:" + decryptResult+ "n");
}
else
System.out.print( "真的不解吗?" +"n");
}
}
while(true); //实现加密询问循环。创建一个无限的do while循环;
}
// 1 加密
public String encrypt(final String plainResult, final String key) { //使用final修饰key,被final修饰的方法不能被重写,不可被改变;
Integer[] S = new Integer[256]; // 构造一个长度256的S表;
Character[] keySchedul = new Character[plainResult.length()]; // 用密钥填充K表,循环使用,直到256;
//Character 类:以确定字符的类别(小写字母、大写字母、数字,等);
//length () :用于获得字符串长度的;
StringBuffer cipherResult = new StringBuffer(); //StringBuffer:在指定位置把任意类型的数据插入到字符串缓冲区里面;
ksa(S, key); //调用以下的KSA算法;
rpga(S, keySchedul, plainResult.length()); //调用以下的rpga算法;
for (int i = 0; i < plainResult.length(); ++i) { //定义i,通过明文长度来决定异或次数;
cipherResult.append((char) (plainResult.charAt(i) ^ keySchedul[i])); //K表数据与S表数据异或,产生密文;
} //append:append()方法 相当于"+",把两个数据放到一个储存地址;
return cipherResult.toString(); //toString:返回值;
}
// 1.1 KSA--密钥调度算法--利用key来对S盒做一个置换,也就是对S盒重新排列 //K表对S表的初始置换;
public void ksa(Integer[] s, String key) { //调用K表; Integer:多种的进制转换,转为2进制;
for (int i = 0; i < 256; ++i) {
s[i] = i; //给S表由1到256赋值;
}
int j = 0;
for (int i = 0; i < 256; ++i) {
j = (j + s[i] + key.charAt(i % key.length())) % 256;//j=(j+S[i]+k[i])mod256;
swap(s, i, j); //置换256次,直至获得初始化后的S表;
}
}
// 1.2 RPGA--伪随机生成算法--利用上面重新排列的S盒来产生任意长度的密钥流
public void rpga(Integer[] s, Character[] keySchedul, int plaintextLength) { //获得明文长度,来决定K表(异或)的长度;
int i = 0, j = 0; //一般使用Random生成伪随机数,由每天的日期和时间生成,因此不够随机,每天可生成86.4万个种子,生成日期可推算种子,每次生成的随机数都是可预测的,故不是太安全
for (int M = 0; M < plaintextLength; ++M) { //定义M作为随机数(新的K表)生成次数
i = (i + 1) % 256; //结果对256取模
j = (j + s[i]) % 256; //结果对256取模;
swap(s, i, j); //置换S表的值;
keySchedul[M] = (char) (s[(s[i] + s[j]) % 256]).intValue(); // T=(s[i] + s[j]) % 256 使K[M]=S[T];
}
}
// 1.3 置换
public void swap(Integer[] s, int i, int j) {
Integer mTemp = s[i];
s[i] = s[j];
s[j] = mTemp;}} //每一个随机数的生成,都会导致S表的两个数字置换,
输入结果
(1)输入明文:“好好学习,天天向上”
输入密钥:“一心一意,努力进取”
按1,得到 “密文为:够奧寤仈?奄奮哤亵”
按2,得到 “解密后为:好好学习,天天向上”
完成加密解密全部过程
(2)按照相同流程输入字母混合数字数据,执行得到结果
(3)在输入明文和密钥后按2,得到提示,程序结束。
(4)在输入明文和密钥后按1,得到密文,然后按1,得到提示后,程序重新开始。
总结
我选择了JAVA进行算法的设计,实现了初始置换,伪随机数的生成,密钥流的产生等,用产生的密钥流与其一一对应的明文进行异或来产生密文。每一次的伪随机数的生成,都会有S表的更新。最后利用产生的密文与密钥逆计算,从而得到明文。
由于RC4在安全性方面的不足。RC4的应用正在逐渐减少,但存在即合理,在一些特定场景下,RC4还是存在它的用途。而密钥,对于RC4的安全性很重要,存在部分弱密钥,使得子密钥序列在不到100万字节内就发生了完全的重复,如果是部分重复,则可能在不到10万字节内就能发生重复,因此,推荐在使用RC4算法时,必须对加密密钥进行测试,判断其是否为弱密钥。否则,容易被找到规律破解。



