RC4加密算法的原理与实现

本文最后更新于:2018-05-18

RC4算法相关信息

设计者:Ronald Rivest(from RSA Security)
发布时间:1987年(设计)/1994年(公开)
算法特点:流加密,密钥长度可变,对称加密算法
密钥长度:40~2048 bits

RC4算法曾经被用于WEP、WPA的无线网络通讯协议,以及SSL和早期的TLS网络传输层安全协议,由于RC4存在快速破解方法,已于2015年被RFC 7465禁止在TLS中使用

算法原理与实现

RC4的原理非常简单,给定一个不超过256字节的密钥,根据密钥在算法中用伪随机数算法初始化一个长度为256、元素不重复的字节数组,之后逐字节读入待加密的数据,通过算法在S盒中取出一个字节并与明文字节进行位异或运算加密。
由于RC4算法使用的是位异或运算进行加密,因此其加密与解密的算法是完全一样的,实现起来也非常方便

以下给出一个简单的实现,仅用于实验目的
使用语言:Kotlin

主函数的实现细节,加密算法核心在此处:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
* RC4Kayo.kt
*
* By Kayo Hikawa(a.k.a. Summerfirefly/Natsuyoru Kurosawa)
*
* License: Copyleft/Public Domain
*
*/

// 这是一个控制台程序
// 接受2-3个控制台参数
// 参数1:输入文件(必需)
// 参数2:输出文件(必需)
// 参数3:密钥文件(加密时可选,解密时必需)

import java.io.File
import kotlin.experimental.xor

fun main(args: Array<String>) {
val key = if (args.size < 3) RC4Key() else RC4Key(File(args[2]))
if (args.size < 3) key.saveKeyAsFile("${args[0]}.kayo.key")

//初始化一个字节数组
val S = IntArray(256, { i -> i })
var j = 0

//使用伪随机打乱S数组
for (i in S.indices) {
j = (j + S[i] + (key.key[i % key.keyLen].toInt() and 0xff)) % 256
val temp = S[i]
S[i] = S[j]
S[j] = temp
}

j = 0
var i = 0
val inputFile = File(args[0]).readBytes()
val outputFile = File(args[1])

// 此处若输出文件已经存在,直接删除旧文件
// 实际应用中为保护用户数据,需更改处理方式
if (outputFile.exists()) outputFile.delete()

//进行流加密
for (b in inputFile) {
i = (i + 1) % 256
j = (j + S[i]) % 256

val temp = S[i]
S[i] = S[j]
S[j] = temp

outputFile.appendBytes(byteArrayOf(b xor S[(S[i] + S[j]) % 256].toByte()))
}
}

RC4Key的实现细节如下
注意,此代码同样仅用于实验,未考虑过多的实用性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
* RC4Key.kt
*
* By Kayo Hikawa(a.k.a. Summerfirefly/Natsuyoru Kurosawa)
*
* License: Copyleft/Public Domain
*
*/

// 这是算法的密钥类
// 可随机生成指定长度密钥,也可指定密钥文件

import java.util.Random
import java.io.File

class RC4Key constructor(private var _keyLen: Int = 256) {
private var _key: ByteArray = ByteArray(_keyLen, { _ -> (Random().nextInt() % 256).toByte() })

val key: ByteArray get() = _key
val keyLen: Int get() = _keyLen

constructor(keyFile: File) : this() {
_key = keyFile.readBytes()
_keyLen = _key.size
}

fun saveKeyAsFile(targetPath: String) {
File(targetPath).writeBytes(_key)
}
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议