更新于 2023-12-20
纯C#实现的RC4加解密,使用流模式。
由于使用流模式,加密和解密不能在同一个Cipher上进行。
可以使用CreateCipher或Reset方法快捷创建新的Cipher。
byte[] clearTextBytes = Encoding.UTF8.GetBytes("hello world!");
byte[] password = new byte[128];
new Random().NextBytes(password);
RC4BlockCipher encryptor = new RC4BlockCipher(password, RC4CipherMode.Encrypt);
Console.WriteLine("ClearText Bytes: {0}", string.Join(",", clearTextBytes));
encryptor.Encrypt(clearTextBytes, 0, clearTextBytes.Length);
Console.WriteLine("Encrypted Bytes: {0}", string.Join(",", clearTextBytes));
RC4BlockCipher decryptor = new RC4BlockCipher(password, RC4CipherMode.Decrypt);
//或者使用CreateCipher创建新的解密Cipher
//RC4BlockCipher decryptor = encryptor.CreateCipher(RC4CipherMode.Decrypt);
decryptor.Decrypt(clearTextBytes, 0, clearTextBytes.Length);
Console.WriteLine("Decrypted Bytes: {0}", string.Join(",", clearTextBytes));
Console.WriteLine("Clear Text: {0}", Encoding.UTF8.GetString(clearTextBytes));
根据随机秘钥不同,密文会有差异。
ClearText Bytes: 104,101,108,108,111,32,119,111,114,108,100,33
Encrypted Bytes: 27,254,98,227,96,143,162,87,250,242,89,88
Decrypted Bytes: 104,101,108,108,111,32,119,111,114,108,100,33
Clear Text: hello world!
public enum RC4CipherMode
{
/// <summary>
/// 加密
/// </summary>
Encrypt,
/// <summary>
/// 解密
/// </summary>
Decrypt
}
public class RC4BlockCipher : IDisposable
{
private byte[] _ciphers = null;
private byte[] _ciphers_copy = null;
private RC4CipherMode _mode;
private int _offsetX = 0;
private int _offsetY = 0;
public void Dispose()
{
_ciphers = null;
_ciphers_copy = null;
}
/// <summary>
/// 使用密码和指定加解密模式创建新的Cipher
/// </summary>
/// <param name="password">密码,最大有效长度256字节。</param>
/// <param name="mode">加解密模式</param>
public RC4BlockCipher(byte[] password, RC4CipherMode mode)
{
_mode = mode;
_ciphers = InitCiphers(password ?? throw new ArgumentNullException(nameof(password)));
_ciphers_copy = new byte[256];
_ciphers.CopyTo(_ciphers_copy, 0);
}
private RC4BlockCipher(RC4CipherMode mode)
{
_mode = mode;
}
/// <summary>
/// 生成加解密秘钥
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
private byte[] InitCiphers(byte[] password)
{
byte j = 0;
int len = password.Length;
byte[] k = new byte[256];
byte[] s = new byte[256];
int i;
for (i = 0; i < 256; i++)
{
s[i] = (byte)i;
k[i] = password[i % len];
}
for (i = 0; i < 256; i++)
{
j = (byte)((j + s[i] + k[i]) & 0xff);
byte tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
return s;
}
/// <summary>
/// 使用当前Cipher的秘钥创建新的Cipher
/// </summary>
/// <param name="mode">新的Cipher加解密模式</param>
/// <returns></returns>
public RC4BlockCipher CreateCipher(RC4CipherMode mode)
{
var cipher = new RC4BlockCipher(mode);
cipher._ciphers = new byte[256];
cipher._ciphers_copy = new byte[256];
_ciphers_copy.CopyTo(cipher._ciphers, 0);
_ciphers_copy.CopyTo(cipher._ciphers_copy, 0);
return cipher;
}
/// <summary>
/// 重置当前Cipher
/// </summary>
public void Reset()
{
_ciphers_copy.CopyTo(_ciphers, 0);
}
/// <summary>
/// 使用新的加解密模式重置当前Cipher
/// </summary>
public void Reset(RC4CipherMode mode)
{
_ciphers_copy.CopyTo(_ciphers, 0);
_mode = mode;
}
/// <summary>
/// 加密数据
/// </summary>
/// <param name="buffer">待加密数据,加密完成后,原数据会被覆写</param>
/// <param name="offset">数据偏移</param>
/// <param name="count">加密长度</param>
/// <returns></returns>
public virtual byte[] Encrypt(byte[] buffer, int offset, int count)
{
if (_mode != RC4CipherMode.Encrypt) throw new InvalidOperationException();
ProcessBlock(buffer, offset, count);
return buffer;
}
/// <summary>
/// 解密数据
/// </summary>
/// <param name="buffer">待解密数据,解密完成后,原数据会被覆写</param>
/// <param name="offset">数据偏移</param>
/// <param name="count">解密长度</param>
/// <returns></returns>
public virtual byte[] Decrypt(byte[] buffer, int offset, int count)
{
if (_mode != RC4CipherMode.Decrypt) throw new InvalidOperationException();
ProcessBlock(buffer, offset, count);
return buffer;
}
private void ProcessBlock(byte[] buffer, int offset, int count)
{
byte m;
int end = offset + count;
byte[] s = _ciphers;
for (int k = offset; k < end; k++)
{
int x = (_offsetX + 1) & 0xff;
int y = (_offsetY + s[x]) & 0xff;
m = s[x]; s[x] = s[y]; s[y] = m;
buffer[k] ^= s[(s[x] + s[y]) & 0xff];
_offsetX = x;
_offsetY = y;
}
}
}
实现在Stream上的加解密,建议同时实现Begin/End的系列方法。
public enum RC4StreamMode
{
Read, Write
}
public class RC4Stream : Stream
{
private byte[] _ciphers = null;
private Stream _innerStream;
private readonly RC4StreamMode _mode;
private int _offsetX = 0;
private int _offsetY = 0;
protected override void Dispose(bool disposing)
{
_ciphers = null;
_innerStream = null;
base.Dispose(disposing);
}
public override bool CanRead => _mode == RC4StreamMode.Read;
public override bool CanSeek => false;
public override bool CanWrite => _mode == RC4StreamMode.Write;
public override long Length => _innerStream.Length;
public override long Position { get => _innerStream.Position; set => throw new NotSupportedException(); }
public RC4Stream(Stream innerStream, byte[] password, RC4StreamMode mode)
{
_innerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream));
_mode = mode;
_ciphers = InitCiphers(password ?? throw new ArgumentNullException(nameof(password)));
}
public RC4Stream(Stream innerStream, string password, RC4StreamMode mode)
: this(innerStream, Convert.FromBase64String(password), mode)
{
}
private byte[] InitCiphers(byte[] password)
{
byte j = 0;
int len = password.Length;
byte[] k = new byte[256];
byte[] s = new byte[256];
int i;
for (i = 0; i < 256; i++)
{
s[i] = (byte)i;
k[i] = password[i % len];
}
for (i = 0; i < 256; i++)
{
j = (byte)((j + s[i] + k[i]) & 0xff);
byte tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
return s;
}
private void ProcessBlock(byte[] buffer, int offset, int count)
{
byte m;
int end = offset + count;
byte[] s = _ciphers;
for (int k = offset; k < end; k++)
{
int x = (_offsetX + 1) & 0xff;
int y = (_offsetY + s[x]) & 0xff;
m = s[x]; s[x] = s[y]; s[y] = m;
buffer[k] ^= s[(s[x] + s[y]) & 0xff];
_offsetX = x;
_offsetY = y;
}
}
public override void Flush() => throw new NotImplementedException();
public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException();
public override void SetLength(long value) => throw new NotImplementedException();
public override int Read(byte[] buffer, int offset, int count)
{
if (_mode != RC4StreamMode.Read) throw new InvalidOperationException();
int rec = _innerStream.Read(buffer, offset, count);
if (rec == 0) return 0;
ProcessBlock(buffer, offset, rec);
return rec;
}
public override void Write(byte[] buffer, int offset, int count)
{
if (_mode != RC4StreamMode.Write) throw new InvalidOperationException();
if (count == 0)
{
_innerStream.Write(buffer, offset, count);
return;
}
byte[] _buffer = new byte[count];
Array.Copy(buffer, offset, _buffer, 0, count);
ProcessBlock(_buffer, 0, count);
_innerStream.Write(_buffer, 0, count);
}
}