RC4加密与实现
背景
RC4全名Rivest Cipher 4,是1987年Ron Rivest设计的一种流加密法,属于对称加密算法,曾经是WEP、TLS等使用的加密算法,它速度较快,且设计简单,所以使用较广
基本原理
首先RC4的秘钥是可变的,长度在1~256个字节之间,开始前我们需要一个初始化状态向量,在进行初始置换后生产流秘钥进行加密。对于解密则是和加密一样的算法。
详细流程
S的初始化
- 首先定义一个长度为1~256个字节的秘钥K。
- 初始化一个向量S,S[0] = 0,S[1] = 1, … ,S[255] = 255
- 创建临时数组T,T的长度是256,T用K填充,填不满的循环用K填充,直到T被填满
S的初始置换
T数组的作用是对S进行初始置换,置换规则如下:将S[i]与S[j]交换,其中j = (j + S[i] + T[i]) mod 256。j的初始值是0
流秘钥生成
根据如下计算:i = (i+1) mod 256,i初始值为0;j = (j + s[i]) mod 256,j初始值位0。然后交换s[i]和S[j]。令t = (S[i] + S[j]) mod 256。输出S[t]作为秘钥通明文进行一字节一字节的加密(异或运算)
简单实现
public class RC4 {
private int[] S = new int[256];
RC4(byte[] keys) throws Exception {
int keyLen = keys.length;
if (keyLen <1 || keyLen > 256)
throw new Exception("秘钥长度错误");
int[] T = new int[256];
for (int i = 0;i<256;i++){
S[i] = i;
}
int j = 0;
for (int i = 0;i<256;i++){
j = (j + S[i] + keys[i % keyLen]) % 256;
int temp = S[i];
S[i] = S[j];
S[j] = temp;
}
}
public byte[] encrypt(byte[] msgs){
int i = 0,j = 0;
byte[] out = new byte[msgs.length];
for (int k = 0;k<msgs.length;k++){
i = (i+1)%256;
j = (j+S[i])%256;
int temp = S[i];
S[i] = S[j];
S[j] = temp;
out[k] = (byte) (msgs[k] ^ S[(S[i] + S[j])%256]);
}
return out;
}
}
验证
public static void main(String[] args) throws Exception {
RC4 rc4 = new RC4("123".getBytes());
byte[] out = rc4.encrypt("abcdefg".getBytes());
Base64.Encoder encoder = Base64.getEncoder();
System.out.println(new String(encoder.encode(out)));
}
最后输出:MpLc5oASYw==
使用第三方RC4加密验证:
解密验证,由于说解密算法和加密算法一致,所以我们不必做任何修改,直接如下:
public static void main(String[] args) throws Exception {
RC4 rc4 = new RC4("123".getBytes());
byte[] out = rc4.encrypt("abcdefg".getBytes());
RC4 rc41 = new RC4("123".getBytes());
System.out.println(new String(rc41.encrypt(out)));
}
需要注意的一点是,解密时要新建一个RC4对象,原来的对象在加密时S数组已经发生交换,不能使用。
总结
RC4算法通过上面实现来看非常简单,没有什么复杂计算,只有简单的交换和异或运算,秘钥也足够长,是一种比较理想的算法。但是弱密钥会导致算法不安全,另外由于更好的算法出现,RC4目前已经很少使用。
题图来自unsplash:https://unsplash.com/photos/B9j-xgMVf90