Fix CFB for AesCryptoServiceProvider (only CFB8 worked, 16-64 did not) and move the...
authorSebastien Pouliot <sebastien@xamarin.com>
Fri, 4 Jan 2013 20:19:18 +0000 (15:19 -0500)
committerSebastien Pouliot <sebastien@xamarin.com>
Mon, 7 Jan 2013 01:08:02 +0000 (20:08 -0500)
mcs/class/corlib/Mono.Security.Cryptography/SymmetricTransform.cs
mcs/class/corlib/System.Security.Cryptography/RijndaelManagedTransform.cs

index bda13d875c517bb0d079b9f005f7b311c332d528..64a1a67ba4165acfc3f7285e6890f3a67ce5dc83 100644 (file)
@@ -45,15 +45,14 @@ namespace Mono.Security.Cryptography {
        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;
 #if !MOONLIGHT
                // Silverlight 2.0 does not support any feedback mode
-               private int FeedBackByte;
-               private int FeedBackIter;
+               protected int FeedBackByte;
 #endif
                private bool m_disposed = false;
                private bool lastBlock;
@@ -81,8 +80,6 @@ namespace Mono.Security.Cryptography {
                        temp2 = new byte [BlockSizeByte];
 #if !MOONLIGHT
                        FeedBackByte = (algo.FeedbackSize >> 3);
-                       if (FeedBackByte != 0)
-                               FeedBackIter = (int) BlockSizeByte / FeedBackByte;
 #endif
                        // transform buffers
                        workBuff = new byte [BlockSizeByte];
@@ -185,30 +182,33 @@ namespace Mono.Security.Cryptography {
 
 #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]);
                                }
                        }
index 396f11f6f44ab0d6d284f893917a81336891f60b..3338414d977181f31c898fa4aac6bacf4bc52e16 100644 (file)
@@ -35,19 +35,20 @@ namespace System.Security.Cryptography {
 
        // Notes: This class is "publicly" new in Fx 2.0 but was already 
        // existing in Fx 1.0. So this new class is only calling the old
-       // (and more general) one (RijndaelTransform) located in 
-       // RijndaelManaged.cs.
+       // (and more general) one (RijndaelTransform)
 
        [ComVisible (true)]
        public sealed class RijndaelManagedTransform: ICryptoTransform, IDisposable {
 
                private RijndaelTransform _st;
                private int _bs;
+               private int _ts;
 
                internal RijndaelManagedTransform (Rijndael algo, bool encryption, byte[] key, byte[] iv)
                {
                        _st = new RijndaelTransform (algo, encryption, key, iv);
                        _bs = algo.BlockSize;
+                       _ts = algo.Mode == CipherMode.CFB ? algo.FeedbackSize >> 3 : _st.InputBlockSize;
                }
 
                public int BlockSizeValue {
@@ -63,11 +64,11 @@ namespace System.Security.Cryptography {
                }
 
                public int InputBlockSize {
-                       get { return _st.InputBlockSize; }
+                       get { return _ts; }
                }
 
                public int OutputBlockSize {
-                       get { return _st.OutputBlockSize; }
+                       get { return _ts; }
                }
 
                public void Clear ()
@@ -100,10 +101,9 @@ namespace System.Security.Cryptography {
                }
        }
 
-       internal class RijndaelTransform : SymmetricTransform
-       {
+       class RijndaelTransform : SymmetricTransform {
                private uint[] expandedKey;
-       
+               private int FeedBackIter;
                private int Nb;
                private int Nk;
                private int Nr;
@@ -126,6 +126,7 @@ namespace System.Security.Cryptography {
                        }
                        keySize <<= 3; // bytes -> bits
                        int blockSize = algo.BlockSize;
+                       FeedBackIter = (int) BlockSizeByte / FeedBackByte;      // for CFB
 
                        this.Nb = (blockSize >> 5); // div 32
                        this.Nk = (keySize >> 5); // div 32
@@ -217,6 +218,37 @@ namespace System.Security.Cryptography {
                        }
                }
 
+               // RijndaelManaged does not implement CFB like any *CryptoServiceProvider does
+               // not even AesCryptoServiceProvider, while AesManaged does not support CFB at all
+               protected override void CFB (byte[] input, byte[] output) 
+               {
+                       if (encrypt) {
+                               for (int x = 0; x < FeedBackIter; x++) {
+                                       // temp is first initialized with the IV
+                                       ECB (temp, temp2);
+                                       
+                                       for (int i = 0; i < FeedBackByte; 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);
+                               }
+                       }
+                       else {
+                               for (int x = 0; x < FeedBackIter; 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++)
+                                               output[i + x] = (byte)(temp2[i] ^ input[i + x]);
+                               }
+                       }
+               }
+
                private UInt32 SubByte (UInt32 a)
                {
                        UInt32 value = 0xff & a;