1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- using System.Text;
- namespace XGame.Framework.Utils
- {
- /// <summary>
- /// 安全性工具类
- /// </summary>
- public static partial class SecurityUtils
- {
- /// <summary>
- /// rc4 密钥字节数组长度
- /// </summary>
- private const short RC4_KEY_LENGTH = 256;
- /// <summary>
- /// 用于密钥索引计算
- /// 位操作( index & 255 )比余数快一点( index % 256 )
- /// </summary>
- private const byte RC4_KEY_LIMIT = 0xFF;//255
- /// <summary>
- /// 状态向量S
- /// </summary>
- private static readonly byte[] RC4_KEY_INDEXS = new byte[RC4_KEY_LENGTH];
- /// <summary>
- /// 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、产生密钥流
- /// 本质上是打乱密钥顺序的异或加密
- /// </summary>
- /// <param name="pwd">密钥</param>
- /// <param name="input">输入数组</param>
- /// <param name="offset">数据偏移值</param>
- /// <param name="length">加密的数据长度</param>
- /// <param name="output">输出,长度和input一致</param>
- 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;
- }
- /// <summary>
- /// 加密字节数组
- /// 加密直接替换原数组内容
- /// </summary>
- /// <param name="pwd">密钥</param>
- /// <param name="bytes">加密源&输出</param>
- public static void RC4(byte[] pwd, byte[] bytes)
- {
- RC4(pwd, bytes, 0, bytes.Length, bytes);
- }
- /// <summary>
- /// 十六进制字符串加密
- /// 返回十六进制字符串
- /// </summary>
- /// <param name="pwd">密钥,不强制使用十六进制</param>
- /// <param name="hexString">必须是十六进制的字符串</param>
- /// <returns></returns>
- 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();
- }
- }
- }
|