Initial Commit
This commit is contained in:
230
iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs
Normal file
230
iTechSharp/srcbc/crypto/modes/CbcBlockCipher.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
|
||||
*/
|
||||
public class CbcBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private byte[] IV, cbcV, cbcNextV;
|
||||
private int blockSize;
|
||||
private IBlockCipher cipher;
|
||||
private bool encrypting;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of chaining.
|
||||
*/
|
||||
public CbcBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
|
||||
this.IV = new byte[blockSize];
|
||||
this.cbcV = new byte[blockSize];
|
||||
this.cbcNextV = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.encrypting = forEncryption;
|
||||
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length != blockSize)
|
||||
{
|
||||
throw new ArgumentException("initialisation vector must be the same length as block size");
|
||||
}
|
||||
|
||||
Array.Copy(iv, 0, IV, 0, iv.Length);
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
cipher.Init(encrypting, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/CBC".
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/CBC"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size of the underlying cipher.
|
||||
*
|
||||
* @return the block size of the underlying cipher.
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
return (encrypting)
|
||||
? EncryptBlock(input, inOff, output, outOff)
|
||||
: DecryptBlock(input, inOff, output, outOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, cbcV, 0, IV.Length);
|
||||
|
||||
cipher.Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate chaining step for CBC mode encryption.
|
||||
*
|
||||
* @param in the array containing the data to be encrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int EncryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
/*
|
||||
* XOR the cbcV and the input,
|
||||
* then encrypt the cbcV
|
||||
*/
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
cbcV[i] ^= input[inOff + i];
|
||||
}
|
||||
|
||||
int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
|
||||
|
||||
/*
|
||||
* copy ciphertext to cbcV
|
||||
*/
|
||||
Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate chaining step for CBC mode decryption.
|
||||
*
|
||||
* @param in the array containing the data to be decrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the decrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int DecryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
Array.Copy(input, inOff, cbcNextV, 0, blockSize);
|
||||
|
||||
int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
|
||||
|
||||
/*
|
||||
* XOR the cbcV and the output
|
||||
*/
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] ^= cbcV[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* swap the back up buffer into next position
|
||||
*/
|
||||
byte[] tmp;
|
||||
|
||||
tmp = cbcV;
|
||||
cbcV = cbcNextV;
|
||||
cbcNextV = tmp;
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
345
iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs
Normal file
345
iTechSharp/srcbc/crypto/modes/CcmBlockCipher.cs
Normal file
@@ -0,0 +1,345 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Macs;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
|
||||
* NIST Special Publication 800-38C.
|
||||
* <p>
|
||||
* <b>Note</b>: this mode is a packet mode - it needs all the data up front.
|
||||
* </p>
|
||||
*/
|
||||
public class CcmBlockCipher
|
||||
: IAeadBlockCipher
|
||||
{
|
||||
private static readonly int BlockSize = 16;
|
||||
|
||||
private readonly IBlockCipher cipher;
|
||||
private readonly byte[] macBlock;
|
||||
private bool forEncryption;
|
||||
private byte[] nonce;
|
||||
private byte[] associatedText;
|
||||
private int macSize;
|
||||
private ICipherParameters keyParam;
|
||||
private readonly MemoryStream data = new MemoryStream();
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used.
|
||||
*/
|
||||
public CcmBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.macBlock = new byte[BlockSize];
|
||||
|
||||
if (cipher.GetBlockSize() != BlockSize)
|
||||
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public virtual IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public virtual void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
if (parameters is AeadParameters)
|
||||
{
|
||||
AeadParameters param = (AeadParameters) parameters;
|
||||
|
||||
nonce = param.GetNonce();
|
||||
associatedText = param.GetAssociatedText();
|
||||
macSize = param.MacSize / 8;
|
||||
keyParam = param.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV param = (ParametersWithIV) parameters;
|
||||
|
||||
nonce = param.GetIV();
|
||||
associatedText = null;
|
||||
macSize = macBlock.Length / 2;
|
||||
keyParam = param.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to CCM");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/CCM"; }
|
||||
}
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public virtual int ProcessByte(
|
||||
byte input,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
data.WriteByte(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual int ProcessBytes(
|
||||
byte[] inBytes,
|
||||
int inOff,
|
||||
int inLen,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
data.Write(inBytes, inOff, inLen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual int DoFinal(
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
byte[] text = data.ToArray();
|
||||
byte[] enc = ProcessPacket(text, 0, text.Length);
|
||||
|
||||
Array.Copy(enc, 0, outBytes, outOff, enc.Length);
|
||||
|
||||
Reset();
|
||||
|
||||
return enc.Length;
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
cipher.Reset();
|
||||
data.SetLength(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing the mac calculated as part of the
|
||||
* last encrypt or decrypt operation.
|
||||
*
|
||||
* @return the last mac calculated.
|
||||
*/
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
byte[] mac = new byte[macSize];
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, mac.Length);
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetOutputSize(
|
||||
int len)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
return (int) data.Length + len + macSize;
|
||||
}
|
||||
|
||||
return (int) data.Length + len - macSize;
|
||||
}
|
||||
|
||||
public byte[] ProcessPacket(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
int inLen)
|
||||
{
|
||||
if (keyParam == null)
|
||||
throw new InvalidOperationException("CCM cipher unitialized.");
|
||||
|
||||
IBlockCipher ctrCipher = new SicBlockCipher(cipher);
|
||||
byte[] iv = new byte[BlockSize];
|
||||
byte[] output;
|
||||
|
||||
iv[0] = (byte)(((15 - nonce.Length) - 1) & 0x7);
|
||||
|
||||
Array.Copy(nonce, 0, iv, 1, nonce.Length);
|
||||
|
||||
ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
int index = inOff;
|
||||
int outOff = 0;
|
||||
|
||||
output = new byte[inLen + macSize];
|
||||
|
||||
calculateMac(input, inOff, inLen, macBlock);
|
||||
|
||||
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0); // S0
|
||||
|
||||
while (index < inLen - BlockSize) // S1...
|
||||
{
|
||||
ctrCipher.ProcessBlock(input, index, output, outOff);
|
||||
outOff += BlockSize;
|
||||
index += BlockSize;
|
||||
}
|
||||
|
||||
byte[] block = new byte[BlockSize];
|
||||
|
||||
Array.Copy(input, index, block, 0, inLen - index);
|
||||
|
||||
ctrCipher.ProcessBlock(block, 0, block, 0);
|
||||
|
||||
Array.Copy(block, 0, output, outOff, inLen - index);
|
||||
|
||||
outOff += inLen - index;
|
||||
|
||||
Array.Copy(macBlock, 0, output, outOff, output.Length - outOff);
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = inOff;
|
||||
int outOff = 0;
|
||||
|
||||
output = new byte[inLen - macSize];
|
||||
|
||||
Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
|
||||
|
||||
ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
|
||||
|
||||
for (int i = macSize; i != macBlock.Length; i++)
|
||||
{
|
||||
macBlock[i] = 0;
|
||||
}
|
||||
|
||||
while (outOff < output.Length - BlockSize)
|
||||
{
|
||||
ctrCipher.ProcessBlock(input, index, output, outOff);
|
||||
outOff += BlockSize;
|
||||
index += BlockSize;
|
||||
}
|
||||
|
||||
byte[] block = new byte[BlockSize];
|
||||
|
||||
Array.Copy(input, index, block, 0, output.Length - outOff);
|
||||
|
||||
ctrCipher.ProcessBlock(block, 0, block, 0);
|
||||
|
||||
Array.Copy(block, 0, output, outOff, output.Length - outOff);
|
||||
|
||||
byte[] calculatedMacBlock = new byte[BlockSize];
|
||||
|
||||
calculateMac(output, 0, output.Length, calculatedMacBlock);
|
||||
|
||||
if (!Arrays.AreEqual(macBlock, calculatedMacBlock))
|
||||
throw new InvalidCipherTextException("mac check in CCM failed");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
|
||||
{
|
||||
IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
|
||||
|
||||
cMac.Init(keyParam);
|
||||
|
||||
//
|
||||
// build b0
|
||||
//
|
||||
byte[] b0 = new byte[16];
|
||||
|
||||
if (hasAssociatedText())
|
||||
{
|
||||
b0[0] |= 0x40;
|
||||
}
|
||||
|
||||
b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
|
||||
|
||||
b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
|
||||
|
||||
Array.Copy(nonce, 0, b0, 1, nonce.Length);
|
||||
|
||||
int q = dataLen;
|
||||
int count = 1;
|
||||
while (q > 0)
|
||||
{
|
||||
b0[b0.Length - count] = (byte)(q & 0xff);
|
||||
q >>= 8;
|
||||
count++;
|
||||
}
|
||||
|
||||
cMac.BlockUpdate(b0, 0, b0.Length);
|
||||
|
||||
//
|
||||
// process associated text
|
||||
//
|
||||
if (hasAssociatedText())
|
||||
{
|
||||
int extra;
|
||||
|
||||
if (associatedText.Length < ((1 << 16) - (1 << 8)))
|
||||
{
|
||||
cMac.Update((byte)(associatedText.Length >> 8));
|
||||
cMac.Update((byte)associatedText.Length);
|
||||
|
||||
extra = 2;
|
||||
}
|
||||
else // can't go any higher than 2^32
|
||||
{
|
||||
cMac.Update((byte)0xff);
|
||||
cMac.Update((byte)0xfe);
|
||||
cMac.Update((byte)(associatedText.Length >> 24));
|
||||
cMac.Update((byte)(associatedText.Length >> 16));
|
||||
cMac.Update((byte)(associatedText.Length >> 8));
|
||||
cMac.Update((byte)associatedText.Length);
|
||||
|
||||
extra = 6;
|
||||
}
|
||||
|
||||
cMac.BlockUpdate(associatedText, 0, associatedText.Length);
|
||||
|
||||
extra = (extra + associatedText.Length) % 16;
|
||||
if (extra != 0)
|
||||
{
|
||||
for (int i = 0; i != 16 - extra; i++)
|
||||
{
|
||||
cMac.Update((byte)0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// add the text
|
||||
//
|
||||
cMac.BlockUpdate(data, dataOff, dataLen);
|
||||
|
||||
return cMac.DoFinal(macBlock, 0);
|
||||
}
|
||||
|
||||
private bool hasAssociatedText()
|
||||
{
|
||||
return associatedText != null && associatedText.Length != 0;
|
||||
}
|
||||
}
|
||||
}
|
218
iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs
Normal file
218
iTechSharp/srcbc/crypto/modes/CfbBlockCipher.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
|
||||
*/
|
||||
public class CfbBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] cfbV;
|
||||
private byte[] cfbOutV;
|
||||
private bool encrypting;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
* @param blockSize the block size in bits (note: a multiple of 8)
|
||||
*/
|
||||
public CfbBlockCipher(
|
||||
IBlockCipher cipher,
|
||||
int bitBlockSize)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = bitBlockSize / 8;
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.cfbV = new byte[cipher.GetBlockSize()];
|
||||
this.cfbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.encrypting = forEncryption;
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV) parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
int diff = IV.Length - iv.Length;
|
||||
Array.Copy(iv, 0, IV, diff, iv.Length);
|
||||
Array.Clear(IV, 0, diff);
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
Reset();
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/CFB"
|
||||
* and the block size in bits.
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at.
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
return (encrypting)
|
||||
? EncryptBlock(input, inOff, output, outOff)
|
||||
: DecryptBlock(input, inOff, output, outOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate processing for CFB mode encryption.
|
||||
*
|
||||
* @param in the array containing the data to be encrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int EncryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
if ((outOff + blockSize) > outBytes.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
|
||||
//
|
||||
// XOR the cfbV with the plaintext producing the cipher text
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
|
||||
return blockSize;
|
||||
}
|
||||
/**
|
||||
* Do the appropriate processing for CFB mode decryption.
|
||||
*
|
||||
* @param in the array containing the data to be decrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int DecryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
if ((outOff + blockSize) > outBytes.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
|
||||
Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
|
||||
//
|
||||
// XOR the cfbV with the plaintext producing the plain text
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
return blockSize;
|
||||
}
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, cfbV, 0, IV.Length);
|
||||
cipher.Reset();
|
||||
}
|
||||
}
|
||||
}
|
253
iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs
Normal file
253
iTechSharp/srcbc/crypto/modes/CtsBlockCipher.cs
Normal file
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
|
||||
* be used to produce cipher text which is the same outLength as the plain text.
|
||||
*/
|
||||
public class CtsBlockCipher
|
||||
: BufferedBlockCipher
|
||||
{
|
||||
private readonly int blockSize;
|
||||
|
||||
/**
|
||||
* Create a buffered block cipher that uses Cipher Text Stealing
|
||||
*
|
||||
* @param cipher the underlying block cipher this buffering object wraps.
|
||||
*/
|
||||
public CtsBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
// TODO Should this test for acceptable ones instead?
|
||||
if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
|
||||
throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
|
||||
|
||||
this.cipher = cipher;
|
||||
|
||||
blockSize = cipher.GetBlockSize();
|
||||
|
||||
buf = new byte[blockSize * 2];
|
||||
bufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update of 'length' bytes.
|
||||
*
|
||||
* @param length the outLength of the input.
|
||||
* @return the space required to accommodate a call to update
|
||||
* with length bytes of input.
|
||||
*/
|
||||
public override int GetUpdateOutputSize(
|
||||
int length)
|
||||
{
|
||||
int total = length + bufOff;
|
||||
int leftOver = total % buf.Length;
|
||||
|
||||
if (leftOver == 0)
|
||||
{
|
||||
return total - buf.Length;
|
||||
}
|
||||
|
||||
return total - leftOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the size of the output buffer required for an update plus a
|
||||
* doFinal with an input of length bytes.
|
||||
*
|
||||
* @param length the outLength of the input.
|
||||
* @return the space required to accommodate a call to update and doFinal
|
||||
* with length bytes of input.
|
||||
*/
|
||||
public override int GetOutputSize(
|
||||
int length)
|
||||
{
|
||||
return length + bufOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* process a single byte, producing an output block if neccessary.
|
||||
*
|
||||
* @param in the input byte.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
*/
|
||||
public override int ProcessByte(
|
||||
byte input,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
if (bufOff == buf.Length)
|
||||
{
|
||||
resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
|
||||
Debug.Assert(resultLen == blockSize);
|
||||
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
bufOff = blockSize;
|
||||
}
|
||||
|
||||
buf[bufOff++] = input;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* process an array of bytes, producing output if necessary.
|
||||
*
|
||||
* @param in the input byte array.
|
||||
* @param inOff the offset at which the input data starts.
|
||||
* @param length the number of bytes to be copied out of the input array.
|
||||
* @param out the space for any output that might be produced.
|
||||
* @param outOff the offset from which the output will be copied.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there isn't enough space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
*/
|
||||
public override int ProcessBytes(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
int length,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
if (length < 0)
|
||||
{
|
||||
throw new ArgumentException("Can't have a negative input outLength!");
|
||||
}
|
||||
|
||||
int blockSize = GetBlockSize();
|
||||
int outLength = GetUpdateOutputSize(length);
|
||||
|
||||
if (outLength > 0)
|
||||
{
|
||||
if ((outOff + outLength) > output.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
}
|
||||
|
||||
int resultLen = 0;
|
||||
int gapLen = buf.Length - bufOff;
|
||||
|
||||
if (length > gapLen)
|
||||
{
|
||||
Array.Copy(input, inOff, buf, bufOff, gapLen);
|
||||
|
||||
resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
bufOff = blockSize;
|
||||
|
||||
length -= gapLen;
|
||||
inOff += gapLen;
|
||||
|
||||
while (length > blockSize)
|
||||
{
|
||||
Array.Copy(input, inOff, buf, bufOff, blockSize);
|
||||
resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
|
||||
Array.Copy(buf, blockSize, buf, 0, blockSize);
|
||||
|
||||
length -= blockSize;
|
||||
inOff += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
Array.Copy(input, inOff, buf, bufOff, length);
|
||||
|
||||
bufOff += length;
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the last block in the buffer.
|
||||
*
|
||||
* @param out the array the block currently being held is copied into.
|
||||
* @param outOff the offset at which the copying starts.
|
||||
* @return the number of output bytes copied to out.
|
||||
* @exception DataLengthException if there is insufficient space in out for
|
||||
* the output.
|
||||
* @exception InvalidOperationException if the underlying cipher is not
|
||||
* initialised.
|
||||
* @exception InvalidCipherTextException if cipher text decrypts wrongly (in
|
||||
* case the exception will never Get thrown).
|
||||
*/
|
||||
public override int DoFinal(
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
if (bufOff + outOff > output.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too small in doFinal");
|
||||
}
|
||||
|
||||
int blockSize = cipher.GetBlockSize();
|
||||
int length = bufOff - blockSize;
|
||||
byte[] block = new byte[blockSize];
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
cipher.ProcessBlock(buf, 0, block, 0);
|
||||
|
||||
if (bufOff < blockSize)
|
||||
{
|
||||
throw new DataLengthException("need at least one block of input for CTS");
|
||||
}
|
||||
|
||||
for (int i = bufOff; i != buf.Length; i++)
|
||||
{
|
||||
buf[i] = block[i - blockSize];
|
||||
}
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
buf[i] ^= block[i - blockSize];
|
||||
}
|
||||
|
||||
IBlockCipher c = (cipher is CbcBlockCipher)
|
||||
? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
|
||||
: cipher;
|
||||
|
||||
c.ProcessBlock(buf, blockSize, output, outOff);
|
||||
|
||||
Array.Copy(block, 0, output, outOff + blockSize, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] lastBlock = new byte[blockSize];
|
||||
|
||||
IBlockCipher c = (cipher is CbcBlockCipher)
|
||||
? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
|
||||
: cipher;
|
||||
|
||||
c.ProcessBlock(buf, 0, block, 0);
|
||||
|
||||
for (int i = blockSize; i != bufOff; i++)
|
||||
{
|
||||
lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
|
||||
}
|
||||
|
||||
Array.Copy(buf, blockSize, block, 0, length);
|
||||
|
||||
cipher.ProcessBlock(block, 0, output, outOff);
|
||||
Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
|
||||
}
|
||||
|
||||
int offset = bufOff;
|
||||
|
||||
Reset();
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
}
|
302
iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs
Normal file
302
iTechSharp/srcbc/crypto/modes/EAXBlockCipher.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Macs;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
|
||||
* Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
|
||||
*
|
||||
* http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
|
||||
*
|
||||
* EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
|
||||
* cipher to encrypt and authenticate data. It's on-line (the length of a
|
||||
* message isn't needed to begin processing it), has good performances, it's
|
||||
* simple and provably secure (provided the underlying block cipher is secure).
|
||||
*
|
||||
* Of course, this implementations is NOT thread-safe.
|
||||
*/
|
||||
public class EaxBlockCipher
|
||||
: IAeadBlockCipher
|
||||
{
|
||||
private enum Tag : byte { N, H, C };
|
||||
|
||||
private SicBlockCipher cipher;
|
||||
|
||||
private bool forEncryption;
|
||||
|
||||
private int blockSize;
|
||||
|
||||
private IMac mac;
|
||||
|
||||
private byte[] nonceMac;
|
||||
private byte[] associatedTextMac;
|
||||
private byte[] macBlock;
|
||||
|
||||
private int macSize;
|
||||
private byte[] bufBlock;
|
||||
private int bufOff;
|
||||
|
||||
/**
|
||||
* Constructor that accepts an instance of a block cipher engine.
|
||||
*
|
||||
* @param cipher the engine to use
|
||||
*/
|
||||
public EaxBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
blockSize = cipher.GetBlockSize();
|
||||
mac = new CMac(cipher);
|
||||
macBlock = new byte[blockSize];
|
||||
bufBlock = new byte[blockSize * 2];
|
||||
associatedTextMac = new byte[mac.GetMacSize()];
|
||||
nonceMac = new byte[mac.GetMacSize()];
|
||||
this.cipher = new SicBlockCipher(cipher);
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName
|
||||
{
|
||||
get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
|
||||
}
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public virtual void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
byte[] nonce, associatedText;
|
||||
ICipherParameters keyParam;
|
||||
|
||||
if (parameters is AeadParameters)
|
||||
{
|
||||
AeadParameters param = (AeadParameters) parameters;
|
||||
|
||||
nonce = param.GetNonce();
|
||||
associatedText = param.GetAssociatedText();
|
||||
macSize = param.MacSize / 8;
|
||||
keyParam = param.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV param = (ParametersWithIV) parameters;
|
||||
|
||||
nonce = param.GetIV();
|
||||
associatedText = new byte[0];
|
||||
macSize = mac.GetMacSize() / 2;
|
||||
keyParam = param.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to EAX");
|
||||
}
|
||||
|
||||
byte[] tag = new byte[blockSize];
|
||||
|
||||
mac.Init(keyParam);
|
||||
tag[blockSize - 1] = (byte) Tag.H;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
mac.BlockUpdate(associatedText, 0, associatedText.Length);
|
||||
mac.DoFinal(associatedTextMac, 0);
|
||||
|
||||
tag[blockSize - 1] = (byte) Tag.N;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
mac.BlockUpdate(nonce, 0, nonce.Length);
|
||||
mac.DoFinal(nonceMac, 0);
|
||||
|
||||
tag[blockSize - 1] = (byte) Tag.C;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
|
||||
cipher.Init(true, new ParametersWithIV(keyParam, nonceMac));
|
||||
}
|
||||
|
||||
private void calculateMac()
|
||||
{
|
||||
byte[] outC = new byte[blockSize];
|
||||
mac.DoFinal(outC, 0);
|
||||
|
||||
for (int i = 0; i < macBlock.Length; i++)
|
||||
{
|
||||
macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Reset(true);
|
||||
}
|
||||
|
||||
private void Reset(
|
||||
bool clearMac)
|
||||
{
|
||||
cipher.Reset();
|
||||
mac.Reset();
|
||||
|
||||
bufOff = 0;
|
||||
Array.Clear(bufBlock, 0, bufBlock.Length);
|
||||
|
||||
if (clearMac)
|
||||
{
|
||||
Array.Clear(macBlock, 0, macBlock.Length);
|
||||
}
|
||||
|
||||
byte[] tag = new byte[blockSize];
|
||||
tag[blockSize - 1] = (byte) Tag.C;
|
||||
mac.BlockUpdate(tag, 0, blockSize);
|
||||
}
|
||||
|
||||
public virtual int ProcessByte(
|
||||
byte input,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
return process(input, outBytes, outOff);
|
||||
}
|
||||
|
||||
public virtual int ProcessBytes(
|
||||
byte[] inBytes,
|
||||
int inOff,
|
||||
int len,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i != len; i++)
|
||||
{
|
||||
resultLen += process(inBytes[inOff + i], outBytes, outOff + resultLen);
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
public virtual int DoFinal(
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
int extra = bufOff;
|
||||
byte[] tmp = new byte[bufBlock.Length];
|
||||
|
||||
bufOff = 0;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
cipher.ProcessBlock(bufBlock, 0, tmp, 0);
|
||||
cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
|
||||
|
||||
Array.Copy(tmp, 0, outBytes, outOff, extra);
|
||||
|
||||
mac.BlockUpdate(tmp, 0, extra);
|
||||
|
||||
calculateMac();
|
||||
|
||||
Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra + macSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (extra > macSize)
|
||||
{
|
||||
mac.BlockUpdate(bufBlock, 0, extra - macSize);
|
||||
|
||||
cipher.ProcessBlock(bufBlock, 0, tmp, 0);
|
||||
cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
|
||||
|
||||
Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
|
||||
}
|
||||
|
||||
calculateMac();
|
||||
|
||||
if (!verifyMac(bufBlock, extra - macSize))
|
||||
throw new InvalidCipherTextException("mac check in EAX failed");
|
||||
|
||||
Reset(false);
|
||||
|
||||
return extra - macSize;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
byte[] mac = new byte[macSize];
|
||||
|
||||
Array.Copy(macBlock, 0, mac, 0, macSize);
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
return ((len + bufOff) / blockSize) * blockSize;
|
||||
}
|
||||
|
||||
public virtual int GetOutputSize(
|
||||
int len)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
return len + bufOff + macSize;
|
||||
}
|
||||
|
||||
return len + bufOff - macSize;
|
||||
}
|
||||
|
||||
private int process(
|
||||
byte b,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
bufBlock[bufOff++] = b;
|
||||
|
||||
if (bufOff == bufBlock.Length)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
|
||||
|
||||
mac.BlockUpdate(outBytes, outOff, blockSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
mac.BlockUpdate(bufBlock, 0, blockSize);
|
||||
|
||||
size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
|
||||
}
|
||||
|
||||
bufOff = blockSize;
|
||||
Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private bool verifyMac(byte[] mac, int off)
|
||||
{
|
||||
for (int i = 0; i < macSize; i++)
|
||||
{
|
||||
if (macBlock[i] != mac[off + i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
447
iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs
Normal file
447
iTechSharp/srcbc/crypto/modes/GCMBlockCipher.cs
Normal file
@@ -0,0 +1,447 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Macs;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
using Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements the Galois/Counter mode (GCM) detailed in
|
||||
/// NIST Special Publication 800-38D.
|
||||
/// </summary>
|
||||
public class GcmBlockCipher
|
||||
: IAeadBlockCipher
|
||||
{
|
||||
private const int BlockSize = 16;
|
||||
private static readonly byte[] Zeroes = new byte[BlockSize];
|
||||
private static readonly BigInteger R = new BigInteger("11100001", 2).ShiftLeft(120);
|
||||
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
// These fields are set by Init and not modified by processing
|
||||
private bool forEncryption;
|
||||
private int macSize;
|
||||
private byte[] nonce;
|
||||
private byte[] A;
|
||||
private KeyParameter keyParam;
|
||||
// private int tagLength;
|
||||
private BigInteger H;
|
||||
private BigInteger initS;
|
||||
private byte[] J0;
|
||||
|
||||
// These fields are modified during processing
|
||||
private byte[] bufBlock;
|
||||
private byte[] macBlock;
|
||||
private BigInteger S;
|
||||
private byte[] counter;
|
||||
private int bufOff;
|
||||
private long totalLength;
|
||||
|
||||
// Debug variables
|
||||
// private int nCount, xCount, yCount;
|
||||
|
||||
public GcmBlockCipher(
|
||||
IBlockCipher c)
|
||||
{
|
||||
if (c.GetBlockSize() != BlockSize)
|
||||
throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
|
||||
|
||||
this.cipher = c;
|
||||
}
|
||||
|
||||
public virtual string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/GCM"; }
|
||||
}
|
||||
|
||||
public virtual int GetBlockSize()
|
||||
{
|
||||
return BlockSize;
|
||||
}
|
||||
|
||||
public virtual void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
this.macSize = 16; // TODO Make configurable?
|
||||
this.macBlock = null;
|
||||
|
||||
// TODO If macSize limitation is removed, be very careful about bufBlock
|
||||
int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
|
||||
this.bufBlock = new byte[bufLength];
|
||||
|
||||
if (parameters is AeadParameters)
|
||||
{
|
||||
AeadParameters param = (AeadParameters)parameters;
|
||||
|
||||
nonce = param.GetNonce();
|
||||
A = param.GetAssociatedText();
|
||||
// macSize = param.getMacSize() / 8;
|
||||
if (param.MacSize != 128)
|
||||
{
|
||||
// TODO Make configurable?
|
||||
throw new ArgumentException("only 128-bit MAC supported currently");
|
||||
}
|
||||
keyParam = param.Key;
|
||||
}
|
||||
else if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV param = (ParametersWithIV)parameters;
|
||||
|
||||
nonce = param.GetIV();
|
||||
A = null;
|
||||
keyParam = (KeyParameter)param.Parameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("invalid parameters passed to GCM");
|
||||
}
|
||||
|
||||
if (nonce == null || nonce.Length < 1)
|
||||
{
|
||||
throw new ArgumentException("IV must be at least 1 byte");
|
||||
}
|
||||
|
||||
if (A == null)
|
||||
{
|
||||
// Avoid lots of null checks
|
||||
A = new byte[0];
|
||||
}
|
||||
|
||||
// Cipher always used input forward mode
|
||||
cipher.Init(true, keyParam);
|
||||
|
||||
// TODO This should be configurable by Init parameters
|
||||
// (but must be 16 if nonce length not 12) (BlockSize?)
|
||||
// this.tagLength = 16;
|
||||
|
||||
byte[] h = new byte[BlockSize];
|
||||
cipher.ProcessBlock(Zeroes, 0, h, 0);
|
||||
//trace("H: " + new string(Hex.encode(h)));
|
||||
this.H = new BigInteger(1, h);
|
||||
this.initS = gHASH(A, false);
|
||||
|
||||
if (nonce.Length == 12)
|
||||
{
|
||||
this.J0 = new byte[16];
|
||||
Array.Copy(nonce, 0, J0, 0, nonce.Length);
|
||||
this.J0[15] = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
BigInteger N = gHASH(nonce, true);
|
||||
BigInteger X = BigInteger.ValueOf(nonce.Length * 8);
|
||||
//trace("len({})||len(IV): " + dumpBigInt(X));
|
||||
|
||||
N = multiply(N.Xor(X), H);
|
||||
//trace("GHASH(H,{},IV): " + dumpBigInt(N));
|
||||
this.J0 = asBlock(N);
|
||||
}
|
||||
|
||||
this.S = initS;
|
||||
this.counter = Arrays.Clone(J0);
|
||||
//trace("Y" + yCount + ": " + new string(Hex.encode(counter)));
|
||||
this.bufOff = 0;
|
||||
this.totalLength = 0;
|
||||
}
|
||||
|
||||
public virtual byte[] GetMac()
|
||||
{
|
||||
return Arrays.Clone(macBlock);
|
||||
}
|
||||
|
||||
public virtual int GetOutputSize(
|
||||
int len)
|
||||
{
|
||||
if (forEncryption)
|
||||
{
|
||||
return len + bufOff + macSize;
|
||||
}
|
||||
|
||||
return len + bufOff - macSize;
|
||||
}
|
||||
|
||||
public virtual int GetUpdateOutputSize(
|
||||
int len)
|
||||
{
|
||||
return ((len + bufOff) / BlockSize) * BlockSize;
|
||||
}
|
||||
|
||||
public virtual int ProcessByte(
|
||||
byte input,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
return Process(input, output, outOff);
|
||||
}
|
||||
|
||||
public virtual int ProcessBytes(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
int len,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
int resultLen = 0;
|
||||
|
||||
for (int i = 0; i != len; i++)
|
||||
{
|
||||
resultLen += Process(input[inOff + i], output, outOff + resultLen);
|
||||
}
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
private int Process(
|
||||
byte input,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
bufBlock[bufOff++] = input;
|
||||
|
||||
if (bufOff == bufBlock.Length)
|
||||
{
|
||||
gCTRBlock(bufBlock, BlockSize, output, outOff);
|
||||
if (!forEncryption)
|
||||
{
|
||||
Array.Copy(bufBlock, BlockSize, bufBlock, 0, BlockSize);
|
||||
}
|
||||
// bufOff = 0;
|
||||
bufOff = bufBlock.Length - BlockSize;
|
||||
// return bufBlock.Length;
|
||||
return BlockSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int DoFinal(byte[] output, int outOff)
|
||||
{
|
||||
int extra = bufOff;
|
||||
if (!forEncryption)
|
||||
{
|
||||
if (extra < macSize)
|
||||
throw new InvalidCipherTextException("data too short");
|
||||
|
||||
extra -= macSize;
|
||||
}
|
||||
|
||||
if (extra > 0)
|
||||
{
|
||||
byte[] tmp = new byte[BlockSize];
|
||||
Array.Copy(bufBlock, 0, tmp, 0, extra);
|
||||
gCTRBlock(tmp, extra, output, outOff);
|
||||
}
|
||||
|
||||
// Final gHASH
|
||||
BigInteger X = BigInteger.ValueOf(A.Length * 8).ShiftLeft(64).Add(
|
||||
BigInteger.ValueOf(totalLength * 8));
|
||||
//trace("len(A)||len(C): " + dumpBigInt(X));
|
||||
|
||||
S = multiply(S.Xor(X), H);
|
||||
//trace("GHASH(H,A,C): " + dumpBigInt(S));
|
||||
|
||||
// T = MSBt(GCTRk(J0,S))
|
||||
byte[] tBytes = new byte[BlockSize];
|
||||
cipher.ProcessBlock(J0, 0, tBytes, 0);
|
||||
//trace("E(K,Y0): " + new string(Hex.encode(tmp)));
|
||||
BigInteger T = S.Xor(new BigInteger(1, tBytes));
|
||||
|
||||
// TODO Fix this if tagLength becomes configurable
|
||||
byte[] tag = asBlock(T);
|
||||
//trace("T: " + new string(Hex.encode(tag)));
|
||||
|
||||
int resultLen = extra;
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
this.macBlock = tag;
|
||||
Array.Copy(tag, 0, output, outOff + bufOff, tag.Length);
|
||||
resultLen += tag.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.macBlock = new byte[macSize];
|
||||
Array.Copy(bufBlock, extra, macBlock, 0, macSize);
|
||||
if (!Arrays.AreEqual(tag, this.macBlock))
|
||||
throw new InvalidCipherTextException("mac check input GCM failed");
|
||||
}
|
||||
|
||||
Reset(false);
|
||||
|
||||
return resultLen;
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
Reset(true);
|
||||
}
|
||||
|
||||
private void Reset(
|
||||
bool clearMac)
|
||||
{
|
||||
// Debug
|
||||
// nCount = xCount = yCount = 0;
|
||||
|
||||
S = initS;
|
||||
counter = Arrays.Clone(J0);
|
||||
bufOff = 0;
|
||||
totalLength = 0;
|
||||
|
||||
if (bufBlock != null)
|
||||
{
|
||||
Array.Clear(bufBlock, 0, bufBlock.Length);
|
||||
}
|
||||
|
||||
if (clearMac)
|
||||
{
|
||||
macBlock = null;
|
||||
}
|
||||
|
||||
cipher.Reset();
|
||||
}
|
||||
|
||||
private void gCTRBlock(byte[] buf, int bufCount, byte[] output, int outOff)
|
||||
{
|
||||
inc(counter);
|
||||
//trace("Y" + ++yCount + ": " + new string(Hex.encode(counter)));
|
||||
|
||||
byte[] tmp = new byte[BlockSize];
|
||||
cipher.ProcessBlock(counter, 0, tmp, 0);
|
||||
//trace("E(K,Y" + yCount + "): " + new string(Hex.encode(tmp)));
|
||||
|
||||
if (forEncryption)
|
||||
{
|
||||
Array.Copy(Zeroes, bufCount, tmp, bufCount, BlockSize - bufCount);
|
||||
|
||||
for (int i = bufCount - 1; i >= 0; --i)
|
||||
{
|
||||
tmp[i] ^= buf[i];
|
||||
output[outOff + i] = tmp[i];
|
||||
}
|
||||
|
||||
gHASHBlock(tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = bufCount - 1; i >= 0; --i)
|
||||
{
|
||||
tmp[i] ^= buf[i];
|
||||
output[outOff + i] = tmp[i];
|
||||
}
|
||||
|
||||
gHASHBlock(buf);
|
||||
}
|
||||
|
||||
totalLength += bufCount;
|
||||
}
|
||||
|
||||
private BigInteger gHASH(byte[] b, bool nonce)
|
||||
{
|
||||
//trace("" + b.Length);
|
||||
BigInteger Y = BigInteger.Zero;
|
||||
|
||||
for (int pos = 0; pos < b.Length; pos += 16)
|
||||
{
|
||||
byte[] x = new byte[16];
|
||||
int num = System.Math.Min(b.Length - pos, 16);
|
||||
Array.Copy(b, pos, x, 0, num);
|
||||
BigInteger X = new BigInteger(1, x);
|
||||
Y = multiply(Y.Xor(X), H);
|
||||
// if (nonce)
|
||||
// {
|
||||
// trace("N" + ++nCount + ": " + dumpBigInt(Y));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// trace("X" + ++xCount + ": " + dumpBigInt(Y) + " (gHASH)");
|
||||
// }
|
||||
}
|
||||
|
||||
return Y;
|
||||
}
|
||||
|
||||
private void gHASHBlock(byte[] block)
|
||||
{
|
||||
if (block.Length > BlockSize)
|
||||
{
|
||||
byte[] tmp = new byte[BlockSize];
|
||||
Array.Copy(block, 0, tmp, 0, BlockSize);
|
||||
block = tmp;
|
||||
}
|
||||
|
||||
BigInteger X = new BigInteger(1, block);
|
||||
S = multiply(S.Xor(X), H);
|
||||
//trace("X" + ++xCount + ": " + dumpBigInt(S) + " (gHASHBlock)");
|
||||
}
|
||||
|
||||
private static void inc(byte[] block)
|
||||
{
|
||||
// assert block.Length == 16;
|
||||
|
||||
for (int i = 15; i >= 12; --i)
|
||||
{
|
||||
byte b = (byte)((block[i] + 1) & 0xff);
|
||||
block[i] = b;
|
||||
|
||||
if (b != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BigInteger multiply(
|
||||
BigInteger X,
|
||||
BigInteger Y)
|
||||
{
|
||||
BigInteger Z = BigInteger.Zero;
|
||||
BigInteger V = X;
|
||||
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
if (Y.TestBit(127 - i))
|
||||
{
|
||||
Z = Z.Xor(V);
|
||||
}
|
||||
|
||||
bool lsb = V.TestBit(0);
|
||||
V = V.ShiftRight(1);
|
||||
if (lsb)
|
||||
{
|
||||
V = V.Xor(R);
|
||||
}
|
||||
}
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
private byte[] asBlock(
|
||||
BigInteger bi)
|
||||
{
|
||||
byte[] b = BigIntegers.AsUnsignedByteArray(bi);
|
||||
if (b.Length < 16)
|
||||
{
|
||||
byte[] tmp = new byte[16];
|
||||
Array.Copy(b, 0, tmp, tmp.Length - b.Length, b.Length);
|
||||
b = tmp;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// private string dumpBigInt(BigInteger bi)
|
||||
// {
|
||||
// byte[] b = asBlock(bi);
|
||||
//
|
||||
// return new string(Hex.encode(b));
|
||||
// }
|
||||
//
|
||||
// private void trace(string msg)
|
||||
// {
|
||||
// System.err.println(msg);
|
||||
// }
|
||||
}
|
||||
}
|
223
iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs
Normal file
223
iTechSharp/srcbc/crypto/modes/GOFBBlockCipher.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements the GOST 28147 OFB counter mode (GCTR).
|
||||
*/
|
||||
public class GOfbBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] ofbV;
|
||||
private byte[] ofbOutV;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
bool firstStep = true;
|
||||
int N3;
|
||||
int N4;
|
||||
const int C1 = 16843012; //00000001000000010000000100000100
|
||||
const int C2 = 16843009; //00000001000000010000000100000001
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* counter mode (must have a 64 bit block size).
|
||||
*/
|
||||
public GOfbBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
|
||||
if (blockSize != 8)
|
||||
{
|
||||
throw new ArgumentException("GCTR only for 64 bit block ciphers");
|
||||
}
|
||||
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param encrypting if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param parameters the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption, //ignored by this CTR mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
firstStep = true;
|
||||
N3 = 0;
|
||||
N4 = 0;
|
||||
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
|
||||
for (int i = 0; i < IV.Length - iv.Length; i++)
|
||||
{
|
||||
IV[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(iv, 0, IV, 0, IV.Length);
|
||||
}
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/GCTR"
|
||||
* and the block size in bits
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/GCTR"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at (in bytes).
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + blockSize) > output.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
if (firstStep)
|
||||
{
|
||||
firstStep = false;
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
N3 = bytesToint(ofbOutV, 0);
|
||||
N4 = bytesToint(ofbOutV, 4);
|
||||
}
|
||||
N3 += C2;
|
||||
N4 += C1;
|
||||
intTobytes(N3, ofbV, 0);
|
||||
intTobytes(N4, ofbV, 4);
|
||||
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the feedback vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, ofbV, 0, IV.Length);
|
||||
|
||||
cipher.Reset();
|
||||
}
|
||||
|
||||
//array of bytes to type int
|
||||
private int bytesToint(
|
||||
byte[] inBytes,
|
||||
int inOff)
|
||||
{
|
||||
return (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
|
||||
((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
|
||||
}
|
||||
|
||||
//int to array of bytes
|
||||
private void intTobytes(
|
||||
int num,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
outBytes[outOff + 3] = (byte)(num >> 24);
|
||||
outBytes[outOff + 2] = (byte)(num >> 16);
|
||||
outBytes[outOff + 1] = (byte)(num >> 8);
|
||||
outBytes[outOff] = (byte)num;
|
||||
}
|
||||
}
|
||||
}
|
90
iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs
Normal file
90
iTechSharp/srcbc/crypto/modes/IAeadBlockCipher.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/// <summary>
|
||||
/// A block cipher mode that includes authenticated encryption with a streaming mode
|
||||
/// and optional associated data.</summary>
|
||||
/// <see cref="AeadParameters"/>
|
||||
public interface IAeadBlockCipher
|
||||
{
|
||||
/// <summary>The name of the algorithm this cipher implements.</summary>
|
||||
string AlgorithmName { get; }
|
||||
|
||||
/// <summary>Initialise the cipher.</summary>
|
||||
/// <remarks>Parameter can either be an AeadParameters or a ParametersWithIV object.</remarks>
|
||||
/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
|
||||
/// <param name="parameters">The key or other data required by the cipher.</param>
|
||||
void Init(bool forEncryption, ICipherParameters parameters);
|
||||
|
||||
/// <returns>The block size for this cipher, in bytes.</returns>
|
||||
int GetBlockSize();
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt a single byte.
|
||||
*
|
||||
* @param input the byte to be processed.
|
||||
* @param outBytes the output buffer the processed byte goes into.
|
||||
* @param outOff the offset into the output byte array the processed data starts at.
|
||||
* @return the number of bytes written to out.
|
||||
* @exception DataLengthException if the output buffer is too small.
|
||||
*/
|
||||
int ProcessByte(byte input, byte[] outBytes, int outOff);
|
||||
|
||||
/**
|
||||
* Process a block of bytes from in putting the result into out.
|
||||
*
|
||||
* @param inBytes the input byte array.
|
||||
* @param inOff the offset into the in array where the data to be processed starts.
|
||||
* @param len the number of bytes to be processed.
|
||||
* @param outBytes the output buffer the processed bytes go into.
|
||||
* @param outOff the offset into the output byte array the processed data starts at.
|
||||
* @return the number of bytes written to out.
|
||||
* @exception DataLengthException if the output buffer is too small.
|
||||
*/
|
||||
int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
|
||||
|
||||
/**
|
||||
* Finish the operation either appending or verifying the MAC at the end of the data.
|
||||
*
|
||||
* @param outBytes space for any resulting output data.
|
||||
* @param outOff offset into out to start copying the data at.
|
||||
* @return number of bytes written into out.
|
||||
* @throws InvalidOperationException if the cipher is in an inappropriate state.
|
||||
* @throws InvalidCipherTextException if the MAC fails to match.
|
||||
*/
|
||||
int DoFinal(byte[] outBytes, int outOff);
|
||||
|
||||
/**
|
||||
* Return the value of the MAC associated with the last stream processed.
|
||||
*
|
||||
* @return MAC for plaintext data.
|
||||
*/
|
||||
byte[] GetMac();
|
||||
|
||||
/**
|
||||
* Return the size of the output buffer required for a ProcessBytes
|
||||
* an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to ProcessBytes
|
||||
* with len bytes of input.
|
||||
*/
|
||||
int GetUpdateOutputSize(int len);
|
||||
|
||||
/**
|
||||
* Return the size of the output buffer required for a ProcessBytes plus a
|
||||
* DoFinal with an input of len bytes.
|
||||
*
|
||||
* @param len the length of the input.
|
||||
* @return the space required to accommodate a call to ProcessBytes and DoFinal
|
||||
* with len bytes of input.
|
||||
*/
|
||||
int GetOutputSize(int len);
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cipher to the same state as it was after the last init (if there was one).
|
||||
/// </summary>
|
||||
void Reset();
|
||||
}
|
||||
}
|
178
iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs
Normal file
178
iTechSharp/srcbc/crypto/modes/OfbBlockCipher.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* implements a Output-FeedBack (OFB) mode on top of a simple cipher.
|
||||
*/
|
||||
public class OfbBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] ofbV;
|
||||
private byte[] ofbOutV;
|
||||
|
||||
private readonly int blockSize;
|
||||
private readonly IBlockCipher cipher;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
* @param blockSize the block size in bits (note: a multiple of 8)
|
||||
*/
|
||||
public OfbBlockCipher(
|
||||
IBlockCipher cipher,
|
||||
int blockSize)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = blockSize / 8;
|
||||
|
||||
this.IV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbV = new byte[cipher.GetBlockSize()];
|
||||
this.ofbOutV = new byte[cipher.GetBlockSize()];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param param the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption, //ignored by this OFB mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
|
||||
for (int i = 0; i < IV.Length - iv.Length; i++)
|
||||
{
|
||||
IV[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(iv, 0, IV, 0, IV.Length);
|
||||
}
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/OFB"
|
||||
* and the block size in bits
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at (in bytes).
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + blockSize) > output.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
|
||||
|
||||
//
|
||||
// XOR the ofbV with the plaintext producing the cipher text (and
|
||||
// the next input block).
|
||||
//
|
||||
for (int i = 0; i < blockSize; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
//
|
||||
// change over the input block.
|
||||
//
|
||||
Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
|
||||
Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the feedback vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, ofbV, 0, IV.Length);
|
||||
|
||||
cipher.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
344
iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs
Normal file
344
iTechSharp/srcbc/crypto/modes/OpenPgpCfbBlockCipher.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
|
||||
* on top of a simple cipher. This class assumes the IV has been prepended
|
||||
* to the data stream already, and just accomodates the reset after
|
||||
* (blockSize + 2) bytes have been read.
|
||||
* <p>
|
||||
* For further info see <a href="http://www.ietf.org/rfc/rfc2440.html">RFC 2440</a>.
|
||||
* </p>
|
||||
*/
|
||||
public class OpenPgpCfbBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private byte[] IV;
|
||||
private byte[] FR;
|
||||
private byte[] FRE;
|
||||
private byte[] tmp;
|
||||
|
||||
private readonly IBlockCipher cipher;
|
||||
private readonly int blockSize;
|
||||
|
||||
private int count;
|
||||
private bool forEncryption;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param cipher the block cipher to be used as the basis of the
|
||||
* feedback mode.
|
||||
*/
|
||||
public OpenPgpCfbBlockCipher(
|
||||
IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
this.IV = new byte[blockSize];
|
||||
this.FR = new byte[blockSize];
|
||||
this.FRE = new byte[blockSize];
|
||||
this.tmp = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the algorithm name and mode.
|
||||
*
|
||||
* @return the name of the underlying algorithm followed by "/PGPCFB"
|
||||
* and the block size in bits.
|
||||
*/
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/OpenPGPCFB"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/**
|
||||
* return the block size we are operating at.
|
||||
*
|
||||
* @return the block size we are operating at (in bytes).
|
||||
*/
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one block of input from the array in and write it to
|
||||
* the out array.
|
||||
*
|
||||
* @param in the array containing the input data.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the output data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining vector back to the IV and reset the underlying
|
||||
* cipher.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
count = 0;
|
||||
|
||||
Array.Copy(IV, 0, FR, 0, FR.Length);
|
||||
|
||||
cipher.Reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cipher and, possibly, the initialisation vector (IV).
|
||||
* If an IV isn't passed as part of the parameter, the IV will be all zeros.
|
||||
* An IV which is too short is handled in FIPS compliant fashion.
|
||||
*
|
||||
* @param forEncryption if true the cipher is initialised for
|
||||
* encryption, if false for decryption.
|
||||
* @param parameters the key and other data required by the cipher.
|
||||
* @exception ArgumentException if the parameters argument is
|
||||
* inappropriate.
|
||||
*/
|
||||
public void Init(
|
||||
bool forEncryption,
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
this.forEncryption = forEncryption;
|
||||
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV)parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
|
||||
if (iv.Length < IV.Length)
|
||||
{
|
||||
// prepend the supplied IV with zeros (per FIPS PUB 81)
|
||||
Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
|
||||
for (int i = 0; i < IV.Length - iv.Length; i++)
|
||||
{
|
||||
IV[i] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(iv, 0, IV, 0, IV.Length);
|
||||
}
|
||||
|
||||
parameters = ivParam.Parameters;
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
cipher.Init(true, parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt one byte of data according to CFB mode.
|
||||
* @param data the byte to encrypt
|
||||
* @param blockOff offset in the current block
|
||||
* @returns the encrypted byte
|
||||
*/
|
||||
private byte EncryptByte(byte data, int blockOff)
|
||||
{
|
||||
return (byte)(FRE[blockOff] ^ data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate processing for CFB IV mode encryption.
|
||||
*
|
||||
* @param in the array containing the data to be encrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int EncryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + blockSize) > outBytes.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
if (count > blockSize)
|
||||
{
|
||||
FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
|
||||
FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
|
||||
}
|
||||
|
||||
Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2);
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
|
||||
}
|
||||
|
||||
Array.Copy(outBytes, outOff, FR, 0, blockSize);
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
else if (count == blockSize)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
outBytes[outOff] = EncryptByte(input[inOff], 0);
|
||||
outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1);
|
||||
|
||||
//
|
||||
// do reset
|
||||
//
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
|
||||
}
|
||||
|
||||
Array.Copy(outBytes, outOff + 2, FR, 0, blockSize - 2);
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the appropriate processing for CFB IV mode decryption.
|
||||
*
|
||||
* @param in the array containing the data to be decrypted.
|
||||
* @param inOff offset into the in array the data starts at.
|
||||
* @param out the array the encrypted data will be copied into.
|
||||
* @param outOff the offset into the out array the output will start at.
|
||||
* @exception DataLengthException if there isn't enough data in in, or
|
||||
* space in out.
|
||||
* @exception InvalidOperationException if the cipher isn't initialised.
|
||||
* @return the number of bytes processed and produced.
|
||||
*/
|
||||
private int DecryptBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] outBytes,
|
||||
int outOff)
|
||||
{
|
||||
if ((inOff + blockSize) > input.Length)
|
||||
{
|
||||
throw new DataLengthException("input buffer too short");
|
||||
}
|
||||
|
||||
if ((outOff + blockSize) > outBytes.Length)
|
||||
{
|
||||
throw new DataLengthException("output buffer too short");
|
||||
}
|
||||
|
||||
if (count > blockSize)
|
||||
{
|
||||
// copy in buffer so that this mode works if in and out are the same
|
||||
Array.Copy(input, inOff, tmp, 0, blockSize);
|
||||
|
||||
outBytes[outOff] = EncryptByte(tmp[0], blockSize - 2);
|
||||
outBytes[outOff + 1] = EncryptByte(tmp[1], blockSize - 1);
|
||||
|
||||
Array.Copy(tmp, 0, FR, blockSize - 2, 2);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
outBytes[outOff + n] = EncryptByte(tmp[n], n - 2);
|
||||
}
|
||||
|
||||
Array.Copy(tmp, 2, FR, 0, blockSize - 2);
|
||||
}
|
||||
else if (count == 0)
|
||||
{
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 0; n < blockSize; n++)
|
||||
{
|
||||
FR[n] = input[inOff + n];
|
||||
outBytes[n] = EncryptByte(input[inOff + n], n);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
else if (count == blockSize)
|
||||
{
|
||||
Array.Copy(input, inOff, tmp, 0, blockSize);
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
outBytes[outOff] = EncryptByte(tmp[0], 0);
|
||||
outBytes[outOff + 1] = EncryptByte(tmp[1], 1);
|
||||
|
||||
Array.Copy(FR, 2, FR, 0, blockSize - 2);
|
||||
|
||||
FR[blockSize - 2] = tmp[0];
|
||||
FR[blockSize - 1] = tmp[1];
|
||||
|
||||
cipher.ProcessBlock(FR, 0, FRE, 0);
|
||||
|
||||
for (int n = 2; n < blockSize; n++)
|
||||
{
|
||||
FR[n - 2] = input[inOff + n];
|
||||
outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
|
||||
}
|
||||
|
||||
count += blockSize;
|
||||
}
|
||||
|
||||
return blockSize;
|
||||
}
|
||||
}
|
||||
}
|
106
iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs
Normal file
106
iTechSharp/srcbc/crypto/modes/SicBlockCipher.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using Org.BouncyCastle.Math;
|
||||
|
||||
namespace Org.BouncyCastle.Crypto.Modes
|
||||
{
|
||||
/**
|
||||
* Implements the Segmented Integer Counter (SIC) mode on top of a simple
|
||||
* block cipher.
|
||||
*/
|
||||
public class SicBlockCipher
|
||||
: IBlockCipher
|
||||
{
|
||||
private readonly IBlockCipher cipher;
|
||||
private readonly int blockSize;
|
||||
private readonly byte[] IV;
|
||||
private readonly byte[] counter;
|
||||
private readonly byte[] counterOut;
|
||||
|
||||
/**
|
||||
* Basic constructor.
|
||||
*
|
||||
* @param c the block cipher to be used.
|
||||
*/
|
||||
public SicBlockCipher(IBlockCipher cipher)
|
||||
{
|
||||
this.cipher = cipher;
|
||||
this.blockSize = cipher.GetBlockSize();
|
||||
this.IV = new byte[blockSize];
|
||||
this.counter = new byte[blockSize];
|
||||
this.counterOut = new byte[blockSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* return the underlying block cipher that we are wrapping.
|
||||
*
|
||||
* @return the underlying block cipher that we are wrapping.
|
||||
*/
|
||||
public IBlockCipher GetUnderlyingCipher()
|
||||
{
|
||||
return cipher;
|
||||
}
|
||||
|
||||
public void Init(
|
||||
bool forEncryption, //ignored by this CTR mode
|
||||
ICipherParameters parameters)
|
||||
{
|
||||
if (parameters is ParametersWithIV)
|
||||
{
|
||||
ParametersWithIV ivParam = (ParametersWithIV) parameters;
|
||||
byte[] iv = ivParam.GetIV();
|
||||
Array.Copy(iv, 0, IV, 0, IV.Length);
|
||||
|
||||
Reset();
|
||||
cipher.Init(true, ivParam.Parameters);
|
||||
}
|
||||
}
|
||||
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return cipher.AlgorithmName + "/SIC"; }
|
||||
}
|
||||
|
||||
public bool IsPartialBlockOkay
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return cipher.GetBlockSize();
|
||||
}
|
||||
|
||||
public int ProcessBlock(
|
||||
byte[] input,
|
||||
int inOff,
|
||||
byte[] output,
|
||||
int outOff)
|
||||
{
|
||||
cipher.ProcessBlock(counter, 0, counterOut, 0);
|
||||
|
||||
//
|
||||
// XOR the counterOut with the plaintext producing the cipher text
|
||||
//
|
||||
for (int i = 0; i < counterOut.Length; i++)
|
||||
{
|
||||
output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
|
||||
}
|
||||
|
||||
// Increment the counter
|
||||
int j = counter.Length;
|
||||
while (--j >= 0 && ++counter[j] == 0)
|
||||
{
|
||||
}
|
||||
|
||||
return counter.Length;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Array.Copy(IV, 0, counter, 0, counter.Length);
|
||||
cipher.Reset();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user