// Sebastien Pouliot <sebastien@ximian.com>
//
// Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
internal abstract class SymmetricTransform : ICryptoTransform {
protected SymmetricAlgorithm algo;
protected bool encrypt;
- private int BlockSizeByte;
- private byte[] temp;
- private byte[] temp2;
+ protected int BlockSizeByte;
+ protected byte[] temp;
+ protected byte[] temp2;
private byte[] workBuff;
private byte[] workout;
- private int FeedBackByte;
- private int FeedBackIter;
+#if !MOONLIGHT
+ // Silverlight 2.0 does not support any feedback mode
+ protected int FeedBackByte;
+#endif
private bool m_disposed = false;
private bool lastBlock;
} else {
rgbIV = (byte[]) rgbIV.Clone ();
}
-#if NET_2_0
// compare the IV length with the "currently selected" block size and *ignore* IV that are too big
if (rgbIV.Length < BlockSizeByte) {
string msg = Locale.GetText ("IV is too small ({0} bytes), it should be {1} bytes long.",
rgbIV.Length, BlockSizeByte);
throw new CryptographicException (msg);
}
-#endif
// mode buffers
temp = new byte [BlockSizeByte];
Buffer.BlockCopy (rgbIV, 0, temp, 0, System.Math.Min (BlockSizeByte, rgbIV.Length));
temp2 = new byte [BlockSizeByte];
+#if !MOONLIGHT
FeedBackByte = (algo.FeedbackSize >> 3);
- if (FeedBackByte != 0)
- FeedBackIter = (int) BlockSizeByte / FeedBackByte;
+#endif
// transform buffers
workBuff = new byte [BlockSizeByte];
workout = new byte [BlockSizeByte];
// i.e. Any padding must be done before calling this method
protected virtual void Transform (byte[] input, byte[] output)
{
+#if MOONLIGHT
+ // Silverlight 2.0 only supports CBC
+ CBC (input, output);
+#else
switch (algo.Mode) {
case CipherMode.ECB:
ECB (input, output);
default:
throw new NotImplementedException ("Unkown CipherMode" + algo.Mode.ToString ());
}
+#endif
}
// Electronic Code Book (ECB)
}
}
+#if !MOONLIGHT
// Cipher-FeedBack (CFB)
+ // this is how *CryptoServiceProvider implements CFB
+ // only AesCryptoServiceProvider support CFB > 8
+ // RijndaelManaged is incompatible with this implementation (and overrides it in it's own transform)
protected virtual void CFB (byte[] input, byte[] output)
{
if (encrypt) {
- for (int x = 0; x < FeedBackIter; x++) {
+ for (int x = 0; x < BlockSizeByte; x++) {
// temp is first initialized with the IV
ECB (temp, temp2);
- for (int i = 0; i < FeedBackByte; i++)
+ for (int i = 0; i < 1; i++)
output[i + x] = (byte)(temp2[i] ^ input[i + x]);
- Buffer.BlockCopy (temp, FeedBackByte, temp, 0, BlockSizeByte - FeedBackByte);
- Buffer.BlockCopy (output, x, temp, BlockSizeByte - FeedBackByte, FeedBackByte);
+ Buffer.BlockCopy (temp, 1, temp, 0, BlockSizeByte - 1);
+ Buffer.BlockCopy (output, x, temp, BlockSizeByte - 1, 1);
}
}
else {
- for (int x = 0; x < FeedBackIter; x++) {
+ for (int x = 0; x < BlockSizeByte; x++) {
// we do not really decrypt this data!
encrypt = true;
// temp is first initialized with the IV
ECB (temp, temp2);
encrypt = false;
- Buffer.BlockCopy (temp, FeedBackByte, temp, 0, BlockSizeByte - FeedBackByte);
- Buffer.BlockCopy (input, x, temp, BlockSizeByte - FeedBackByte, FeedBackByte);
- for (int i = 0; i < FeedBackByte; i++)
+ Buffer.BlockCopy (temp, 1, temp, 0, BlockSizeByte - 1);
+ Buffer.BlockCopy (input, x, temp, BlockSizeByte - 1, 1);
+ for (int i = 0; i < 1; i++)
output[i + x] = (byte)(temp2[i] ^ input[i + x]);
}
}
// Cipher Text Stealing (CTS)
protected virtual void CTS (byte[] input, byte[] output)
{
- throw new CryptographicException ("CTS isn't supported by the framework");
+ throw new CryptographicException ("CTS isn't supported by the framework");
}
+#endif
private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
{
throw new ArgumentNullException ("outputBuffer");
if (outputOffset < 0)
throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
- // ordered to avoid possible integer overflow
- if (outputOffset > outputBuffer.Length - inputCount)
- throw new ArgumentException ("outputBuffer", Locale.GetText ("Overflow"));
+ // ordered to avoid possible integer overflow
+ int len = outputBuffer.Length - inputCount - outputOffset;
+#if MOONLIGHT
+ // only PKCS7 is supported Silverlight 2.0
+ if (KeepLastBlock) {
+#else
+ if (!encrypt && (0 > len) && ((algo.Padding == PaddingMode.None) || (algo.Padding == PaddingMode.Zeros))) {
+ throw new CryptographicException ("outputBuffer", Locale.GetText ("Overflow"));
+ } else if (KeepLastBlock) {
+#endif
+ if (0 > len + BlockSizeByte) {
+ throw new CryptographicException ("outputBuffer", Locale.GetText ("Overflow"));
+ }
+ } else {
+ if (0 > len) {
+ // there's a special case if this is the end of the decryption process
+ if (inputBuffer.Length - inputOffset - outputBuffer.Length == BlockSizeByte)
+ inputCount = outputBuffer.Length - outputOffset;
+ else
+ throw new CryptographicException ("outputBuffer", Locale.GetText ("Overflow"));
+ }
+ }
return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
private bool KeepLastBlock {
get {
- return ((!encrypt) && (algo.Mode != CipherMode.ECB) && (algo.Padding != PaddingMode.None));
+#if MOONLIGHT
+ // only PKCS7 is supported Silverlight 2.0
+ return !encrypt;
+#else
+ return ((!encrypt) && (algo.Padding != PaddingMode.None) && (algo.Padding != PaddingMode.Zeros));
+#endif
}
}
return total;
}
-#if NET_2_0
+#if !MOONLIGHT
RandomNumberGenerator _rng;
private void Random (byte[] buffer, int start, int length)
int rem = inputCount - full;
int total = full;
+#if MOONLIGHT
+ // only PKCS7 is supported Silverlight 2.0
+ total += BlockSizeByte;
+#else
switch (algo.Padding) {
-#if NET_2_0
case PaddingMode.ANSIX923:
case PaddingMode.ISO10126:
-#endif
case PaddingMode.PKCS7:
// we need to add an extra block for padding
total += BlockSizeByte;
}
break;
}
+#endif // NET_2_1
byte[] res = new byte [total];
int outputOffset = 0;
// now we only have a single last block to encrypt
byte padding = (byte) (BlockSizeByte - rem);
+#if MOONLIGHT
+ // only PKCS7 is supported Silverlight 2.0
+ for (int i = res.Length; --i >= (res.Length - padding);)
+ res [i] = padding;
+ Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
+ InternalTransformBlock (res, full, BlockSizeByte, res, full);
+#else
switch (algo.Padding) {
-#if NET_2_0
case PaddingMode.ANSIX923:
// XX 00 00 00 00 00 00 07 (zero + padding length)
res [res.Length - 1] = padding;
// the last padded block will be transformed in-place
InternalTransformBlock (res, full, BlockSizeByte, res, full);
break;
-#endif
case PaddingMode.PKCS7:
// XX 07 07 07 07 07 07 07 (padding length)
for (int i = res.Length; --i >= (res.Length - padding);)
InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
break;
}
+#endif // NET_2_1
return res;
}
// total may be 0 (e.g. PaddingMode.None)
byte padding = ((total > 0) ? res [total - 1] : (byte) 0);
+#if MOONLIGHT
+ // only PKCS7 is supported Silverlight 2.0
+ if ((padding == 0) || (padding > BlockSizeByte))
+ throw new CryptographicException (Locale.GetText ("Bad padding length."));
+ for (int i = padding - 1; i > 0; i--) {
+ if (res [total - 1 - i] != padding)
+ throw new CryptographicException (Locale.GetText ("Bad padding at position {0}.", i));
+ }
+ total -= padding;
+#else
switch (algo.Padding) {
-#if NET_2_0
case PaddingMode.ANSIX923:
if ((padding == 0) || (padding > BlockSizeByte))
ThrowBadPaddingException (algo.Padding, padding, -1);
- for (int i=padding; i > 0; i--) {
+ for (int i = padding - 1; i > 0; i--) {
if (res [total - 1 - i] != 0x00)
ThrowBadPaddingException (algo.Padding, -1, i);
}
case PaddingMode.PKCS7:
if ((padding == 0) || (padding > BlockSizeByte))
ThrowBadPaddingException (algo.Padding, padding, -1);
- for (int i=padding - 1; i > 0; i--) {
+ for (int i = padding - 1; i > 0; i--) {
if (res [total - 1 - i] != padding)
ThrowBadPaddingException (algo.Padding, -1, i);
}
total -= padding;
break;
-#else
- case PaddingMode.PKCS7:
- total -= padding;
- break;
-#endif
case PaddingMode.None: // nothing to do - it's a multiple of block size
case PaddingMode.Zeros: // nothing to do - user must unpad himself
break;
}
+#endif // NET_2_1
// return output without padding
if (total > 0) {