网络安全实验——RC4的实现

一、实验要求

① 编码实现RC4,简单分析代码

② 加解密个人信息,包含姓名学号,等相关信息

二、实验原理

RC4是RonRivest为RSA公司在1987年设计的一种流密码。它是一个可变密钥长度、面向字节操作的流密码。该算法以随机置换作为基础。分析显示该密码的周期很可能大于ARC4加密算法 rc4加密算法实验报告_web安全。每输出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中的元素个体就被重新置换一次。


ARC4加密算法 rc4加密算法实验报告_ARC4加密算法_02

初始化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]开始


ARC4加密算法 rc4加密算法实验报告_安全_03

/*密钥流的生成*/
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加密解密。