2010-02-28 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / class / Mono.Security / Mono.Security.Cryptography / SymmetricTransform.cs
index 4d464b88d139a23a79c394612e877d9fdd3404ba..ab43c4a5becc4599a62a0bfe2fce1edcbb8f5e32 100644 (file)
@@ -6,7 +6,7 @@
 //     Sebastien Pouliot <sebastien@ximian.com>
 //
 // Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004-2007 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
@@ -50,8 +50,11 @@ namespace Mono.Security.Cryptography {
                private byte[] temp2;
                private byte[] workBuff;
                private byte[] workout;
+#if !NET_2_1 || MONOTOUCH
+               // Silverlight 2.0 does not support any feedback mode
                private int FeedBackByte;
                private int FeedBackIter;
+#endif
                private bool m_disposed = false;
                private bool lastBlock;
 
@@ -66,21 +69,22 @@ namespace Mono.Security.Cryptography {
                        } 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 !NET_2_1 || MONOTOUCH
                        FeedBackByte = (algo.FeedbackSize >> 3);
                        if (FeedBackByte != 0)
                                FeedBackIter = (int) BlockSizeByte / FeedBackByte;
+#endif
                        // transform buffers
                        workBuff = new byte [BlockSizeByte];
                        workout =  new byte [BlockSizeByte];
@@ -133,6 +137,10 @@ namespace Mono.Security.Cryptography {
                // i.e. Any padding must be done before calling this method
                protected virtual void Transform (byte[] input, byte[] output) 
                {
+#if NET_2_1 && !MONOTOUCH
+                       // Silverlight 2.0 only supports CBC
+                       CBC (input, output);
+#else
                        switch (algo.Mode) {
                        case CipherMode.ECB:
                                ECB (input, output);
@@ -152,6 +160,7 @@ namespace Mono.Security.Cryptography {
                        default:
                                throw new NotImplementedException ("Unkown CipherMode" + algo.Mode.ToString ());
                        }
+#endif
                }
 
                // Electronic Code Book (ECB)
@@ -175,6 +184,7 @@ namespace Mono.Security.Cryptography {
                        }
                }
 
+#if !NET_2_1 || MONOTOUCH
                // Cipher-FeedBack (CFB)
                protected virtual void CFB (byte[] input, byte[] output) 
                {
@@ -216,6 +226,7 @@ namespace Mono.Security.Cryptography {
                {
                        throw new CryptographicException ("CTS isn't supported by the framework");
                }
+#endif
 
                private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
                {
@@ -244,11 +255,17 @@ namespace Mono.Security.Cryptography {
 
                        // ordered to avoid possible integer overflow
                        int len = outputBuffer.Length - inputCount - outputOffset;
+#if NET_2_1 && !MONOTOUCH
+                       // 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) {
-                               if (0 > len + BlockSizeByte)
+                       } 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
@@ -263,7 +280,12 @@ namespace Mono.Security.Cryptography {
 
                private bool KeepLastBlock {
                        get {
-                               return ((!encrypt) && (algo.Mode != CipherMode.ECB) && (algo.Padding != PaddingMode.None));
+#if NET_2_1 && !MONOTOUCH
+                               // only PKCS7 is supported Silverlight 2.0
+                               return !encrypt;
+#else
+                               return ((!encrypt) && (algo.Padding != PaddingMode.None) && (algo.Padding != PaddingMode.Zeros));
+#endif
                        }
                }
 
@@ -313,7 +335,7 @@ namespace Mono.Security.Cryptography {
                        return total;
                }
 
-#if NET_2_0
+#if (!NET_2_1 || MONOTOUCH)
                RandomNumberGenerator _rng;
 
                private void Random (byte[] buffer, int start, int length)
@@ -344,11 +366,13 @@ namespace Mono.Security.Cryptography {
                        int rem = inputCount - full;
                        int total = full;
 
+#if NET_2_1 && !MONOTOUCH
+                       // 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;
@@ -369,6 +393,7 @@ namespace Mono.Security.Cryptography {
                                }
                                break;
                        }
+#endif // NET_2_1
 
                        byte[] res = new byte [total];
                        int outputOffset = 0;
@@ -383,8 +408,14 @@ namespace Mono.Security.Cryptography {
 
                        // now we only have a single last block to encrypt
                        byte padding = (byte) (BlockSizeByte - rem);
+#if NET_2_1 && !MONOTOUCH
+                       // 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;
@@ -400,7 +431,6 @@ namespace Mono.Security.Cryptography {
                                // 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);) 
@@ -413,6 +443,7 @@ namespace Mono.Security.Cryptography {
                                InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
                                break;
                        }
+#endif // NET_2_1
                        return res;
                }
 
@@ -444,12 +475,21 @@ namespace Mono.Security.Cryptography {
 
                        // total may be 0 (e.g. PaddingMode.None)
                        byte padding = ((total > 0) ? res [total - 1] : (byte) 0);
+#if NET_2_1 && !MONOTOUCH
+                       // 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);
                                }
@@ -463,7 +503,7 @@ namespace Mono.Security.Cryptography {
                        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);
                                }
@@ -473,11 +513,12 @@ namespace Mono.Security.Cryptography {
                        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) {