When you use PaddingMode.None you can wrap the ICrytoTransform and handle final block yourself:
new CryptoStream(fsCrypt, new NoPaddingTransformWrapper(encryptor), CryptoStreamMode.Write)
The following is a wrapper class itself:
public class NoPaddingTransformWrapper : ICryptoTransform
{
private ICryptoTransform m_Transform;
public NoPaddingTransformWrapper(ICryptoTransform symmetricAlgoTransform)
{
if (symmetricAlgoTransform == null)
throw new ArgumentNullException("symmetricAlgoTransform");
m_Transform = symmetricAlgoTransform;
}
#region simple wrap
public bool CanReuseTransform
{
get { return m_Transform.CanReuseTransform; }
}
public bool CanTransformMultipleBlocks
{
get { return m_Transform.CanTransformMultipleBlocks; }
}
public int InputBlockSize
{
get { return m_Transform.InputBlockSize; }
}
public int OutputBlockSize
{
get { return m_Transform.OutputBlockSize; }
}
public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
return m_Transform.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
#endregion
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputCount % m_Transform.InputBlockSize == 0)
return m_Transform.TransformFinalBlock(inputBuffer, inputOffset, inputCount);
else
{
byte[] lastBlocks = new byte[inputCount / m_Transform.InputBlockSize + m_Transform.InputBlockSize];
Buffer.BlockCopy(inputBuffer,inputOffset, lastBlocks, 0, inputCount);
byte[] result = m_Transform.TransformFinalBlock(lastBlocks, 0, lastBlocks.Length);
Debug.Assert(inputCount < result.Length);
Array.Resize(ref result, inputCount);
return result;
}
}
public void Dispose()
{
m_Transform.Dispose();
}
}
OR you can wrap a SymmetricAlgorithm so that it will do appropriate wrapping in CreateEncryptor/CreateDecryptor depending on padding mode:
public class NoPadProblemSymmetricAlgorithm : SymmetricAlgorithm
{
private SymmetricAlgorithm m_Algo;
public NoPadProblemSymmetricAlgorithm(SymmetricAlgorithm algo)
{
if (algo == null)
throw new ArgumentNullException();
m_Algo = algo;
}
public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
{
if (m_Algo.Padding == PaddingMode.None)
return new NoPaddingTransformWrapper(m_Algo.CreateDecryptor(rgbKey, rgbIV));
else
return m_Algo.CreateDecryptor(rgbKey, rgbIV);
}
public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
{
if (m_Algo.Padding == PaddingMode.None)
return new NoPaddingTransformWrapper(m_Algo.CreateEncryptor(rgbKey, rgbIV));
else
return m_Algo.CreateEncryptor(rgbKey, rgbIV);
}
#region simple wrap
public override void GenerateIV()
{
m_Algo.GenerateIV();
}
public override void GenerateKey()
{
m_Algo.GenerateIV();
}
public override int BlockSize
{
get { return m_Algo.BlockSize; }
set { m_Algo.BlockSize = value; }
}
public override int FeedbackSize
{
get { return m_Algo.FeedbackSize; }
set { m_Algo.FeedbackSize = value; }
}
public override byte[] IV
{
get { return m_Algo.IV; }
set { m_Algo.IV = value; }
}
public override byte[] Key
{
get { return m_Algo.Key; }
set { m_Algo.Key = value; }
}
public override int KeySize
{
get { return m_Algo.KeySize; }
set { m_Algo.KeySize = value; }
}
public override KeySizes[] LegalBlockSizes
{
get { return m_Algo.LegalBlockSizes; }
}
public override KeySizes[] LegalKeySizes
{
get { return m_Algo.LegalKeySizes; }
}
public override CipherMode Mode
{
get { return m_Algo.Mode; }
set { m_Algo.Mode = value; }
}
public override PaddingMode Padding
{
get { return m_Algo.Padding; }
set { m_Algo.Padding = m_Algo.Padding; }
}
protected override void Dispose(bool disposing)
{
if (disposing)
m_Algo.Dispose();
base.Dispose(disposing);
}
#endregion
}