ARC4 加密库





5.00/5 (15投票s)
ARC4(疑似 RC4)加密提供程序类库
- 下载 DLL 文件 - 12.5 KB
- 下载 .NET Framework 4.0 源代码 - 17.7 KB
- 下载 .NET 9.0 源代码 - 11.5 KB
- 下载演示应用程序 - 24.9 KB
目录
引言
ARC4 加密提供程序类库是一个用于 .NET 项目的 DLL 文件,其中包含了一个众所周知的对称加密算法的实现,该算法在 mscorlib 库的 System.Security.Cryptography 命名空间中不存在。
这种加密算法,称为 ARC4(Alleged RC4),是一种流密码,广泛应用于计算机网络上的各种信息安全系统中(例如,SSL 和 TLS 协议,WEP 和 WPA 无线安全算法)。最初的 RC4 流密码由 RSA Security 的 Ronald Rivest 创建。该算法曾是商业机密长达七年,只有在签署保密协议后才提供其确切的描述,但在 1994 年 9 月,其描述被匿名发送到了 Cypherpunks 邮件列表中。
为了避免商标所有者可能提出的索赔,该算法有时被称为 ARC4,意为“声称的 RC4”(因为 RSA Security 没有正式发布该算法)。
尽管不推荐使用该算法,但 ARC4 仍然因其软件实现简单和操作速度快而受欢迎。另一个重要优点是密钥长度可变,并且加密数据量与原始数据量相同。
库内容
该库包含以下命名空间
- System.Security.Cryptography 包含 ARC4 算法的 SymmetricAlgorithm 和 DeriveBytes 基类的实现。
- System.IO 包含使用 ARC4 算法对加密数据进行流处理的实现。
用法
有两种方法可以在自己的项目中(ARC4Lib)中使用
- 将下载的 DLL 文件复制到开发文件夹中的自定义文件夹中。在 Visual Studio IDE 中创建一个项目。在解决方案资源管理器中,右键单击“引用”或“依赖项”节点,然后选择“添加项目引用”,然后单击“浏览”按钮,选择要添加的 ARC4Lib.dll 文件,然后按“确定”。
- 将下载的源代码项目复制到开发文件夹中的自定义文件夹中。在 Visual Studio IDE 中创建一个解决方案。将 ARC4Lib.csproj 添加到解决方案中。在解决方案资源管理器中,右键单击“引用”或“依赖项”节点,然后选择“添加项目引用”,然后单击“项目”,选择要添加的 ARC4Lib.csproj 文件,然后按“确定”。这样,您可以按需修改 ARC4Lib。
要为当前应用程序域注册算法映射名称,请尝试以下操作
C#
using System.Security.Cryptography; // ... ARC4.Register();
数据加密和解密示例
C#
using System.Security.Cryptography; // ... byte[] password = Encoding.UTF8.GetBytes("password"); byte[] data = Encoding.UTF8.GetBytes("secret"); byte[] encrypted, restored; using (var arc4 = ARC4.Create(password) { using(var transform = arc4.CreateEncryptor()) // Encryption. { encrypted = transform.TransformFinalBlock(data, 0, data.Length); } using(var transform = arc4.CreateDecryptor()) // Decryption. { restored = transform.TransformFinalBlock(data, 0, data.Length); } }
使用加密流的示例
C#
收起 ▲
using System.Security.Cryptography; // ... string password = "password"; string data = "secret"; string restored; using (var memory = new MemoryStream()) { // Encryption. using (var stream = new ARC4Stream(memory, password)) { using (var writer = new StreamWriter(stream)) { writer.Write(data); } } memory.Seek(0, SeekOrigin.Begin); // Reset the memory position to start. // Decryption. using (var stream = new ARC4Stream(memory, password)) { using (var reader = new StreamReader(stream)) { restored = reader.ReadToEnd(); } } }
形成密钥的示例
C#
using System.Security.Cryptography; // ... const int KEY_LENGTH = 64; string password = "password"; byte[] key; byte[] salt; using (var deriveBytes = new ARC4DeriveBytes(password)) { key = deriveBytes.GetBytes(KEY_LENGTH); salt = deriveBytes.Salt; }
工作原理
流密码算法的核心是一个函数——伪随机位(gamma)生成器,它产生一个密钥位流(密钥流、gamma、伪随机位序列)。然后,通过按位 XOR 将其与用户想要加密的原始数据相结合进行加密;解密以类似的方式进行(因为与给定数据的 XOR 是一种对合运算)。
S 块初始化
该算法也称为密钥调度算法(KSA)。该算法使用用户输入的密钥,存储在 Key 中,长度为 L 字节。初始化开始时会填充数组(S-block),然后根据密钥定义的排列对该数组进行洗牌。由于只对 S-block 执行一项操作,因此必须说明 S-block 始终包含初始化期间给定的一组值:Si=i。用户还可以通过初始化向量使用自己的 S 块版本,或者生成伪随机 S 块。
C#
byte[] sblock = new byte[256]; // The array contained S-block. void CreateSBlock() { for (int i = 0; i < 256; i++) { sblock[i] = (byte)i; // S-block initialization. } } void KeyScheduling() (byte[] key) // KSA { for (int i = 0, j = 0, l = key.Length; i < 256; i++) { j = (j + sblock[i] + key[i % l]) % 256; Swap(sblock, i, j); // See below for "Swap" implementation ↓ } }
注意!默认情况下,在当前的 ARC4.Create() 实现中,S 块使用通过线性同余方法(LCR)获得的伪随机字节数组和随机的 256 字节密钥进行初始化。这与经典的算法不太吻合,经典的算法是在将 S 块传递给 PRGA 之前,用 0 到 255 的序列(Si=i)进行初始化的。如果需要经典行为,请使用 ARC4.Create(key) 或将 ARC4SBlock.DefaultSBlock 作为初始化向量传递给 ARC4.Create(key,iv)。否则,您应该始终保留初始化向量以防止解密的数据损坏,因为每次使用 ARC4.Create() 初始化引擎时,加密的数据都会不同。
如果您想使用自己的自定义 S 块,它将通过 ValidBytes 函数进行测试,以确保所有 256 个值都不重复。
C#
bool ValidBytes(byte[] bytes) { if (bytes == null || bytes.Length != 256) { return false; } for (int i = 0; i < 256; i++) { for (int j = i + 1; j < 256; j++) { if (bytes[i] == bytes[j]) { return false; } } } return true; }
生成伪随机字 K
算法的这一部分称为伪随机生成算法(PRGA)。ARC4 密钥流生成器会置换 S 块中存储的值。在一个 ARC4 周期中,会确定一个 8 位 K 字作为密钥流。将来,该字将与用户想要加密的原始文本进行模二运算,从而获得密文。
NextByte 函数执行 PRGA 转换并返回字 K。
C#
int x = 0, y = 0; void Swap(byte[] array, int index1, int index2) { byte b = array[index1]; array[index1] = array[index2]; array[index2] = b; } byte NextByte() // PRGA { x = (x + 1) % 256; y = (y + sblock[x]) % 256; Swap(sblock, x, y); return sblock[(sblock[x] + sblock[y]) % 256]; }
加密算法
加密
该函数生成一个比特序列 Ki。然后,该比特序列通过按位 XOR (⊕) 操作与原始数据 Di 组合。结果是密文 Ci。
Ci = Di ⊕ Ki。
解密
密钥比特流(密钥流)Ki 会被重新创建(重新生成)。通过 XOR 操作将密钥比特流与密文 Ci 相加。由于 XOR 操作的特性,输出是恢复的原始数据 Ri(使得 Ri = Di 对于所有 i 成立)。
Ri = Ci ⊕ Ki = ( Di ⊕ Ki ) ⊕ Ki
Cipher 函数使用 ARC4 算法执行对称加密和解密。
C#
void Cipher(byte[] buffer, int offset, int count) { for (int i = offset; i < count; i++) { buffer[i] = unchecked((byte)(buffer[i] ^ NextByte())); } }
基于 ARC4 的随机字节生成器
ARC4DeriveBytes 类实现了基于密码生成指定长度密钥的功能,该功能使用 PRGA 伪随机数生成器。首先,通过零值初始化给定长度的数据数组,然后使用 PRGA 算法填充它。
线性同余随机数
LCR 方法的本质是计算随机数序列 Xi,设置
Xi+1 = (A • Xi + C) MOD M,其中
- M 是模数(一个自然数 M ≥ 2,计算其除法的余数);
- A 是因子(0 ≤ A < M);
- C 是增量(0 ≤ C < M);
- X0 是初始值 0 ≤ X0 < M;
- 索引 i 在 0 ≤ i < M 中按顺序变化。
因此,只有当以下条件满足时,LCR 才能生成 M 个不重复的伪随机值:
- C 和 M 是互质数;
- B = A - 1 是 m 的每个素数因子 P 的倍数;
- 如果 M 是 4 的倍数,则 B 是 4 的倍数。
为了优化,在本例中预定义为
- Xi+1 = R ⊕ (A • Xi + C) MOD M,
- Xi ∈ (0, 256),
- X0 是随机的,
- R ∈ (0, 256) 是随机常数,
- M = 256,
- A ∈ (9, 249) 且 A - 1 可被 4 整除,
- C ∈ (5, 251) 且 C 是素数。
使用以下方法可以获得的 S 块的不同数量的上限约为 2 亿个。
C#
收起 ▲
byte[] _A = // An array of all values that A. { 0x09, 0x0D, 0x11, 0x15, 0x19, 0x1D, 0x21, 0x25, 0x29, 0x2D, 0x31, 0x35, 0x39, 0x3D, 0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x91, 0x95, 0x99, 0x9D, 0xA1, 0xA5, 0xA9, 0xAD, 0xB1, 0xB5, 0xB9, 0xBD, 0xC1, 0xC5, 0xC9, 0xCD, 0xD1, 0xD5, 0xD9, 0xDD, 0xE1, 0xE5, 0xE9, 0xED, 0xF1, 0xF5, 0xF9 }; byte[] _C = // An array of all values that C. { 0x05, 0x07, 0x0B, 0x0D, 0x11, 0x13, 0x17, 0x1D, 0x1F, 0x25, 0x29, 0x2B, 0x2F, 0x35, 0x3B, 0x3D, 0x43, 0x47, 0x49, 0x4F, 0x53, 0x59, 0x61, 0x65, 0x67, 0x6B, 0x6D, 0x71, 0x7F, 0x83, 0x89, 0x8B, 0x95, 0x97, 0x9D, 0xA3, 0xA7, 0xAD, 0xB3, 0xB5, 0xBF, 0xC1, 0xC5, 0xC7, 0xD3, 0xDF, 0xE3, 0xE5, 0xE9, 0xEF, 0xF1, 0xFB }; void CreateRandomSBlock() // LCR { using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) { byte[] random = new byte[4]; rng.GetBytes(random); int r = random[0]; // For best ranodimzation. int x = random[1]; int a = _A[random[2] % _A.Length]; int c = _C[random[3] % _C.Length]; int m = 256; for (int i = 0; i < m; i++) { // S-block initialization. sblock[i] = (byte) (r ^ (x = (a * x + c) % m)); } } }