网络安全实验——RC4的实现
一、实验要求
① 编码实现RC4,简单分析代码
② 加解密个人信息,包含姓名学号,等相关信息
二、实验原理
RC4是RonRivest为RSA公司在1987年设计的一种流密码。它是一个可变密钥长度、面向字节操作的流密码。该算法以随机置换作为基础。分析显示该密码的周期很可能大于。每输出1字节的结果仅需要8~16条机器操作指令,软件实现的该密码运行很快。RC4应用很广,例如,它用于作为EEE802.l1无线局域网标准一部分的WEP(WiredEquivalentPrivacy)协议和新的WiFi受保护访问协议(WPA)中。作为可选,它也被用于SecureShell(SSH)和Kerberos中。在当时RC4作为RSA公司的商业机密并没有公开。直到1994年9月,RC4算法才通过Cypherpunks匿名邮件列表匿名地公开于Internet上。
RC4算法非常简单,易于描述:用1~ 256个字节(8~2048位)的可变长度密钥初始化一个256个字节的状态向量S,S的元素记为S [0],S [1],…,S [255],从始至终置换后的S包含从0~255所有的8位数。对于加密和解密,字节k是从S的255个元素中按一种系统化的方式选出的一个元素生成的。每生成一个k值,S中的元素个体就被重新置换一次。
初始化S
开始时,S中元素的值按升序被置为从0~255,即S[0],S[1],…,S[255]。同时建立一个临时向量T。如果密钥K的长度为256字节,则将K赋给T。否则若密钥长度为keylen个字节(keylen<256),则将K的值赋给T的前keylen个元素,并循环重复用K的值赋给T剩下的元素,直到T的所有元素都被赋值。这些预操作可被概括为如下:
/*初始化*/
for i = 0 to 255 do
S[i] = i
T[i] = K[i mod keylen]
然后用T产生S的初始置换,从S[0]到S[255],对每个S[i],根据由T[i]确定的方案,将S[i]可置换为S中的另一字节。
/*S的初始置换*/
j = 0
for i = 0 to 255 do
j = (j + S[i] + T[i])(mod 256)
swap(S[i] , S[j])
因为对S的操作仅是交换,所以唯一的改变就是置换。S仍然包含所有值为0~255的元素。
密钥流的产生
向量S一旦完成初始化,输入密钥就不再被使用。密钥流的生成过程是,从S[0]到S[255],对每个S[i],根据S的当前配置,将S[i]与S中的另一字节置换。当S[255]完成置换后,操作继续重复从S[0]开始
/*密钥流的生成*/
i = j = 0
while(true)
i = (i + 1)(mod 256)
j = (j + S[i])(mod 256)
swap(S[i],S[j])
t = (S[i] + S[j])(mod 256)
k = S[t]
加密中,将k的值与明文的下一字节异或;解密中,将k的值与密文的下一字节异或。
三、代码说明
这里我使用java来实现RC4。
首先定义了几个变量
private int[] S;//S盒
private char[] K;//密钥
private char[] data;//数据
private char[] key_stream;//密钥流
初始化S
/**
* 初始化S
*/
public void initS() {
S = new int[256];
int[] T = new int[256];
//初始化
for (int i = 0; i < 256; i++) {
S[i] = i;
T[i] = K[i % K.length];
}
//S的初始置换
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + S[i] + T[i]) % 256;
swap(S, i, j);
}
}
密钥流的产生
根据 S 盒生成与明文长度相同的秘钥流。
/**
* 产生密钥流
*/
public void generateKeyStream() {
int i = 0, j = 0;
for (int q = 0; q < data.length; q++) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(S, i, j);
int t = (S[i] + S[j]) % 256;
key_stream[q] = (char) (S[t]);
}
}
加密与解密
由于异或运算的特性,使得加密与解密过程一致。如果输入的是明文,输出的就是密文;如果输入的是密文,输出的就是明文。调用过程如下:
/**
* 加密
* @param key 密钥
* @param plaintext 明文
* @return 密文
*/
public String encrypt(String key, String plaintext) {
return useRC4(key, plaintext);
}
/**
* 解密
* @param key 密钥
* @param ciphertext 密文
* @return 明文
*/
public String decrypt(String key, String ciphertext) {
return useRC4(key, ciphertext);
}
/**
* 使用RC4
* @param key 密钥
* @param string 明文/密文
* @return 密文/明文
*/
private String useRC4(String key, String string) {
this.data = string.toCharArray();
this.key_stream = new char[data.length];
this.K = key.toCharArray();
//初始化S
initS();
//产生密钥流
generateKeyStream();
StringBuffer result = new StringBuffer();
//逐字加密数据
for (int i = 0; i < data.length; i++) {
result.append((char) (string.charAt(i) ^ key_stream[i]));
}
//输出结果
return result.toString();
}
四、实验结果
测试数据如下(考虑隐私,已经去掉了学号等信息):
我把我的整个灵魂都给你,连同它的怪癖,耍小脾气,忽明忽暗,一千八百种坏毛病。它真讨厌,只有一点好,爱你。——from 王小波
测试代码如下
String key = "love";
String plaintext = readFile("src/input.txt");
RC4 test = new RC4();
System.out.println("明文为:");
System.out.println(plaintext);
System.out.println("使用RC4加密后的密文:");
String ciphertext = test.encrypt(key, plaintext);
System.out.println(ciphertext);
System.out.println("使用RC4解密该密文得到:");
String plaintext_rc4 = test.decrypt(key, ciphertext);
System.out.println(plaintext_rc4);
实验结果如下:
明文为:
我把我的整个灵魂都给你,连同它的怪癖,耍小脾气,忽明忽暗,一千八百种坏毛病。它真讨厌,只有一点好,爱你。——from 王小波
使用RC4加密后的密文:
轁亰2:V覃嬽丯邎妢孋〾戡扎拡癖敔丹炏鮭達绫佹¥輳咲家瘸悁癓;聂岇脐氖ᄋ彳曚忩昲₩乶印冺瘾禟圴殃畱ク密睾诣危厯枒仦炁妫"牪佽ぷ―‚§.-3Y珧屯汞
使用RC4解密该密文得到:
我把我的整个灵魂都给你,连同它的怪癖,耍小脾气,忽明忽暗,一千八百种坏毛病。它真讨厌,只有一点好,爱你。——from 王小波
综上,该实验能成功实现简单的RC4加密解密。