using System.Text;
namespace XGame.Framework.Utils
{
///
/// 安全性工具类
///
public static partial class SecurityUtils
{
///
/// rc4 密钥字节数组长度
///
private const short RC4_KEY_LENGTH = 256;
///
/// 用于密钥索引计算
/// 位操作( index & 255 )比余数快一点( index % 256 )
///
private const byte RC4_KEY_LIMIT = 0xFF;//255
///
/// 状态向量S
///
private static readonly byte[] RC4_KEY_INDEXS = new byte[RC4_KEY_LENGTH];
///
/// RC4算法的特点是算法简单,运行速度快,而且密钥长度是可变的,可变范围为1-256字节(8-2048比特),
/// RC4加密算法中的几个关键变量:
/// 1、密钥流:RC4算法的关键是根据明文和密钥生成相应的密钥流,密钥流的长度和明文的长度是对应的,也就是说明文的长度是500字节,那么密钥流也是500字节。当然,加密生成的密文也是500字节,因为密文第i字节=明文第i字节^密钥流第i字节;
/// 2、状态向量S:长度为256,S[0],S[1].....S[255]。每个单元都是一个字节,算法运行的任何时候,S都包括0-255的8比特数的排列组合,只不过值的位置发生了变换;
/// 3、临时向量T:长度也为256,每个单元也是一个字节。如果密钥的长度是256字节,就直接把密钥的值赋给T,否则,轮转地将密钥的每个字节赋给T;
/// 4、密钥K:长度为1-256字节,注意密钥的长度keylen与明文长度、密钥流的长度没有必然关系,通常密钥的长度趣味16字节(128比特)。
/// RC4步骤:1、初始化S和T 2、初始排列S 3、产生密钥流
/// 本质上是打乱密钥顺序的异或加密
///
/// 密钥
/// 输入数组
/// 数据偏移值
/// 加密的数据长度
/// 输出,长度和input一致
public static void RC4(byte[] pwd, byte[] input, int offset, int length, byte[] output)
{
Assert.IsFalse(pwd == null || pwd.Length == 0, "RC4密钥不能为空.");
Assert.IsFalse(input == null || input.Length == 0, "RC4输入数据内容不能为空.");
Assert.IsFalse(output == null || output.Length == 0, "RC4输出数据不能为空.");
Assert.IsTrue(input.Length == output.Length, $"RC4输入输出数据长度必须一致.Input:{input.Length} Output:{output.Length}");
Assert.IsFalse(offset < 0 || length <= 0 || offset + length > input.Length, $"RC4数据偏移值错误.offset:{offset} length:{length} inputL:{input.Length}");
int a, i, j, k;
var pwdLength = pwd.Length;
//打乱密码,密码,密码箱长度
for (i = 0; i < RC4_KEY_LENGTH; i++)
{ // 先重置索引
RC4_KEY_INDEXS[i] = (byte)i;
}
for (j = i = 0; i < RC4_KEY_LENGTH; i++)
{
j = (j + RC4_KEY_INDEXS[i] + pwd[i % pwdLength]) & RC4_KEY_LIMIT; // 位操作( &255 )比余数快一点( %256 )
Swap(RC4_KEY_INDEXS, i, j);
}
for (j = i = 0; i < length; i++)
{
a = (i + 1) & RC4_KEY_LIMIT;
j = (j + RC4_KEY_INDEXS[a]) & RC4_KEY_LIMIT;
Swap(RC4_KEY_INDEXS, a, j);
k = RC4_KEY_INDEXS[(RC4_KEY_INDEXS[a] + RC4_KEY_INDEXS[j]) & RC4_KEY_LIMIT];
output[i + offset] = (byte)(input[i + offset] ^ k);
}
}
private static void Swap(byte[] s, int i, int j)
{
var c = s[i];
s[i] = s[j];
s[j] = c;
}
///
/// 加密字节数组
/// 加密直接替换原数组内容
///
/// 密钥
/// 加密源&输出
public static void RC4(byte[] pwd, byte[] bytes)
{
RC4(pwd, bytes, 0, bytes.Length, bytes);
}
///
/// 十六进制字符串加密
/// 返回十六进制字符串
///
/// 密钥,不强制使用十六进制
/// 必须是十六进制的字符串
///
public static string RC4(string pwd, string hexString)
{
byte[] key = Encoding.UTF8.GetBytes(pwd);
byte[] bytes = hexString.ToHexBytes();
RC4(key, bytes, 0, bytes.Length, bytes);
return bytes.ToHexString();
}
}
}