/*
* Mentalis.org Security Library
*
* Copyright © 2002-2005, The KPD-Team
* All rights reserved.
* http://www.mentalis.org/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the KPD-Team, nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using Org.Mentalis.Security;
namespace Org.Mentalis.Security.Cryptography {
///
/// Represents an ARCFour managed ICryptoTransform.
///
internal sealed class ARCFourManagedTransform : ICryptoTransform {
///
/// Initializes a new instance of the ARCFourManagedTransform class.
///
/// The key used to initialize the ARCFour state.
public ARCFourManagedTransform(byte[] key) {
m_Key = (byte[])key.Clone();
m_KeyLen = key.Length;
m_Permutation = new byte[256];
m_Disposed = false;
Init();
}
///
/// Gets a value indicating whether the current transform can be reused.
///
/// This property returns true.
public bool CanReuseTransform {
get {
return true;
}
}
///
/// Gets a value indicating whether multiple blocks can be transformed.
///
/// This property returns true.
public bool CanTransformMultipleBlocks {
get {
return true;
}
}
///
/// Gets the input block size.
///
/// This property returns 1.
public int InputBlockSize {
get {
return 1;
}
}
///
/// Gets the output block size.
///
/// This property returns 1.
public int OutputBlockSize {
get {
return 1;
}
}
///
/// Transforms the specified region of the input byte array and copies the resulting transform to the specified region of the output byte array.
///
/// The input for which to compute the transform.
/// The offset into the input byte array from which to begin using data.
/// The number of bytes in the input byte array to use as data.
/// The output to which to write the transform.
/// The offset into the output byte array from which to begin writing data.
/// The number of bytes written.
/// The object has been disposed.
/// or is a null reference (Nothing in Visual Basic).
/// , or is invalid.
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
if (m_Disposed)
throw new ObjectDisposedException(this.GetType().FullName);
if (inputBuffer == null || outputBuffer == null)
throw new ArgumentNullException();
if (inputOffset < 0 || outputOffset < 0 || inputOffset + inputCount > inputBuffer.Length || outputOffset + inputCount > outputBuffer.Length)
throw new ArgumentOutOfRangeException();
byte j, temp;
int length = inputOffset + inputCount;
for(; inputOffset < length; inputOffset++, outputOffset++) {
// update indices
m_Index1 = (byte)((m_Index1 + 1) % 256);
m_Index2 = (byte)((m_Index2 + m_Permutation[m_Index1]) % 256);
// swap m_State.permutation[m_State.index1] and m_State.permutation[m_State.index2]
temp = m_Permutation[m_Index1];
m_Permutation[m_Index1] = m_Permutation[m_Index2];
m_Permutation[m_Index2] = temp;
// transform byte
j = (byte)((m_Permutation[m_Index1] + m_Permutation[m_Index2]) % 256);
outputBuffer[outputOffset] = (byte)(inputBuffer[inputOffset] ^ m_Permutation[j]);
}
return inputCount;
}
///
/// Transforms the specified region of the specified byte array.
///
/// The input for which to compute the transform.
/// The offset into the byte array from which to begin using data.
/// The number of bytes in the byte array to use as data.
/// The computed transform.
/// The object has been disposed.
/// is a null reference (Nothing in Visual Basic).
/// or is invalid.
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount ) {
if (m_Disposed)
throw new ObjectDisposedException(this.GetType().FullName);
byte[] ret = new byte[inputCount];
TransformBlock(inputBuffer, inputOffset, inputCount, ret, 0);
Init();
return ret;
}
///
/// This method (re)initializes the cipher.
///
private void Init() {
byte temp;
// init state variable
for (int i = 0; i < 256; i++) {
m_Permutation[i] = (byte)i;
}
m_Index1 = 0;
m_Index2 = 0;
// randomize, using key
for (int j = 0, i = 0; i < 256; i++) {
j = (j + m_Permutation[i] + m_Key[i % m_KeyLen]) % 256;
// swap m_State.permutation[i] and m_State.permutation[j]
temp = m_Permutation[i];
m_Permutation[i] = m_Permutation[j];
m_Permutation[j] = temp;
}
}
///
/// Disposes of the cryptographic parameters.
///
public void Dispose() {
Array.Clear(m_Key, 0, m_Key.Length);
Array.Clear(m_Permutation, 0, m_Permutation.Length);
m_Index1 = 0;
m_Index2 = 0;
m_Disposed = true;
try {
GC.SuppressFinalize(this);
} catch {}
}
///
/// Finalizes the object.
///
~ARCFourManagedTransform() {
Dispose();
}
///
/// Holds the key that is used to initialize the ARCFour state.
///
private byte[] m_Key;
///
/// Holds the length of the key, in bytes.
///
private int m_KeyLen;
///
/// Holds state information.
///
private byte[] m_Permutation;
///
/// Holds state information.
///
private byte m_Index1;
///
/// Holds state information.
///
private byte m_Index2;
///
/// Holds a boolean that indicates whether the class has been disposed of or not.
///
private bool m_Disposed;
}
}