Arc4Cipher
Implements ARCH4 cipher algorithm.
using System;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
public sealed class Arc4Cipher : StreamCipher
{
private const int STATE_LENGTH = 256;
private byte[] _engineState;
private int _x;
private int _y;
public override byte MinimumSize => 0;
public Arc4Cipher(byte[] key, bool dischargeFirstBytes)
: base(key)
{
SetKey(key);
if (dischargeFirstBytes)
Encrypt(new byte[1536]);
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return ProcessBytes(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
byte[] array = new byte[length];
ProcessBytes(input, offset, length, array, 0);
return array;
}
public override byte[] Decrypt(byte[] input)
{
return Decrypt(input, 0, input.Length);
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
return Encrypt(input, offset, length);
}
private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputOffset + inputCount > inputBuffer.Length)
throw new ArgumentException("input buffer too short");
if (outputOffset + inputCount > outputBuffer.Length)
throw new ArgumentException("output buffer too short");
for (int i = 0; i < inputCount; i++) {
_x = ((_x + 1) & 255);
_y = ((_engineState[_x] + _y) & 255);
byte b = _engineState[_x];
_engineState[_x] = _engineState[_y];
_engineState[_y] = b;
outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ _engineState[(_engineState[_x] + _engineState[_y]) & 255]);
}
return inputCount;
}
private void SetKey(byte[] keyBytes)
{
_x = 0;
_y = 0;
if (_engineState == null)
_engineState = new byte[256];
for (int i = 0; i < 256; i++) {
_engineState[i] = (byte)i;
}
int num = 0;
int num2 = 0;
for (int j = 0; j < 256; j++) {
num2 = (((keyBytes[num] & 255) + _engineState[j] + num2) & 255);
byte b = _engineState[j];
_engineState[j] = _engineState[num2];
_engineState[num2] = b;
num = (num + 1) % keyBytes.Length;
}
}
}
}