[mono/crimson] [15 commits] 8c3d777b: Initial implementation of Crimson.OpenSsl

"Sebastien Pouliot ([email protected])" <[email protected]>
Newsgroups gmane.comp.gnome.mono.patches
Message-ID <000001418f15efd0-604e4a68-787f-46d9-b531-e938f5c3b0ec-000000@email.amazonses.com>
   Branch: refs/heads/master
     Home: https://github.com/mono/crimson
  Compare: https://github.com/mono/crimson/compare/6f2c6b779ac4...b6641f3b4602

   Commit: 8c3d777bae4aaf426146f4c60fbf06e86b5f4b24
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 05:51:02 GMT
      URL: https://github.com/mono/crimson/commit/8c3d777bae4aaf426146f4c60fbf06e86b5f4b24

Initial implementation of Crimson.OpenSsl

Added paths:
  A class/Crimson.OpenSsl/.gitignore
  A class/Crimson.OpenSsl/AUTHORS
  A class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  A class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  A class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  A class/Crimson.OpenSsl/LICENSE
  A class/Crimson.OpenSsl/Makefile
  A class/Crimson.OpenSsl/README
  A class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs
  A class/Crimson.OpenSsl/tools/generator.cs
  A class/Crimson.OpenSsl/tools/torture.cs
  A common/CryptoTransformBase.cs

Added: class/Crimson.OpenSsl/.gitignore
===================================================================
@@ -0,0 +1,5 @@
+*.dll*
+Crimson.Security.Cryptography/*.g.cs
+TestResult.xml
+AssemblyInfo.cs
+tools/generator.exe
\ No newline at end of file

Added: class/Crimson.OpenSsl/AUTHORS
===================================================================
@@ -0,0 +1,2 @@
+Sebastien Pouliot  <[email protected]>
+Bassam Tabbara <[email protected]>
\ No newline at end of file

Added: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -0,0 +1,85 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Crimson.OpenSsl
+{
+    using System;
+
+    public sealed class HashHelper : IDisposable
+    {
+        private IntPtr context;
+        private readonly int hashSize;
+
+        public HashHelper(IntPtr mdptr, int hashSize)
+        {
+            this.hashSize = hashSize >> 3;
+            this.context = Native.EVP_MD_CTX_create();
+
+            Native.ExpectSuccess(Native.EVP_DigestInit_ex(this.context, mdptr, IntPtr.Zero));
+        }
+
+        ~HashHelper()
+        {
+            Dispose();
+        }
+
+        public void Dispose()
+        {
+            if (this.context != IntPtr.Zero)
+            {
+                Native.EVP_MD_CTX_destroy(this.context);
+                this.context = IntPtr.Zero;
+            }
+
+            GC.SuppressFinalize(this);
+        }
+
+        public unsafe void Update(byte[] data, int start, int length)
+        {
+            if (length == 0)
+            {
+                return;
+            }
+
+            fixed (byte* p = &data[start])
+            {
+                Native.ExpectSuccess(Native.EVP_DigestUpdate(this.context, (IntPtr)p, (uint)length));
+            }
+        }
+
+        public unsafe byte[] Final()
+        {
+            var digest = new byte[this.hashSize];
+            var len = (uint)digest.Length;
+
+            fixed (byte* p = &digest[0])
+            {
+                Native.ExpectSuccess(Native.EVP_DigestFinal_ex(this.context, (IntPtr)p, ref len));
+            }
+
+            return digest;
+        }
+    }
+}


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -0,0 +1,118 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Crimson.OpenSsl
+{
+    using System;
+    using System.Runtime.InteropServices;
+    using System.Security.Cryptography;
+
+    /// <summary>
+    /// Documentation can be found here: http://www.openssl.org/docs/crypto/EVP_DigestInit.html
+    /// </summary>
+    internal class Native
+    {
+        const string Dllname = "libcrypto";
+
+        public static int ExpectSuccess(int ret)
+        {
+            if (ret <= 0)
+            {
+                throw new CryptographicException();
+            }
+
+            return ret;
+        }
+
+        //
+        // Digests
+        //
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_md5();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_sha1();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_sha256();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_MD_CTX_create();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static void EVP_MD_CTX_destroy(IntPtr ctx);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_DigestInit_ex(IntPtr ctx, IntPtr type, IntPtr impl);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_DigestUpdate(IntPtr ctx, IntPtr d, uint cnt);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_DigestFinal_ex(IntPtr ctx, IntPtr md, ref uint s);
+
+        //
+        // Ciphers
+        //
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_128_cbc();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_192_cbc();
+        
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_256_cbc();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_128_ecb();
+        
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_192_ecb();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_aes_256_ecb();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static IntPtr EVP_CIPHER_CTX_new();
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_CIPHER_CTX_free(IntPtr a);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_CipherInit_ex(IntPtr ctx, IntPtr type, IntPtr impl, IntPtr key, IntPtr iv, int enc);
+
+        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+        public extern static int EVP_CipherUpdate(IntPtr ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
+    }
+}


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -0,0 +1,109 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Crimson.OpenSsl
+{
+    using System;
+    using System.Security.Cryptography;
+    using Crimson.Common;
+
+    public unsafe class OpenSslCryptoTransform : CryptoTransformBase
+    {
+        private IntPtr context;
+
+        public OpenSslCryptoTransform(SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
+            : base(algo, encrypt, rgbKey, rgbIV)
+        {
+            this.context = Native.EVP_CIPHER_CTX_new();
+
+            var cptr = this.GetCipher(algo.Mode, rgbKey.Length);
+
+            fixed (byte *pkey = &rgbKey[0])
+            fixed (byte* piv = &iv[0])
+            {
+                Native.ExpectSuccess(Native.EVP_CipherInit_ex(this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, encrypt? 1: 0));
+            }
+
+            Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_key_length(this.context, rgbKey.Length));
+            Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_padding(this.context, 0));
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (this.context != IntPtr.Zero)
+            {
+                Native.EVP_CIPHER_CTX_free(this.context);
+                this.context = IntPtr.Zero;
+            }
+
+            base.Dispose(disposing);
+        }
+
+        protected override void Transform(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount)
+        {
+            fixed (byte* input = &inputBuffer[inputOffset])
+            fixed (byte* output = &outputBuffer[outputOffset])
+            {
+                int outputCount;
+                Native.ExpectSuccess(Native.EVP_CipherUpdate(this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
+            }
+        }
+
+        private IntPtr GetCipher(CipherMode mode, int keyLength)
+        {
+            if (mode == CipherMode.CBC)
+            {
+                switch (keyLength)
+                {
+                    case 16:
+                        return Native.EVP_aes_128_cbc();
+
+                    case 24:
+                        return Native.EVP_aes_192_cbc();
+
+                    case 32:
+                        return Native.EVP_aes_256_cbc();
+                }
+            }
+            else if (mode == CipherMode.ECB)
+            {
+                switch (keyLength)
+                {
+                    case 16:
+                        return Native.EVP_aes_128_ecb();
+
+                    case 24:
+                        return Native.EVP_aes_192_ecb();
+
+                    case 32:
+                        return Native.EVP_aes_256_ecb();
+                }
+            }
+
+            throw new CryptographicException(string.Format("{0} not supported", mode));
+        }
+    }
+}


Added: class/Crimson.OpenSsl/LICENSE
===================================================================
@@ -0,0 +1,20 @@
+Copyright 2013 Symform Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: class/Crimson.OpenSsl/Makefile
===================================================================
@@ -0,0 +1,84 @@
+CSC=gmcs
+
+CSC_FLAGS= -optimize
+#CSC_FLAGS= -debug
+
+SOURCES = \
+	Crimson.OpenSsl/Native.cs			\
+	Crimson.OpenSsl/HashHelper.cs		\
+	Crimson.OpenSsl/OpenSslCryptoTransform.cs			\
+	AssemblyInfo.cs					\
+	../../common/Locale.cs \
+	../../common/CryptoTransformBase.cs
+
+all: Crimson.OpenSsl.dll
+
+GENERATED_SOURCES = \
+	Crimson.Security.Cryptography/AesOpenSsl.g.cs	\
+	Crimson.Security.Cryptography/RijndaelOpenSsl.g.cs	\
+	Crimson.Security.Cryptography/MD5OpenSsl.g.cs	\
+	Crimson.Security.Cryptography/SHA1OpenSsl.g.cs	\
+	Crimson.Security.Cryptography/SHA256OpenSsl.g.cs
+
+tools/generator.exe: tools/generator.cs
+	$(CSC) -t:exe -out:$@ $^
+
+$(GENERATED_SOURCES): tools/generator.exe
+	mono tools/generator.exe Crimson.Security.Cryptography
+
+AssemblyInfo.cs:
+	@ver='tarball'; \
+	if test -d $(CURDIR)/../../.git; then \
+	  cd $(CURDIR)/../..; \
+	  LANG=C; export LANG; \
+	  branch=`git branch | grep '^\*' | cut -d ' ' -f 2`; \
+	  version=`git log --no-color --first-parent -n1 --pretty=format:%h`; \
+	  if [ "$$branch" = '(no' ]; then \
+	    ver="$$version"; \
+	  else \
+	    ver="$$branch/$$version"; \
+	  fi; \
+	  cd $(CURDIR); \
+	fi; \
+	( \
+	  echo "using System.Reflection;"; \
+	  echo "[assembly:AssemblyInformationalVersionAttribute(\"$${ver}\")]"; \
+	) > $@
+
+Crimson.OpenSsl.dll: $(SOURCES) $(GENERATED_SOURCES)
+	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
+
+torture.exe: Crimson.OpenSsl.dll tools/torture.cs
+	dmcs -debug tools/torture.cs -r:Crimson.OpenSsl.dll -out:torture.exe
+
+torture: torture.exe
+	mono --debug torture.exe -v
+
+clean:
+	rm -f torture.exe
+	rm -f tools/generator.exe
+	rm -f $(GENERATED_SOURCES) AssemblyInfo.cs
+	rm -f *.dll*
+
+BASE_TESTS = \
+	../../tests/AesTest.cs			\
+	../../tests/HashAlgorithmTest.cs	\
+	../../tests/RijndaelTest.cs		\
+	../../tests/SHA1Test.cs			\
+	../../tests/SHA256Test.cs		\
+	../../tests/SymmetricAlgorithmTest.cs
+
+GENERATED_TESTS = \
+	Tests/AesOpenSslTests.cs		\
+	Tests/RijndaelOpenSslTests.cs	\
+	Tests/SHA1OpenSslTests.cs		\
+	Tests/SHA256OpenSslTests.cs	\
+
+Crimson.OpenSsl.Tests.dll: $(BASE_TESTS) $(GENERATED_TESTS) Crimson.OpenSsl.dll
+	mcs -debug $(BASE_TESTS) $(GENERATED_TESTS) -t:library -out:$@ -r:Crimson.OpenSsl.dll -pkg:mono-nunit
+
+test: Crimson.OpenSsl.Tests.dll
+
+run-test: test
+	@echo running tests
+	nunit-console Crimson.OpenSsl.Tests.dll

Added: class/Crimson.OpenSsl/README
===================================================================
@@ -0,0 +1,67 @@
+This assembly goal is to provide a managed wrapper on to /dev/crypto
+as provided by either `cryptodev` [1] or OCF [2].
+
+References:
+[1] http://home.gna.org/cryptodev-linux/
+[2] http://ocf-linux.sourceforge.net
+
+
+/dev/crypto Availability
+----------------------
+
+Most Linux distributions do not ship /dev/crypto so you'll have to:
+
+1. build it yourself (from one of the above links);
+
+2. install the driver, e.g.
+
+	sudo insmod /path/to/cryptodev.ko
+
+3. give read/write permissions to the device, e.g. for everyone do:
+
+	sudo chmod 666 /dev/crypto
+
+
+Building
+--------
+
+If a recent mono is available then 'make' should be enough to build
+the generator (creating the source files) and then build the assembly
+
+You can verify that everything works, if nunit is available, by doing
+'make run-test'
+
+
+cryptodev/mv_cesa specific notes
+--------------------------------
+
+Hardware have limited internal buffers to work on. The drivers should 
+make this limit invisible to callers. This is not (always) the case.
+
+Testing as show that the hardware limit is hit if we use more than:
+
+1920 bytes for SHA1
+1936 bytes for AES
+
+As such the code can be adapted to work with those limits. By default
+the implementations will use a limit of Int32.MaxValue but, if defined
+differently, will iterate large buffers based on a smaller limit (and
+workaround the driver limitation).
+
+Changing this limit is done using environment variables, e.g.
+
+CRIMSON_AES_BUFFER_BLOCK_SIZE=1936 make run-test
+
+will run the unit tests using a block size limited to 1936 bytes.
+While
+
+CRIMSON_SHA1_BUFFER_BLOCK_SIZE=1920 make run-test
+
+will run the unit tests with a block size limited to 1920 bytes.
+
+This way each algorithm limitation can be configured separately. Even
+if the limit is likely identical between many of them.
+
+Since having those limits potentially requires a lot more native/kernels
+calls, reducing overall performance, it should only be used if required.
+

Added: class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
===================================================================
@@ -0,0 +1,51 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl {
+
+	[TestFixture]
+	public class AesKernelTest : AesTest {
+		
+		[SetUp]
+		protected void SetUp () 
+		{
+			algo = Create (); // shared
+		}
+
+		protected override SymmetricAlgorithm Create ()
+		{
+			return new AesOpenSsl ();
+		}
+	}
+}
\ No newline at end of file

Added: class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
===================================================================
@@ -0,0 +1,518 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl {
+
+    [TestFixture]
+    public class RijndaelOpenSslTests : RijndaelTest
+    {
+        [SetUp]
+        protected void SetUp()
+        {
+            this.algo = this.Create(); // shared
+        }
+
+        protected override SymmetricAlgorithm Create()
+        {
+            return new RijndaelOpenSsl();
+        }
+
+        static bool Compare(byte[] actual, byte[] expected)
+        {
+            if (actual == null)
+                return (expected == null);
+            if (expected == null)
+                return false;
+            if (actual.Length != expected.Length)
+                return false;
+            for (int i = 0; i < actual.Length; i++)
+            {
+                if (actual[i] != expected[i])
+                    return false;
+            }
+            return true;
+        }
+
+        [Test]
+        public void CbcIvBlock()
+        {
+            byte[] key = this.algo.Key;
+            byte[] iv = this.algo.IV;
+            this.algo.Mode = CipherMode.CBC;
+
+            // 1952 = max mv_cesa + one block
+            for (int i = 16; i <= 1952; i += 16)
+            {
+                byte[] data = new byte[i];
+                byte[] enc1 = this.algo.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
+                byte[] enc2 = null;
+                using (Rijndael r = new RijndaelManaged())
+                {
+                    r.Mode = CipherMode.CBC;
+                    r.Key = key;
+                    r.IV = iv;
+                    enc2 = this.algo.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
+                }
+
+                if (!Compare(enc1, enc2))
+                    Assert.Fail("Data size = " + i);
+            }
+        }
+
+        private static byte[] key1 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+        private static byte[] key2 = { 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01 };
+        private static byte[] key3 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+
+        protected byte[] CombineKeys(byte[] key1, byte[] key2, byte[] key3)
+        {
+            int k1l = key1.Length;
+            int k2l = key2.Length;
+            int k3l = key3.Length;
+            byte[] key = new byte[k1l + k2l + k3l];
+            Array.Copy(key1, 0, key, 0, k1l);
+            Array.Copy(key2, 0, key, k1l, k2l);
+            Array.Copy(key3, 0, key, k1l + k2l, k3l);
+            return key;
+        }
+
+        private Rijndael GetAES()
+        {
+            Rijndael aes = (Rijndael)this.Create();
+            aes.Key = this.CombineKeys(key1, key2, key3);
+            return aes;
+        }
+
+        private byte[] GetData(byte size)
+        {
+            byte[] data = new byte[size];
+            for (byte i = 0; i < size; i++)
+            {
+                data[i] = i;
+            }
+            return data;
+        }
+
+        private byte[] Decrypt(SymmetricAlgorithm algo, PaddingMode padding, byte[] data)
+        {
+            algo.IV = new byte[algo.BlockSize >> 3];
+            algo.Mode = CipherMode.CBC;
+            algo.Padding = padding;
+            ICryptoTransform ct = algo.CreateDecryptor();
+            return ct.TransformFinalBlock(data, 0, data.Length);
+        }
+
+        private byte[] Encrypt(SymmetricAlgorithm algo, PaddingMode padding, byte[] data)
+        {
+            algo.IV = new byte[algo.BlockSize >> 3];
+            algo.Mode = CipherMode.CBC;
+            algo.Padding = padding;
+            ICryptoTransform ct = algo.CreateEncryptor();
+            return ct.TransformFinalBlock(data, 0, data.Length);
+        }
+
+        [Test]
+        [ExpectedException(typeof(CryptographicException))]
+        public void RijndaelNone_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+        }
+
+        [Test]
+        public void RijndaelNone_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB", BitConverter.ToString(encdata), "RijndaelNone_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.None, encdata);
+            this.AssertEquals("RijndaelNone_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        [ExpectedException(typeof(CryptographicException))]
+        public void RijndaelNone_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+        }
+
+        [Test]
+        public void RijndaelNone_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            // note: encrypted data is truncated to a multiple of block size
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF", BitConverter.ToString(encdata), "RijndaelNone_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.None, encdata);
+            this.AssertEquals("RijndaelNone_ExactMultipleBlockSize_Decrypt", this.GetData(48), decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("AB-E0-20-5E-BC-28-A0-B7-A7-56-A3-BF-13-55-13-7E", BitConverter.ToString(encdata), "RijndaelPKCS7_SmallerThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_SmallerThanOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-60-CE-9F-E0-72-3B-D6-D1-A5-F8-33-D8-25-31-7F-D4", BitConverter.ToString(encdata), "RijndaelPKCS7_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-06-3F-D3-51-8D-55-E9-2F-02-4A-4E-F2-91-55-31-83", BitConverter.ToString(encdata), "RijndaelPKCS7_MoreThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_MoreThanOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF-37-42-81-21-47-A7-E0-AA-64-A7-8B-65-25-95-AA-54", BitConverter.ToString(encdata), "RijndaelPKCS7_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_ExactMultipleBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelZeros_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("DD-BE-D7-CE-E2-DD-5C-A3-3E-44-A1-76-00-E5-5B-5D", BitConverter.ToString(encdata), "RijndaelZeros_SmallerThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            Assert.AreEqual("00-01-02-03-04-05-06-07-00-00-00-00-00-00-00-00", BitConverter.ToString(decdata), "RijndaelZeros_SmallerThanOneBlockSize_Decrypt");
+        }
+
+        [Test]
+        public void RijndaelZeros_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB", BitConverter.ToString(encdata), "RijndaelZeros_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            this.AssertEquals("RijndaelZeros_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelZeros_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-04-6C-F7-A5-DE-FF-B4-30-29-7A-0E-04-3B-D4-B8-F2", BitConverter.ToString(encdata), "RijndaelZeros_MoreThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            Assert.AreEqual("00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-10-11-12-13-00-00-00-00-00-00-00-00-00-00-00-00", BitConverter.ToString(decdata), "RijndaelZeros_MoreThanOneBlockSize_Decrypt");
+        }
+
+        [Test]
+        public void RijndaelZeros_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF", BitConverter.ToString(encdata), "RijndaelZeros_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            this.AssertEquals("RijndaelZeros_ExactMultipleBlockSize_Decrypt", this.GetData(48), decdata);
+        }
+
+        private byte[] GetKey(SymmetricAlgorithm sa)
+        {
+            byte[] key = new byte[sa.KeySize >> 3];
+            // no weak key this way (DES, TripleDES)
+            for (byte i = 0; i < key.Length; i++)
+                key[i] = i;
+            return key;
+        }
+
+        private byte[] GetIV(SymmetricAlgorithm sa)
+        {
+            return new byte[sa.BlockSize >> 3];
+        }
+
+        private ICryptoTransform GetEncryptor(SymmetricAlgorithm sa, PaddingMode mode)
+        {
+            sa.Mode = CipherMode.ECB; // basic (no) mode
+            sa.Padding = mode;
+            return sa.CreateEncryptor(this.GetKey(sa), this.GetIV(sa));
+        }
+
+        private ICryptoTransform GetDecryptor(SymmetricAlgorithm sa, PaddingMode mode)
+        {
+            sa.Mode = CipherMode.ECB; // basic (no) mode
+            sa.Padding = mode;
+            return sa.CreateDecryptor(this.GetKey(sa), this.GetIV(sa));
+        }
+
+        // the best way to verify padding is to:
+        // a. encrypt data larger than one block with a padding mode "X"
+        // b. decrypt the data with padding mode "None"
+        // c. compare the last (padding) bytes with the expected padding
+
+        private void ANSIX923_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ANSIX923);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ANSI X.923 is all 0 except last byte (length)
+            for (int i = 0; i < bs - 1; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ANSIX923_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ANSIX923);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ANSI X.923 is all 0 except last byte (length)
+            for (int i = 0; i < pd - 1; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ISO10126_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ISO10126);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ISO10126 is all random except last byte (length)
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ISO10126_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ISO10126);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ISO10126 is all random except last byte (length)
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void PKCS7_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.PKCS7);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - PKCS7 is all padding char
+            for (int i = 0; i < bs; i++)
+                Assert.AreEqual(pd, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        private void PKCS7_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.PKCS7);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - PKCS7 is all padding char
+            for (int i = 0; i < pd; i++)
+                Assert.AreEqual(pd, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        private void Zeros_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            for (int i = 0; i < data.Length; i++)
+                data[i] = 0xFF;
+
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.Zeros);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // NO extra block is used for zero padding
+            Assert.AreEqual(data.Length, encdata.Length, "no extra block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            // now validate absence of padding
+            Assert.AreEqual(0xFF, decdata[decdata.Length - 1], "no padding");
+        }
+
+        private void Zeros_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            for (int i = 0; i < data.Length; i++)
+                data[i] = 0xFF;
+
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.Zeros);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - Zeros is all 0x00 char
+            for (int i = 0; i < pd; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        [Test]
+        public void Rijndael_ANSIX923_Full()
+        {
+            this.ANSIX923_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ANSIX923_Partial()
+        {
+            this.ANSIX923_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ISO10126_Full()
+        {
+            this.ISO10126_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ISO10126_Partial()
+        {
+            this.ISO10126_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_PKCS7_Full()
+        {
+            this.PKCS7_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_PKCS7_Partial()
+        {
+            this.PKCS7_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_Zeros_Full()
+        {
+            this.Zeros_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_Zeros_Partial()
+        {
+            this.Zeros_Partial(this.Create());
+        }
+    }
+}


Added: class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
===================================================================
@@ -0,0 +1,46 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+    [TestFixture]
+    public class SHA1OpenSslTests : SHA1Test
+    {
+        [SetUp]
+        protected void SetUp()
+        {
+            hash = new SHA1OpenSsl();
+        }
+    }
+}


Added: class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs
===================================================================
@@ -0,0 +1,46 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+    [TestFixture]
+    public class SHA256OpenSslTests : SHA256Test
+    {
+        [SetUp]
+        protected void SetUp()
+        {
+            hash = new SHA256OpenSsl();
+        }
+    }
+}


Added: class/Crimson.OpenSsl/tools/generator.cs
===================================================================
@@ -0,0 +1,222 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+class Program {
+
+	static void GenerateHash (string name)
+	{
+		string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// 'Software'), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Security.Cryptography;
+using Crimson.OpenSsl;
+
+namespace Crimson.Security.Cryptography {
+
+	public class {0}OpenSsl : {0} {
+
+        private HashHelper helper;
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && helper != null)
+            {
+                helper.Dispose();
+                helper = null;
+            }
+            base.Dispose(disposing);
+        }
+
+        public override void Initialize()
+        {
+            helper = new HashHelper(Native.EVP_sha1(), this.HashSize);
+        }
+
+        protected override void HashCore(byte[] data, int start, int length)
+        {
+            if (this.helper == null)
+            {
+                this.Initialize();
+            }
+
+            helper.Update(data, start, length);
+        }
+
+        protected override byte[] HashFinal()
+        {
+            if (this.helper == null)
+            {
+                this.Initialize();
+            }
+
+            return helper.Final();
+        }
+	}
+}";
+		string filename = Path.Combine (OutputDirectory,
+			String.Format ("{0}OpenSsl.g.cs", name));
+		string content = template.Replace ("{0}", name).
+			Replace ("{1}", name.ToUpperInvariant ());
+		File.WriteAllText (filename, content);
+	}
+
+	static void GenerateSymmetricAlgorithm (string name, string fallback, string ecb, string cbc)
+	{
+		string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author: Bassam Tabbara  <[email protected]>
+// See LICENSE for copyrights and restrictions
+//
+using System.Security.Cryptography;
+using Crimson.OpenSsl;
+
+namespace Crimson.Security.Cryptography {
+
+	public class {0}OpenSsl : {0} {
+		
+        public static RandomNumberGenerator Rng = RandomNumberGenerator.Create();
+
+        public override void GenerateIV()
+        {
+            IVValue = new byte[BlockSizeValue >> 3];
+            Rng.GetBytes(IVValue);
+        }
+
+        public override void GenerateKey()
+        {
+            KeyValue = new byte[KeySizeValue >> 3];
+            Rng.GetBytes(KeyValue);
+        }
+
+        public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
+        {
+            try
+            {
+                if (BlockSize == 128)
+                {
+                    return new OpenSslCryptoTransform(this, false, rgbKey, rgbIV);
+                }
+            }
+            catch (CryptographicException)
+            {
+            }
+
+            using (var r = this.Fallback())
+            {
+                return r.CreateDecryptor(rgbKey, rgbIV);
+            }
+        }
+
+        public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
+        {
+            try
+            {
+                if (BlockSize == 128)
+                {
+                    return new OpenSslCryptoTransform(this, true, rgbKey, rgbIV);
+                }
+            }
+            catch (CryptographicException)
+            {
+            }
+
+            using (var r = this.Fallback())
+            {
+                return r.CreateEncryptor(rgbKey, rgbIV);
+            }
+        }
+
+        private Rijndael Fallback()
+        {
+            Rijndael r = new RijndaelManaged();
+            r.Mode = Mode;
+            r.Padding = Padding;
+            r.BlockSize = BlockSize;
+            return r;
+        }
+	}
+}";
+		string filename = Path.Combine (OutputDirectory,
+			String.Format ("{0}OpenSsl.g.cs", name));
+		string content = template.Replace ("{0}", name).
+			Replace ("{1}", fallback).
+			Replace ("{2}", ecb).
+			Replace ("{3}", cbc).
+			Replace ("{4}", name.ToUpperInvariant ());
+		File.WriteAllText (filename, content);
+	}
+
+	static string OutputDirectory { get; set; }
+
+	static void Main (string[] args)
+	{
+		OutputDirectory = args.Length == 0 ? "." : args [0];
+
+		GenerateHash ("SHA1");		// CRYPTO_SHA1
+		GenerateHash ("SHA256");	// CRYPTO_SHA256
+		GenerateHash ("MD5");		// CRYPTO_MD5
+#if UNTESTED
+		GenerateHash ("RIPEMD160");	// CRYPTO_RIPEMD160
+		GenerateHash ("SHA384");	// CRYPTO_SHA2_384
+		GenerateHash ("SHA512");	// CRYPTO_SHA2_512
+#endif
+		GenerateSymmetricAlgorithm ("Rijndael", "RijndaelManaged", "AES_ECB", "AES_CBC");
+		GenerateSymmetricAlgorithm ("Aes", "RijndaelManaged", "AES_ECB", "AES_CBC");
+#if UNTESTED
+		GenerateSymmetricAlgorithm ("Des", "DESCryptoServiceProvider", null, "DES_CBC");
+		GenerateSymmetricAlgorithm ("TripleDes", "TripleDESCryptoServiceProvider", null, "3DES_CBC");
+		// BLF (Blowfish), CAST, SKIPJACK and Camellia are not part of the .NET framework 
+		// and would require a additional base classes and fallbacks
+#endif
+	}
+}

Added: class/Crimson.OpenSsl/tools/torture.cs
===================================================================
@@ -0,0 +1,256 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2012 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Crimson.Security.Cryptography;
+
+class Program {
+
+	static bool verbose;
+
+	static byte[] sha_a_input = Encoding.Default.GetBytes ("abc");
+	static byte[] sha_b_input = Encoding.Default.GetBytes ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+	static byte[] sha_c_input;
+
+	static Program ()
+	{
+		sha_c_input = new byte [1000000];
+		for (int i = 0; i < 1000000; i++)
+			sha_c_input[i] = 0x61; // a
+	}
+
+	static void Main (string [] args)
+	{
+		verbose = args.Length > 0;
+
+		Parallel.Invoke (
+			() => { SHA1a ();	},
+			() => { SHA1b ();	},
+			() => { SHA1c ();	},
+			() => { SHA256a ();	},
+			() => { SHA256b ();	},
+			() => { SHA256c ();	},
+			() => { AESa ();	},
+			() => { AESb ();	},
+			() => { AESc ();	},
+			() => { AESd ();	}
+		);
+		Console.WriteLine ("End");
+        }
+
+	static void SHA1 (string name, int max, byte[] input, byte[] output)
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (SHA1 digest = new SHA1Kernel ()) {
+					if (!Compare (output, digest.ComputeHash (input)))
+						throw new Exception (name + " " + i.ToString ());
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+	static byte[] sha1_a_output = new byte [] {
+		0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 
+		0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d };
+
+	static void SHA1a ()
+	{
+		SHA1 ("SHA1a", 10000, sha_a_input, sha1_a_output);
+	}
+
+	static byte[] sha1_b_output = new byte [] {
+		0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae, 
+		0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 };
+
+	static void SHA1b ()
+	{
+		SHA1 ("SHA1b", 5000, sha_b_input, sha1_b_output);
+	}
+
+	static byte[] sha1_c_output = new byte [] {
+		0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e, 
+		0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f };
+
+	static void SHA1c ()
+	{
+		SHA1 ("SHA1c", 2000, sha_c_input, sha1_c_output);
+	}
+
+	static void SHA256 (string name, int max, byte[] input, byte[] output)
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (SHA256 digest = new SHA256Kernel ()) {
+					if (!Compare (output, digest.ComputeHash (input)))
+						throw new Exception (name + " " + i.ToString ());
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+	static byte[] sha256_a_output = new byte [] {
+		0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 
+		0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 
+		0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 
+		0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad };
+
+	static void SHA256a ()
+	{
+		SHA256 ("SHA256a", 8000, sha_a_input, sha256_a_output);
+	}
+
+	static byte[] sha256_b_output = new byte [] {
+		0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 
+		0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 
+		0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 
+		0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 };
+
+	static void SHA256b ()
+	{
+		SHA256 ("SHA256b", 4000, sha_b_input, sha256_b_output);
+	}
+
+	static byte[] sha256_c_output = new byte [] {
+		0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 
+		0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 
+		0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 
+		0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 };
+
+	static void SHA256c ()
+	{
+		SHA256 ("SHA256c", 2000, sha_c_input, sha256_c_output);
+	}
+
+	static void Process (string name, int iteration, int max)
+	{
+		if (!verbose)
+			return;
+		if (iteration % 1000 == 0)
+			Console.WriteLine ("{0} {1}/{2} ({3})", name, iteration, max, Thread.CurrentThread.ManagedThreadId);
+	}
+
+	static byte[] aes_iv = new byte [16];
+
+	static void AES (string name, int max, byte[] key, byte[] input, byte[] expected) 
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (Aes cipher = new AesKernel ()) {
+					cipher.Mode = CipherMode.ECB;
+					cipher.KeySize = key.Length * 8;
+					cipher.Padding = PaddingMode.Zeros;
+
+					byte[] output = new byte [input.Length];
+					ICryptoTransform encryptor = cipher.CreateEncryptor (key, aes_iv);
+					encryptor.TransformBlock (input, 0, input.Length, output, 0);
+					if (!Compare (output, expected))
+						throw new Exception ("encryptor");
+	
+					byte[] original = new byte [output.Length];
+					ICryptoTransform decryptor = cipher.CreateDecryptor (key, aes_iv); 
+					decryptor.TransformBlock (output, 0, output.Length, original, 0);
+					if (!Compare (original, input))
+						throw new Exception ("decryptor");
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+
+	static byte[] aes_a_key = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
+	static byte[] aes_a_input = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
+	static byte[] aes_a_expected = { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
+
+	static void AESa () 
+	{
+		AES ("AESa", 4000, aes_a_key, aes_a_input, aes_a_expected);
+	}
+
+	static byte[] aes_b_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+	static byte[] aes_b_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_b_expected = { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a };
+
+	static void AESb () 
+	{
+		AES ("AESb", 4000, aes_b_key, aes_b_input, aes_b_expected);
+	}
+
+	static byte[] aes_c_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+	static byte[] aes_c_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_c_expected = { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 };
+
+	static void AESc () 
+	{
+		AES ("AESc", 3000, aes_c_key, aes_c_input, aes_c_expected);
+	}
+
+	static byte[] aes_d_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+	static byte[] aes_d_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_d_expected = { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
+
+	static void AESd () 
+	{
+		AES ("AESc", 2000, aes_d_key, aes_d_input, aes_d_expected);
+	}
+
+	static bool Compare (byte[] actual, byte[] expected)
+	{
+		if (actual == null)
+			return (expected == null);
+		if (expected == null)
+			return false;
+		if (actual.Length != expected.Length)
+			return false;
+		for (int i=0; i < actual.Length; i++) {
+			if (actual [i] != expected [i])
+				return false;
+		}
+		return true;
+	}
+}

Added: common/CryptoTransformBase.cs
===================================================================
@@ -0,0 +1,406 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2012 Symform Inc.
+//
+// This code is based on:
+
+//
+// Mono.Security.Cryptography.SymmetricTransform implementation
+//
+// Authors:
+//	Thomas Neidhart ([email protected])
+//	Sebastien Pouliot <[email protected]>
+//
+// Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+namespace Crimson.Common
+{
+    public abstract class CryptoTransformBase : ICryptoTransform
+    {
+        bool encrypt;
+        int BlockSizeByte;
+        byte[] workBuff;
+        bool lastBlock;
+        PaddingMode padding;
+        protected byte[] iv;
+
+        public CryptoTransformBase(SymmetricAlgorithm algo, bool encryption, byte[] rgbKey, byte[] rgbIV)
+        {
+            if (rgbKey == null)
+                throw new CryptographicException("Invalid (null) key");
+
+            BlockSizeByte = (algo.BlockSize >> 3);
+
+            if (rgbIV == null)
+            {
+                iv = new byte[BlockSizeByte];
+                this.Random(iv, 0, BlockSizeByte);
+            }
+            else
+            {
+                // 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);
+                }
+                iv = (byte[])rgbIV.Clone();
+            }
+
+            encrypt = encryption;
+            padding = algo.Padding;
+
+            // transform buffer
+            workBuff = new byte[BlockSizeByte];
+        }
+
+        ~CryptoTransformBase()
+        {
+            Dispose(false);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+        }
+
+        public virtual bool CanTransformMultipleBlocks
+        {
+            get { return true; }
+        }
+
+        public virtual bool CanReuseTransform
+        {
+            get { return false; }
+        }
+
+        public virtual int InputBlockSize
+        {
+            get { return BlockSizeByte; }
+        }
+
+        public virtual int OutputBlockSize
+        {
+            get { return BlockSizeByte; }
+        }
+
+        protected abstract void Transform(byte[] input, int inputOffset, byte[] output, int outputOffset, int length);
+
+        private void CheckInput(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            if (inputBuffer == null)
+                throw new ArgumentNullException("inputBuffer");
+            if (inputOffset < 0)
+                throw new ArgumentOutOfRangeException("inputOffset", "< 0");
+            if (inputCount < 0)
+                throw new ArgumentOutOfRangeException("inputCount", "< 0");
+            // ordered to avoid possible integer overflow
+            if (inputOffset > inputBuffer.Length - inputCount)
+                throw new ArgumentException("inputBuffer", Locale.GetText("Overflow"));
+        }
+
+        // this method may get called MANY times so this is the one to optimize
+        public virtual int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+        {
+            CheckInput(inputBuffer, inputOffset, inputCount);
+            // check output parameters
+            if (outputBuffer == null)
+                throw new ArgumentNullException("outputBuffer");
+            if (outputOffset < 0)
+                throw new ArgumentOutOfRangeException("outputOffset", "< 0");
+
+            // ordered to avoid possible integer overflow
+            int len = outputBuffer.Length - inputCount - outputOffset;
+            if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros)))
+            {
+                throw new CryptographicException("outputBuffer", Locale.GetText("Overflow"));
+            }
+            else if (KeepLastBlock)
+            {
+                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) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
+            }
+        }
+
+        private int InternalTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+        {
+            int offs = inputOffset;
+            int full;
+
+            // this way we don't do a modulo every time we're called
+            // and we may save a division
+            if (inputCount != BlockSizeByte)
+            {
+                if ((inputCount % BlockSizeByte) != 0)
+                    throw new CryptographicException("Invalid input block size.");
+
+                full = inputCount / BlockSizeByte;
+            }
+            else
+                full = 1;
+
+            if (KeepLastBlock)
+                full--;
+
+            int total = 0;
+
+            if (lastBlock)
+            {
+                Transform(workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
+                outputOffset += BlockSizeByte;
+                total += BlockSizeByte;
+                lastBlock = false;
+            }
+
+            if (full > 0)
+            {
+                int length = full * BlockSizeByte;
+                Transform(inputBuffer, offs, outputBuffer, outputOffset, length);
+                offs += length;
+                outputOffset += length;
+                total += length;
+            }
+
+            if (KeepLastBlock)
+            {
+                Buffer.BlockCopy(inputBuffer, offs, workBuff, 0, BlockSizeByte);
+                lastBlock = true;
+            }
+
+            return total;
+        }
+
+        RandomNumberGenerator _rng;
+
+        private void Random(byte[] buffer, int start, int length)
+        {
+            if (_rng == null)
+            {
+                _rng = RandomNumberGenerator.Create();
+            }
+            byte[] random = new byte[length];
+            _rng.GetBytes(random);
+            Buffer.BlockCopy(random, 0, buffer, start, length);
+        }
+
+        private void ThrowBadPaddingException(PaddingMode padding, int length, int position)
+        {
+            string msg = String.Format(Locale.GetText("Bad {0} padding."), padding);
+            if (length >= 0)
+                msg += String.Format(Locale.GetText(" Invalid length {0}."), length);
+            if (position >= 0)
+                msg += String.Format(Locale.GetText(" Error found at position {0}."), position);
+            throw new CryptographicException(msg);
+        }
+
+        private byte[] FinalEncrypt(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            // are there still full block to process ?
+            int full = (inputCount / BlockSizeByte) * BlockSizeByte;
+            int rem = inputCount - full;
+            int total = full;
+
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                case PaddingMode.ISO10126:
+                case PaddingMode.PKCS7:
+                    // we need to add an extra block for padding
+                    total += BlockSizeByte;
+                    break;
+                default:
+                    if (inputCount == 0)
+                        return new byte[0];
+                    if (rem != 0)
+                    {
+                        if (padding == PaddingMode.None)
+                            throw new CryptographicException("invalid block length");
+                        // zero padding the input (by adding a block for the partial data)
+                        byte[] paddedInput = new byte[full + BlockSizeByte];
+                        Buffer.BlockCopy(inputBuffer, inputOffset, paddedInput, 0, inputCount);
+                        inputBuffer = paddedInput;
+                        inputOffset = 0;
+                        inputCount = paddedInput.Length;
+                        total = inputCount;
+                    }
+                    break;
+            }
+
+            byte[] res = new byte[total];
+            int outputOffset = 0;
+
+            // process all blocks except the last (final) block
+            if (total > BlockSizeByte)
+            {
+                outputOffset = InternalTransformBlock(inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
+                inputOffset += outputOffset;
+            }
+
+            // now we only have a single last block to encrypt
+            byte pad = (byte)(BlockSizeByte - rem);
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                    // XX 00 00 00 00 00 00 07 (zero + padding length)
+                    res[res.Length - 1] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                case PaddingMode.ISO10126:
+                    // XX 3F 52 2A 81 AB F7 07 (random + padding length)
+                    Random(res, res.Length - pad, pad - 1);
+                    res[res.Length - 1] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                case PaddingMode.PKCS7:
+                    // XX 07 07 07 07 07 07 07 (padding length)
+                    for (int i = res.Length; --i >= (res.Length - pad); )
+                        res[i] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                default:
+                    InternalTransformBlock(inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
+                    break;
+            }
+            return res;
+        }
+
+        private byte[] FinalDecrypt(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            if ((inputCount % BlockSizeByte) > 0)
+                throw new CryptographicException("Invalid input block size.");
+
+            int total = inputCount;
+            if (lastBlock)
+                total += BlockSizeByte;
+
+            byte[] res = new byte[total];
+            int outputOffset = 0;
+
+            if (inputCount > 0)
+                outputOffset = InternalTransformBlock(inputBuffer, inputOffset, inputCount, res, 0);
+
+            if (lastBlock)
+            {
+                Transform(workBuff, 0, res, outputOffset, BlockSizeByte);
+                outputOffset += BlockSizeByte;
+                lastBlock = false;
+            }
+
+            // total may be 0 (e.g. PaddingMode.None)
+            byte pad = ((total > 0) ? res[total - 1] : (byte)0);
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    for (int i = pad - 1; i > 0; i--)
+                    {
+                        if (res[total - 1 - i] != 0x00)
+                            ThrowBadPaddingException(padding, -1, i);
+                    }
+                    total -= pad;
+                    break;
+                case PaddingMode.ISO10126:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    total -= pad;
+                    break;
+                case PaddingMode.PKCS7:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    for (int i = pad - 1; i > 0; i--)
+                    {
+                        if (res[total - 1 - i] != pad)
+                            ThrowBadPaddingException(padding, -1, i);
+                    }
+                    total -= pad;
+                    break;
+                case PaddingMode.None:	// nothing to do - it's a multiple of block size
+                case PaddingMode.Zeros:	// nothing to do - user must unpad himself
+                    break;
+            }
+
+            // return output without padding
+            if (total > 0)
+            {
+                byte[] data = new byte[total];
+                Buffer.BlockCopy(res, 0, data, 0, total);
+                // zeroize decrypted data (copy with padding)
+                Array.Clear(res, 0, res.Length);
+                return data;
+            }
+            else
+                return new byte[0];
+        }
+
+        public virtual byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            CheckInput(inputBuffer, inputOffset, inputCount);
+
+            if (encrypt)
+                return FinalEncrypt(inputBuffer, inputOffset, inputCount);
+            else
+                return FinalDecrypt(inputBuffer, inputOffset, inputCount);
+        }
+    }
+}
\ No newline at end of file

   Commit: 1b3c9758415acde1bc071152a694ba6321671498
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 05:51:02 GMT
      URL: https://github.com/mono/crimson/commit/1b3c9758415acde1bc071152a694ba6321671498

Share more code between CryptoDev and OpenSsl implementations. Ignore tests if openssl is not found. Cleanup

Changed paths:
  M class/Crimson.CryptoDev/.gitignore
  M class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
  M class/Crimson.CryptoDev/Makefile
  M class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  M class/Crimson.OpenSsl/Makefile
  M class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
  M common/CryptoTransformBase.cs
Added paths:
  A class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
  A class/Crimson.OpenSsl/Tests/OpenSslTests.cs

Modified: class/Crimson.CryptoDev/.gitignore
===================================================================
@@ -4,3 +4,4 @@ CryptoTools.cs
 SymmetricTransform.cs
 TestResult.xml
 AssemblyInfo.cs
+tools/generator.exe
\ No newline at end of file

Modified: class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
===================================================================
@@ -39,46 +39,23 @@
 using System;
 using System.Runtime.InteropServices;
 using System.Security.Cryptography;
+using Crimson.Common;
 
 using Mono.Security.Cryptography;
 
 namespace Crimson.CryptoDev {
 
-	unsafe class CryptoDevTransform : ICryptoTransform {
-		bool encrypt;
-		int BlockSizeByte;
-		byte[] workBuff;
-		bool lastBlock;
+	unsafe class CryptoDevTransform : CryptoTransformBase {
 		Crypt context;
-		PaddingMode padding;
-		byte[] iv;
 		byte[] save_iv;
 
-		public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encryption, byte[] rgbKey, byte[] rgbIV, int bufferBlockSize) 
+		public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encryption, byte[] rgbKey, byte[] rgbIV, int bufferBlockSize)
+			: base(algo, encryption, rgbKey, rgbIV)
+
 		{
 			if (!Helper.IsAvailable (cipher))
 				throw new CryptographicException (String.Format ("{0} not available from /dev/crypto", algo));
 
-			if (rgbKey == null)
-				throw new CryptographicException ("Invalid (null) key");
-
-			BlockSizeByte = (algo.BlockSize >> 3);
-
-			if (rgbIV == null) {
-				rgbIV = KeyBuilder.IV (BlockSizeByte);
-			} else {
-				// 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);
-				}
-				rgbIV = (byte[]) rgbIV.Clone ();
-			}
-
-			encrypt = encryption;
-			padding = algo.Padding;
-
 			// linux does not requires cloning the file descriptor with CRIOGET
 			Session sess = new Session ();
 			sess.cipher = cipher;
@@ -101,32 +78,18 @@ public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encrypti
 				context.op++;
 			
 			if (algo.Mode != CipherMode.ECB) {
-				iv = rgbIV;
 				save_iv = new byte [BlockSizeByte];
 			}
 
-			// transform buffer
-			workBuff = new byte [BlockSizeByte];
 			// change this value if the driver (e.g. mv_cesa) has a limit that 
 			// it can process in a single shot (e.g. 1936 for AES)
 			BufferBlockSize = bufferBlockSize;
 		}
 
-		~CryptoDevTransform () 
-		{
-			Dispose (false);
-		}
-
-		void IDisposable.Dispose () 
-		{
-			Dispose (true);
-		}
-
-		protected virtual void Dispose (bool disposing) 
+		protected override void Dispose (bool disposing) 
 		{
 			if (context.ses != 0) {
 				Helper.CloseSession (ref context.ses);
-				GC.SuppressFinalize (this);
 			}
 		}
 
@@ -134,23 +97,7 @@ protected virtual void Dispose (bool disposing)
 			get; set;
 		}
 
-		public virtual bool CanTransformMultipleBlocks {
-			get { return true; }
-		}
-
-		public virtual bool CanReuseTransform {
-			get { return false; }
-		}
-
-		public virtual int InputBlockSize {
-			get { return BlockSizeByte; }
-		}
-
-		public virtual int OutputBlockSize {
-			get { return BlockSizeByte; }
-		}
-
-		void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
+		protected override void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
 		{
 			while (length > 0) {
 				int size = Math.Min (length, BufferBlockSize);
@@ -192,266 +139,5 @@ void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset,
 				outputOffset += size;
 			}
 		}
-
-		private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
-		{
-			if (inputBuffer == null)
-				throw new ArgumentNullException ("inputBuffer");
-			if (inputOffset < 0)
-				throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
-			if (inputCount < 0)
-				throw new ArgumentOutOfRangeException ("inputCount", "< 0");
-			// ordered to avoid possible integer overflow
-			if (inputOffset > inputBuffer.Length - inputCount)
-				throw new ArgumentException ("inputBuffer", Locale.GetText ("Overflow"));
-		}
-
-		// this method may get called MANY times so this is the one to optimize
-		public virtual int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
-		{
-			CheckInput (inputBuffer, inputOffset, inputCount);
-			// check output parameters
-			if (outputBuffer == null)
-				throw new ArgumentNullException ("outputBuffer");
-			if (outputOffset < 0)
-				throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
-
-			// ordered to avoid possible integer overflow
-			int len = outputBuffer.Length - inputCount - outputOffset;
-			if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros))) {
-				throw new CryptographicException ("outputBuffer", Locale.GetText ("Overflow"));
-			} else if (KeepLastBlock) {
-				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) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
-			}
-		}
-
-		private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
-		{
-			int offs = inputOffset;
-			int full;
-
-			// this way we don't do a modulo every time we're called
-			// and we may save a division
-			if (inputCount != BlockSizeByte) {
-				if ((inputCount % BlockSizeByte) != 0)
-					throw new CryptographicException ("Invalid input block size.");
-
-				full = inputCount / BlockSizeByte;
-			} else
-				full = 1;
-
-			if (KeepLastBlock)
-				full--;
-
-			int total = 0;
-
-			if (lastBlock) {
-				Transform (workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
-				outputOffset += BlockSizeByte;
-				total += BlockSizeByte;
-				lastBlock = false;
-			}
-
-			if (full > 0) {
-				int length = full * BlockSizeByte;
-				Transform (inputBuffer, offs, outputBuffer, outputOffset, length);
-				offs += length;
-				outputOffset += length;
-				total += length;
-			}
-
-			if (KeepLastBlock) {
-				Buffer.BlockCopy (inputBuffer, offs, workBuff, 0, BlockSizeByte);
-				lastBlock = true;
-			}
-
-			return total;
-		}
-
-		RandomNumberGenerator _rng;
-
-		private void Random (byte[] buffer, int start, int length)
-		{
-			if (_rng == null) {
-				_rng = RandomNumberGenerator.Create ();
-			}
-			byte[] random = new byte [length];
-			_rng.GetBytes (random);
-			Buffer.BlockCopy (random, 0, buffer, start, length);
-		}
-
-		private void ThrowBadPaddingException (PaddingMode padding, int length, int position)
-		{
-			string msg = String.Format (Locale.GetText ("Bad {0} padding."), padding);
-			if (length >= 0)
-				msg += String.Format (Locale.GetText (" Invalid length {0}."), length);
-			if (position >= 0)
-				msg += String.Format (Locale.GetText (" Error found at position {0}."), position);
-			throw new CryptographicException (msg);
-		}
-
-		private byte[] FinalEncrypt (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			// are there still full block to process ?
-			int full = (inputCount / BlockSizeByte) * BlockSizeByte;
-			int rem = inputCount - full;
-			int total = full;
-
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-			case PaddingMode.ISO10126:
-			case PaddingMode.PKCS7:
-				// we need to add an extra block for padding
-				total += BlockSizeByte;
-				break;
-			default:
-				if (inputCount == 0)
-					return new byte [0];
-				if (rem != 0) {
-					if (padding == PaddingMode.None)
-						throw new CryptographicException ("invalid block length");
-					// zero padding the input (by adding a block for the partial data)
-					byte[] paddedInput = new byte [full + BlockSizeByte];
-					Buffer.BlockCopy (inputBuffer, inputOffset, paddedInput, 0, inputCount);
-					inputBuffer = paddedInput;
-					inputOffset = 0;
-					inputCount = paddedInput.Length;
-					total = inputCount;
-				}
-				break;
-			}
-
-			byte[] res = new byte [total];
-			int outputOffset = 0;
-
- 			// process all blocks except the last (final) block
-			if (total > BlockSizeByte) {
-				outputOffset = InternalTransformBlock (inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
-				inputOffset += outputOffset;
-			}
-
-			// now we only have a single last block to encrypt
-			byte pad = (byte) (BlockSizeByte - rem);
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-				// XX 00 00 00 00 00 00 07 (zero + padding length)
-				res [res.Length - 1] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			case PaddingMode.ISO10126:
-				// XX 3F 52 2A 81 AB F7 07 (random + padding length)
-				Random (res, res.Length - pad, pad - 1);
-				res [res.Length - 1] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			case PaddingMode.PKCS7:
-				// XX 07 07 07 07 07 07 07 (padding length)
-				for (int i = res.Length; --i >= (res.Length - pad);) 
-					res [i] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			default:
-				InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
-				break;
-			}
-			return res;
-		}
-
-		private byte[] FinalDecrypt (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			if ((inputCount % BlockSizeByte) > 0)
-				throw new CryptographicException ("Invalid input block size.");
-
-			int total = inputCount;
-			if (lastBlock)
-				total += BlockSizeByte;
-
-			byte[] res = new byte [total];
-			int outputOffset = 0;
-
-			if (inputCount > 0)
-				outputOffset = InternalTransformBlock (inputBuffer, inputOffset, inputCount, res, 0);
-
-			if (lastBlock) {
-				Transform (workBuff, 0, res, outputOffset, BlockSizeByte);
-				outputOffset += BlockSizeByte;
-				lastBlock = false;
-			}
-
-			// total may be 0 (e.g. PaddingMode.None)
-			byte pad = ((total > 0) ? res [total - 1] : (byte) 0);
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				for (int i = pad - 1; i > 0; i--) {
-					if (res [total - 1 - i] != 0x00)
-						ThrowBadPaddingException (padding, -1, i);
-				}
-				total -= pad;
-				break;
-			case PaddingMode.ISO10126:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				total -= pad;
-				break;
-			case PaddingMode.PKCS7:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				for (int i = pad - 1; i > 0; i--) {
-					if (res [total - 1 - i] != pad)
-						ThrowBadPaddingException (padding, -1, i);
-				}
-				total -= pad;
-				break;
-			case PaddingMode.None:	// nothing to do - it's a multiple of block size
-			case PaddingMode.Zeros:	// nothing to do - user must unpad himself
-				break;
-			}
-
-			// return output without padding
-			if (total > 0) {
-				byte[] data = new byte [total];
-				Buffer.BlockCopy (res, 0, data, 0, total);
-				// zeroize decrypted data (copy with padding)
-				Array.Clear (res, 0, res.Length);
-				return data;
-			}
-			else
-				return new byte [0];
-		}
-
-		public virtual byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			CheckInput (inputBuffer, inputOffset, inputCount);
-
-			if (encrypt)
-				return FinalEncrypt (inputBuffer, inputOffset, inputCount);
-			else
-				return FinalDecrypt (inputBuffer, inputOffset, inputCount);
-		}
 	}
 }

Modified: class/Crimson.CryptoDev/Makefile
===================================================================
@@ -12,7 +12,8 @@ SOURCES = \
 	Crimson.Security.Cryptography/RijndaelKernel.cs	\
 	CryptoTools.cs 					\
 	AssemblyInfo.cs					\
-	../../common/Locale.cs
+	../../common/Locale.cs          \
+	../../common/CryptoTransformBase.cs
 
 all: Crimson.CryptoDev.dll
 
@@ -50,7 +51,7 @@ AssemblyInfo.cs:
 	) > $@
 
 Crimson.CryptoDev.dll: $(SOURCES) $(GENERATED_SOURCES)
-	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
+	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -debug -out:$@ -keyfile:../crimson.snk
 
 torture.exe: Crimson.CryptoDev.dll tools/torture.cs
 	dmcs -debug tools/torture.cs -r:Crimson.CryptoDev.dll -out:torture.exe

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -27,7 +27,7 @@ namespace Crimson.OpenSsl
 {
     using System;
 
-    public sealed class HashHelper : IDisposable
+    internal sealed class HashHelper : IDisposable
     {
         private IntPtr context;
         private readonly int hashSize;


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -47,6 +47,19 @@ public static int ExpectSuccess(int ret)
             return ret;
         }
 
+		//
+		// Version
+		//
+
+		public const int SSLEAY_VERSION = 0;
+		public const int SSLEAY_CFLAGS = 2;
+		public const int SSLEAY_BUILT_ON = 3;
+		public const int SSLEAY_PLATFORM = 4;
+		public const int SSLEAY_DIR = 5;
+
+		[DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
+		public extern static string SSLeay_version(int type);
+
         //
         // Digests
         //


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -30,7 +30,7 @@ namespace Crimson.OpenSsl
     using System.Security.Cryptography;
     using Crimson.Common;
 
-    public unsafe class OpenSslCryptoTransform : CryptoTransformBase
+    internal unsafe class OpenSslCryptoTransform : CryptoTransformBase
     {
         private IntPtr context;
 


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -0,0 +1,54 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+namespace Crimson.OpenSsl
+{
+	using System;
+	using System.Runtime.InteropServices;
+	using System.Security.Cryptography;
+
+	public class OpenSslUtil
+	{
+		public static bool IsAvailable()
+		{
+			try
+			{
+				Native.SSLeay_version(Native.SSLEAY_VERSION);
+			}
+			catch (DllNotFoundException)
+			{
+				return false;
+			}
+			
+			return true;
+		}
+
+		public static string GetVersionInfo()
+		{
+			return Native.SSLeay_version (Native.SSLEAY_VERSION);
+		}
+	}
+}

Modified: class/Crimson.OpenSsl/Makefile
===================================================================
@@ -6,7 +6,8 @@ CSC_FLAGS= -optimize
 SOURCES = \
 	Crimson.OpenSsl/Native.cs			\
 	Crimson.OpenSsl/HashHelper.cs		\
-	Crimson.OpenSsl/OpenSslCryptoTransform.cs			\
+	Crimson.OpenSsl/OpenSslCryptoTransform.cs \
+	Crimson.OpenSsl/OpenSslUtil.cs \
 	AssemblyInfo.cs					\
 	../../common/Locale.cs \
 	../../common/CryptoTransformBase.cs
@@ -46,7 +47,7 @@ AssemblyInfo.cs:
 	) > $@
 
 Crimson.OpenSsl.dll: $(SOURCES) $(GENERATED_SOURCES)
-	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
+	$(CSC) $(CSC_FLAGS) $^ -t:library -debug -unsafe -out:$@ -keyfile:../crimson.snk
 
 torture.exe: Crimson.OpenSsl.dll tools/torture.cs
 	dmcs -debug tools/torture.cs -r:Crimson.OpenSsl.dll -out:torture.exe
@@ -68,14 +69,15 @@ BASE_TESTS = \
 	../../tests/SHA256Test.cs		\
 	../../tests/SymmetricAlgorithmTest.cs
 
-GENERATED_TESTS = \
+TESTS = \
 	Tests/AesOpenSslTests.cs		\
 	Tests/RijndaelOpenSslTests.cs	\
 	Tests/SHA1OpenSslTests.cs		\
 	Tests/SHA256OpenSslTests.cs	\
+	Tests/OpenSslTests.cs
 
-Crimson.OpenSsl.Tests.dll: $(BASE_TESTS) $(GENERATED_TESTS) Crimson.OpenSsl.dll
-	mcs -debug $(BASE_TESTS) $(GENERATED_TESTS) -t:library -out:$@ -r:Crimson.OpenSsl.dll -pkg:mono-nunit
+Crimson.OpenSsl.Tests.dll: $(BASE_TESTS) $(TESTS) Crimson.OpenSsl.dll
+	mcs -debug $(BASE_TESTS) $(TESTS) -t:library -out:$@ -r:Crimson.OpenSsl.dll -pkg:mono-nunit
 
 test: Crimson.OpenSsl.Tests.dll
 

Added: class/Crimson.OpenSsl/Tests/OpenSslTests.cs
===================================================================
@@ -0,0 +1,44 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+using NUnit.Framework;
+using Crimson.OpenSsl;
+
+namespace Crimson.Test.OpenSsl {
+
+	static class CryptoDevTest {
+		
+		static public void EnsureAvailability ()
+		{
+			if (!OpenSslUtil.IsAvailable ()) {
+				Assert.Ignore ("libcrypto not found.");
+			}
+		}
+	}
+}

Modified: class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
===================================================================
@@ -147,7 +147,7 @@ public void RijndaelNone_SmallerThanOneBlockSize()
         {
             Rijndael aes = this.GetAES();
             byte[] data = this.GetData(8);
-            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            this.Encrypt(aes, PaddingMode.None, data);
         }
 
         [Test]
@@ -167,7 +167,7 @@ public void RijndaelNone_MoreThanOneBlockSize()
         {
             Rijndael aes = this.GetAES();
             byte[] data = this.GetData(20);
-            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            this.Encrypt(aes, PaddingMode.None, data);
         }
 
         [Test]


Modified: common/CryptoTransformBase.cs
===================================================================
@@ -43,11 +43,12 @@ namespace Crimson.Common
 {
     public abstract class CryptoTransformBase : ICryptoTransform
     {
-        bool encrypt;
-        int BlockSizeByte;
         byte[] workBuff;
         bool lastBlock;
         PaddingMode padding;
+
+        protected bool encrypt;
+        protected int BlockSizeByte;
         protected byte[] iv;
 
         public CryptoTransformBase(SymmetricAlgorithm algo, bool encryption, byte[] rgbKey, byte[] rgbIV)


   Commit: 077c9c91a61dff451e61f8bc63ae3f409a474693
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 05:51:03 GMT
      URL: https://github.com/mono/crimson/commit/077c9c91a61dff451e61f8bc63ae3f409a474693

Fix generator, now passing torture tests. Fix marshaling of version string. Fallback to RijndaelManaged if openssl is not found. Remove MD5 as its not tested.

Changed paths:
  M class/Crimson.CryptoDev/Makefile
  M class/Crimson.OpenSsl/.gitignore
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
  M class/Crimson.OpenSsl/Makefile
  M class/Crimson.OpenSsl/tools/generator.cs
  M class/Crimson.OpenSsl/tools/torture.cs

Modified: class/Crimson.CryptoDev/Makefile
===================================================================
@@ -51,7 +51,7 @@ AssemblyInfo.cs:
 	) > $@
 
 Crimson.CryptoDev.dll: $(SOURCES) $(GENERATED_SOURCES)
-	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -debug -out:$@ -keyfile:../crimson.snk
+	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
 
 torture.exe: Crimson.CryptoDev.dll tools/torture.cs
 	dmcs -debug tools/torture.cs -r:Crimson.CryptoDev.dll -out:torture.exe

Modified: class/Crimson.OpenSsl/.gitignore
===================================================================
@@ -2,4 +2,5 @@
 Crimson.Security.Cryptography/*.g.cs
 TestResult.xml
 AssemblyInfo.cs
-tools/generator.exe
\ No newline at end of file
+tools/generator.exe
+torture.exe*

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -58,7 +58,8 @@ public static int ExpectSuccess(int ret)
 		public const int SSLEAY_DIR = 5;
 
 		[DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-		public extern static string SSLeay_version(int type);
+		[return : MarshalAs(UnmanagedType.LPStr)]
+		public extern static IntPtr SSLeay_version(int type);
 
         //
         // Digests


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -37,6 +37,8 @@ internal unsafe class OpenSslCryptoTransform : CryptoTransformBase
         public OpenSslCryptoTransform(SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
             : base(algo, encrypt, rgbKey, rgbIV)
         {
+			OpenSslUtil.EnsureAvailability ();
+
             this.context = Native.EVP_CIPHER_CTX_new();
 
             var cptr = this.GetCipher(algo.Mode, rgbKey.Length);


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -36,7 +36,7 @@ public static bool IsAvailable()
 		{
 			try
 			{
-				Native.SSLeay_version(Native.SSLEAY_VERSION);
+				GetVersionInfo();
 			}
 			catch (DllNotFoundException)
 			{
@@ -46,9 +46,16 @@ public static bool IsAvailable()
 			return true;
 		}
 
+		public static void EnsureAvailability()
+		{
+			if (!IsAvailable ()) {
+				throw new CryptographicException ("libcrypto was not found");
+			}
+		}
+
 		public static string GetVersionInfo()
 		{
-			return Native.SSLeay_version (Native.SSLEAY_VERSION);
+			return Marshal.PtrToStringUni(Native.SSLeay_version (Native.SSLEAY_VERSION));
 		}
 	}
 }

Modified: class/Crimson.OpenSsl/Makefile
===================================================================
@@ -17,7 +17,6 @@ all: Crimson.OpenSsl.dll
 GENERATED_SOURCES = \
 	Crimson.Security.Cryptography/AesOpenSsl.g.cs	\
 	Crimson.Security.Cryptography/RijndaelOpenSsl.g.cs	\
-	Crimson.Security.Cryptography/MD5OpenSsl.g.cs	\
 	Crimson.Security.Cryptography/SHA1OpenSsl.g.cs	\
 	Crimson.Security.Cryptography/SHA256OpenSsl.g.cs
 
@@ -47,7 +46,7 @@ AssemblyInfo.cs:
 	) > $@
 
 Crimson.OpenSsl.dll: $(SOURCES) $(GENERATED_SOURCES)
-	$(CSC) $(CSC_FLAGS) $^ -t:library -debug -unsafe -out:$@ -keyfile:../crimson.snk
+	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
 
 torture.exe: Crimson.OpenSsl.dll tools/torture.cs
 	dmcs -debug tools/torture.cs -r:Crimson.OpenSsl.dll -out:torture.exe
@@ -56,7 +55,7 @@ torture: torture.exe
 	mono --debug torture.exe -v
 
 clean:
-	rm -f torture.exe
+	rm -f torture.exe*
 	rm -f tools/generator.exe
 	rm -f $(GENERATED_SOURCES) AssemblyInfo.cs
 	rm -f *.dll*

Modified: class/Crimson.OpenSsl/tools/generator.cs
===================================================================
@@ -79,7 +79,7 @@ protected override void Dispose(bool disposing)
 
         public override void Initialize()
         {
-            helper = new HashHelper(Native.EVP_sha1(), this.HashSize);
+            helper = new HashHelper(Native.EVP_{1}(), this.HashSize);
         }
 
         protected override void HashCore(byte[] data, int start, int length)
@@ -106,7 +106,7 @@ protected override byte[] HashFinal()
 		string filename = Path.Combine (OutputDirectory,
 			String.Format ("{0}OpenSsl.g.cs", name));
 		string content = template.Replace ("{0}", name).
-			Replace ("{1}", name.ToUpperInvariant ());
+			Replace ("{1}", name.ToLowerInvariant ());
 		File.WriteAllText (filename, content);
 	}
 
@@ -204,8 +204,8 @@ static void Main (string[] args)
 
 		GenerateHash ("SHA1");		// CRYPTO_SHA1
 		GenerateHash ("SHA256");	// CRYPTO_SHA256
-		GenerateHash ("MD5");		// CRYPTO_MD5
 #if UNTESTED
+		GenerateHash ("MD5");		// CRYPTO_MD5
 		GenerateHash ("RIPEMD160");	// CRYPTO_RIPEMD160
 		GenerateHash ("SHA384");	// CRYPTO_SHA2_384
 		GenerateHash ("SHA512");	// CRYPTO_SHA2_512

Modified: class/Crimson.OpenSsl/tools/torture.cs
===================================================================
@@ -73,7 +73,7 @@ static void SHA1 (string name, int max, byte[] input, byte[] output)
 		int i = 0;
 		try {
 			for (; i < max; i++) {
-				using (SHA1 digest = new SHA1Kernel ()) {
+				using (SHA1 digest = new SHA1OpenSsl ()) {
 					if (!Compare (output, digest.ComputeHash (input)))
 						throw new Exception (name + " " + i.ToString ());
 				}
@@ -117,7 +117,7 @@ static void SHA256 (string name, int max, byte[] input, byte[] output)
 		int i = 0;
 		try {
 			for (; i < max; i++) {
-				using (SHA256 digest = new SHA256Kernel ()) {
+				using (SHA256 digest = new SHA256OpenSsl ()) {
 					if (!Compare (output, digest.ComputeHash (input)))
 						throw new Exception (name + " " + i.ToString ());
 				}
@@ -177,7 +177,7 @@ static void AES (string name, int max, byte[] key, byte[] input, byte[] expected
 		int i = 0;
 		try {
 			for (; i < max; i++) {
-				using (Aes cipher = new AesKernel ()) {
+				using (Aes cipher = new AesOpenSsl ()) {
 					cipher.Mode = CipherMode.ECB;
 					cipher.KeySize = key.Length * 8;
 					cipher.Padding = PaddingMode.Zeros;

   Commit: 937ed083b75e07ec62b29dc7174f29414fecacc3
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 05:51:03 GMT
      URL: https://github.com/mono/crimson/commit/937ed083b75e07ec62b29dc7174f29414fecacc3

Update README

Changed paths:
  M class/Crimson.OpenSsl/README
  M class/README

Modified: class/Crimson.OpenSsl/README
===================================================================
@@ -1,26 +1,12 @@
-This assembly goal is to provide a managed wrapper on to /dev/crypto
-as provided by either `cryptodev` [1] or OCF [2].
+This assembly goal is to provide a managed wrapper on top of libcrypto[1].
 
 References:
-[1] http://home.gna.org/cryptodev-linux/
-[2] http://ocf-linux.sourceforge.net
+[1] http://www.openssl.org/
 
-
-/dev/crypto Availability
+libcrypto Availability
 ----------------------
 
-Most Linux distributions do not ship /dev/crypto so you'll have to:
-
-1. build it yourself (from one of the above links);
-
-2. install the driver, e.g.
-
-	sudo insmod /path/to/cryptodev.ko
-
-3. give read/write permissions to the device, e.g. for everyone do:
-
-	sudo chmod 666 /dev/crypto
-
+Most Linux distributions ship with openssl. 
 
 Building
 --------
@@ -31,37 +17,3 @@ the generator (creating the source files) and then build the assembly
 You can verify that everything works, if nunit is available, by doing
 'make run-test'
 
-
-cryptodev/mv_cesa specific notes
---------------------------------
-
-Hardware have limited internal buffers to work on. The drivers should 
-make this limit invisible to callers. This is not (always) the case.
-
-Testing as show that the hardware limit is hit if we use more than:
-
-1920 bytes for SHA1
-1936 bytes for AES
-
-As such the code can be adapted to work with those limits. By default
-the implementations will use a limit of Int32.MaxValue but, if defined
-differently, will iterate large buffers based on a smaller limit (and
-workaround the driver limitation).
-
-Changing this limit is done using environment variables, e.g.
-
-CRIMSON_AES_BUFFER_BLOCK_SIZE=1936 make run-test
-
-will run the unit tests using a block size limited to 1936 bytes.
-While
-
-CRIMSON_SHA1_BUFFER_BLOCK_SIZE=1920 make run-test
-
-will run the unit tests with a block size limited to 1920 bytes.
-
-This way each algorithm limitation can be configured separately. Even
-if the limit is likely identical between many of them.
-
-Since having those limits potentially requires a lot more native/kernels
-calls, reducing overall performance, it should only be used if required.
-

Modified: class/README
===================================================================
@@ -6,6 +6,11 @@ The following assemblies are available in Crimson:
 	algorithm implementations, either native or hardware accelerated.
 	Ref: http://home.gna.org/cryptodev-linux/
 
+* Crimson.OpenSsl.dll
+
+	This assembly provides a wrapper around libcrypto.
+	Ref: http://www.openssl.org/
+	
 * Crimson.MHash.dll
 
 	This assembly provides wrapper around the native hash implementations 

   Commit: bdec80a1c53993f5826184f866f66486ab0317be
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 05:51:03 GMT
      URL: https://github.com/mono/crimson/commit/bdec80a1c53993f5826184f866f66486ab0317be

Check if save_iv is not null in CryptoDevTransform before copying. Using PtrToStringAuto in OpenSslUtil.

Changed paths:
  M class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs

Modified: class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
===================================================================
@@ -104,7 +104,7 @@ protected override void Transform (byte[] input, int inputOffset, byte[] output,
 				fixed (byte *v = iv)
 				fixed (byte *i = &input [inputOffset])
 				fixed (byte *o = &output [outputOffset]) {
-					if (iv != null) {
+					if (save_iv != null) {
 						context.iv = (IntPtr) v;
 
 						if (!encrypt) {
@@ -127,7 +127,7 @@ protected override void Transform (byte[] input, int inputOffset, byte[] output,
 					}
 				}
 
-				if (iv != null) {
+				if (save_iv != null) {
 					if (encrypt)
 						Buffer.BlockCopy (output, outputOffset + size - BlockSizeByte, iv, 0, BlockSizeByte);
 					else

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -55,7 +55,7 @@ public static void EnsureAvailability()
 
 		public static string GetVersionInfo()
 		{
-			return Marshal.PtrToStringUni(Native.SSLeay_version (Native.SSLEAY_VERSION));
+			return Marshal.PtrToStringAuto(Native.SSLeay_version (Native.SSLEAY_VERSION));
 		}
 	}
 }

   Commit: f29759158581ec35990a97886561efc30559e977
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 07:00:12 GMT
      URL: https://github.com/mono/crimson/commit/f29759158581ec35990a97886561efc30559e977

Make more base test class abstract to prevent NUnit from running them.

Changed paths:
  M tests/HashAlgorithmTest.cs
  M tests/SHA1Test.cs
  M tests/SHA256Test.cs
  M tests/SymmetricAlgorithmTest.cs

Modified: tests/HashAlgorithmTest.cs
===================================================================
@@ -36,7 +36,7 @@
 
 namespace Crimson.Test.Base {
 
-	public class HashAlgorithmTest {
+	public abstract class HashAlgorithmTest {
 	
 		protected HashAlgorithm hash;
 	

Modified: tests/SHA1Test.cs
===================================================================
@@ -21,7 +21,7 @@ namespace Crimson.Test.Base {
 // a.	FIPS PUB 180-1: Secure Hash Standard
 //	http://csrc.nist.gov/publications/fips/fips180-1/fip180-1.txt
 
-	public class SHA1Test : HashAlgorithmTest {
+	public abstract class SHA1Test : HashAlgorithmTest {
 	
 		// test vectors from NIST FIPS 186-2
 	

Modified: tests/SHA256Test.cs
===================================================================
@@ -21,7 +21,7 @@ namespace Crimson.Test.Base {
 // a.	FIPS PUB 180-2: Secure Hash Standard
 //	http://csrc.nist.gov/publications/fips/fips180-2/fip180-2.txt
 
-	public class SHA256Test : HashAlgorithmTest {
+	public abstract class SHA256Test : HashAlgorithmTest {
 	
 		// test vectors from NIST FIPS 186-2
 	

Modified: tests/SymmetricAlgorithmTest.cs
===================================================================
@@ -5,7 +5,7 @@
 
 namespace Crimson.Test.Base {
 
-	public class SymmetricAlgorithmTest {
+	public abstract class SymmetricAlgorithmTest {
 	
 		protected SymmetricAlgorithm algo;
 

   Commit: 7ce60337b00737e9afcd2dd20d57c0a78df35249
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 19:30:22 GMT
      URL: https://github.com/mono/crimson/commit/7ce60337b00737e9afcd2dd20d57c0a78df35249

Ensure the ciphers are available before running tests.

Changed paths:
  M class/Crimson.CryptoDev/Tests/AesKernelTest.cs
  M class/Crimson.CryptoDev/Tests/CryptoDevTest.cs
  M class/Crimson.CryptoDev/Tests/RijndaelKernelTest.cs
  M class/Crimson.CryptoDev/Tests/SHA1KernelTest.cs
  M class/Crimson.CryptoDev/Tests/SHA256KernelTest.cs

Modified: class/Crimson.CryptoDev/Tests/AesKernelTest.cs
===================================================================
@@ -40,7 +40,7 @@ public class AesKernelTest : AesTest {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.AES_CBC);
 			algo = Create (); // shared
 		}
 

Modified: class/Crimson.CryptoDev/Tests/CryptoDevTest.cs
===================================================================
@@ -26,6 +26,7 @@
 
 using System;
 using System.IO;
+using Crimson.CryptoDev;
 
 using NUnit.Framework;
 
@@ -51,5 +52,14 @@ static public void EnsureAvailability ()
 				// fix by doing "sudo chmod 600 /dev/crypto"
 			}
 		}
+
+		static public void EnsureAvailability (Cipher cipher)
+		{
+			EnsureAvailability();
+
+			if (!Crimson.CryptoDev.Helper.IsAvailable (cipher)) {
+				Assert.Ignore (string.Format("{0} not available on this platform", cipher));
+			}
+		}
 	}
 }

Modified: class/Crimson.CryptoDev/Tests/RijndaelKernelTest.cs
===================================================================
@@ -41,7 +41,7 @@ public class RijndaelKernelTest : RijndaelTest {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.AES_CBC);
 			algo = Create (); // shared
 		}
 

Modified: class/Crimson.CryptoDev/Tests/SHA1KernelTest.cs
===================================================================
@@ -39,7 +39,7 @@ public class SHA1KernelTest : SHA1Test {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.SHA1);
 			hash = new SHA1Kernel ();
 		}
 	}

Modified: class/Crimson.CryptoDev/Tests/SHA256KernelTest.cs
===================================================================
@@ -39,7 +39,7 @@ public class SHA256KernelTest : SHA256Test {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.SHA256);
 			hash = new SHA256Kernel ();
 		}
 	}

   Commit: 66039fe4e5fac5b69709a219950b97ba9dac8d1b
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-25 20:44:37 GMT
      URL: https://github.com/mono/crimson/commit/66039fe4e5fac5b69709a219950b97ba9dac8d1b

Ensure the output directory is created prior to generating code.

Changed paths:
  M class/Crimson.OpenSsl/tools/generator.cs

Modified: class/Crimson.OpenSsl/tools/generator.cs
===================================================================
@@ -202,6 +202,8 @@ static void Main (string[] args)
 	{
 		OutputDirectory = args.Length == 0 ? "." : args [0];
 
+		System.IO.Directory.CreateDirectory (OutputDirectory);
+
 		GenerateHash ("SHA1");		// CRYPTO_SHA1
 		GenerateHash ("SHA256");	// CRYPTO_SHA256
 #if UNTESTED

   Commit: 13b5d51805a5d6626a80be400697a0943e1722f7
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-09-26 06:59:42 GMT
      URL: https://github.com/mono/crimson/commit/13b5d51805a5d6626a80be400697a0943e1722f7

Remove unnecessary finalizer.

Changed paths:
  M class/Crimson.CryptoDev/tools/generator.cs
  M class/Crimson.OpenSsl/tools/generator.cs

Modified: class/Crimson.CryptoDev/tools/generator.cs
===================================================================
@@ -76,21 +76,11 @@ public class {0}Kernel : {0} {
 
 		public static int BufferBlockSize { get; set; }
 
-		public {0}Kernel ()
-		{
-		}
-
-		~{0}Kernel ()
-		{
-			Dispose (false);
-		}
-
 		protected override void Dispose (bool disposing)
 		{
-			if (disposing && (helper != null)) {
+			if (disposing && helper != null) {
 				helper.Dispose ();
-				helper = null;
-				GC.SuppressFinalize (this);
+                helper = null;
 			}
 			base.Dispose (disposing);
 		}

Modified: class/Crimson.OpenSsl/tools/generator.cs
===================================================================
@@ -110,13 +110,35 @@ protected override byte[] HashFinal()
 		File.WriteAllText (filename, content);
 	}
 
-	static void GenerateSymmetricAlgorithm (string name, string fallback, string ecb, string cbc)
+	static void GenerateSymmetricAlgorithm (string name, string fallback)
 	{
 		string template = @"// NOTE: Generated code DO NOT EDIT
 //
-// Author: Bassam Tabbara  <[email protected]>
-// See LICENSE for copyrights and restrictions
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// 'Software'), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
+
 using System.Security.Cryptography;
 using Crimson.OpenSsl;
 
@@ -176,23 +198,18 @@ public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
             }
         }
 
-        private Rijndael Fallback()
-        {
-            Rijndael r = new RijndaelManaged();
-            r.Mode = Mode;
-            r.Padding = Padding;
-            r.BlockSize = BlockSize;
-            return r;
-        }
+		private {1} Fallback ()
+		{
+			{1} r = new {1} ();
+			r.Mode = Mode;
+			r.Padding = Padding;
+			r.BlockSize = BlockSize;
+			return r;
+		}
 	}
 }";
-		string filename = Path.Combine (OutputDirectory,
-			String.Format ("{0}OpenSsl.g.cs", name));
-		string content = template.Replace ("{0}", name).
-			Replace ("{1}", fallback).
-			Replace ("{2}", ecb).
-			Replace ("{3}", cbc).
-			Replace ("{4}", name.ToUpperInvariant ());
+		string filename = Path.Combine (OutputDirectory, String.Format ("{0}OpenSsl.g.cs", name));
+		string content = template.Replace ("{0}", name).Replace ("{1}", fallback);
 		File.WriteAllText (filename, content);
 	}
 
@@ -212,8 +229,8 @@ static void Main (string[] args)
 		GenerateHash ("SHA384");	// CRYPTO_SHA2_384
 		GenerateHash ("SHA512");	// CRYPTO_SHA2_512
 #endif
-		GenerateSymmetricAlgorithm ("Rijndael", "RijndaelManaged", "AES_ECB", "AES_CBC");
-		GenerateSymmetricAlgorithm ("Aes", "RijndaelManaged", "AES_ECB", "AES_CBC");
+		GenerateSymmetricAlgorithm ("Rijndael", "RijndaelManaged");
+		GenerateSymmetricAlgorithm ("Aes", "RijndaelManaged");
 #if UNTESTED
 		GenerateSymmetricAlgorithm ("Des", "DESCryptoServiceProvider", null, "DES_CBC");
 		GenerateSymmetricAlgorithm ("TripleDes", "TripleDESCryptoServiceProvider", null, "3DES_CBC");

   Commit: 1c715e16901a43eb6be55f3b50d89e9bcfec582a
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-10-01 18:16:23 GMT
      URL: https://github.com/mono/crimson/commit/1c715e16901a43eb6be55f3b50d89e9bcfec582a

Increase the size of the buffer passed to EVP_DigestFinal_ex, and make size and output parameter.

Changed paths:
  M class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -26,6 +26,7 @@
 namespace Crimson.OpenSsl
 {
     using System;
+	using System.Security.Cryptography;
 
     internal sealed class HashHelper : IDisposable
     {
@@ -71,15 +72,25 @@ public unsafe void Update(byte[] data, int start, int length)
 
         public unsafe byte[] Final()
         {
-            var digest = new byte[this.hashSize];
-            var len = (uint)digest.Length;
+			var digest = new byte[Native.EVP_MAX_MD_SIZE];
+            uint len;
 
             fixed (byte* p = &digest[0])
             {
-                Native.ExpectSuccess(Native.EVP_DigestFinal_ex(this.context, (IntPtr)p, ref len));
+                Native.ExpectSuccess(Native.EVP_DigestFinal_ex(this.context, (IntPtr)p, out len));
             }
 
-            return digest;
+			if (len != hashSize) {
+				throw new CryptographicException (string.Format("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
+			}
+
+			if (len == digest.Length) {
+				return digest;
+			}
+
+			var result = new byte[this.hashSize];
+			Buffer.BlockCopy (digest, 0, result, 0, this.hashSize);
+            return result;
         }
     }
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -65,6 +65,8 @@ public static int ExpectSuccess(int ret)
         // Digests
         //
 
+		public const int EVP_MAX_MD_SIZE = 64;
+
         [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
         public extern static IntPtr EVP_md5();
 
@@ -87,7 +89,7 @@ public static int ExpectSuccess(int ret)
         public extern static int EVP_DigestUpdate(IntPtr ctx, IntPtr d, uint cnt);
 
         [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_DigestFinal_ex(IntPtr ctx, IntPtr md, ref uint s);
+        public extern static int EVP_DigestFinal_ex(IntPtr ctx, IntPtr md, out uint s);
 
         //
         // Ciphers
@@ -115,7 +117,7 @@ public static int ExpectSuccess(int ret)
         public extern static IntPtr EVP_CIPHER_CTX_new();
 
         [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_CIPHER_CTX_free(IntPtr a);
+        public extern static void EVP_CIPHER_CTX_free(IntPtr a);
 
         [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
         public extern static int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);


   Commit: e3055f7cc410ab0da5106c8a21f1f0bf9828b315
   Author: Chris Araman <[email protected]> (chris-araman)
     Date: 2013-10-01 18:48:13 GMT
      URL: https://github.com/mono/crimson/commit/e3055f7cc410ab0da5106c8a21f1f0bf9828b315

P/Invoke marshaling improvements

Changed paths:
  M class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -23,74 +23,61 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-namespace Crimson.OpenSsl
-{
+namespace Crimson.OpenSsl {
     using System;
 	using System.Security.Cryptography;
 
-    internal sealed class HashHelper : IDisposable
-    {
-        private IntPtr context;
+    internal sealed class HashHelper : IDisposable {
+        private readonly Native.SafeDigestContextHandle context;
         private readonly int hashSize;
 
-        public HashHelper(IntPtr mdptr, int hashSize)
-        {
+        public HashHelper (Native.SafeDigestHandle digest, int hashSize) {
             this.hashSize = hashSize >> 3;
-            this.context = Native.EVP_MD_CTX_create();
+            if (this.hashSize > Native.MaximumDigestSize) {
+                throw new ArgumentOutOfRangeException("hashSize");
+            }
 
-            Native.ExpectSuccess(Native.EVP_DigestInit_ex(this.context, mdptr, IntPtr.Zero));
+            this.context = Native.EVP_MD_CTX_create ();
+            Native.ExpectSuccess (Native.EVP_DigestInit_ex (this.context, digest, IntPtr.Zero));
         }
 
-        ~HashHelper()
-        {
-            Dispose();
+        public void Dispose () {
+            this.context.Dispose ();
         }
 
-        public void Dispose()
-        {
-            if (this.context != IntPtr.Zero)
-            {
-                Native.EVP_MD_CTX_destroy(this.context);
-                this.context = IntPtr.Zero;
+        public unsafe void Update (byte[] data, int start, int length) {
+            if (length == 0) {
+                return;
             }
 
-            GC.SuppressFinalize(this);
-        }
-
-        public unsafe void Update(byte[] data, int start, int length)
-        {
-            if (length == 0)
-            {
-                return;
+            if (length < uint.MinValue) {
+                throw new ArgumentOutOfRangeException("length");
             }
 
-            fixed (byte* p = &data[start])
-            {
-                Native.ExpectSuccess(Native.EVP_DigestUpdate(this.context, (IntPtr)p, (uint)length));
+            fixed (byte* p = &data[start]) {
+                Native.ExpectSuccess (Native.EVP_DigestUpdate(this.context, (IntPtr)p, (uint)length));
             }
         }
 
-        public unsafe byte[] Final()
-        {
-			var digest = new byte[Native.EVP_MAX_MD_SIZE];
+        public unsafe byte[] Final () {
+            var digest = new byte[Native.MaximumDigestSize];
             uint len;
 
-            fixed (byte* p = &digest[0])
-            {
-                Native.ExpectSuccess(Native.EVP_DigestFinal_ex(this.context, (IntPtr)p, out len));
+            fixed (byte* p = &digest[0]) {
+                Native.ExpectSuccess (Native.EVP_DigestFinal_ex (this.context, (IntPtr)p, out len));
             }
 
-			if (len != hashSize) {
-				throw new CryptographicException (string.Format("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
-			}
+            if (len != this.hashSize) {
+                throw new CryptographicException (string.Format ("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
+            }
 
-			if (len == digest.Length) {
-				return digest;
-			}
+            if (len == digest.Length) {
+                return digest;
+            }
 
-			var result = new byte[this.hashSize];
-			Buffer.BlockCopy (digest, 0, result, 0, this.hashSize);
-            return result;
+            var trimmed = new byte[this.hashSize];
+            Buffer.BlockCopy (digest, 0, trimmed, 0, this.hashSize);
+            return trimmed;
         }
     }
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -24,8 +24,8 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-namespace Crimson.OpenSsl
-{
+namespace Crimson.OpenSsl {
+    using Microsoft.Win32.SafeHandles;
     using System;
     using System.Runtime.InteropServices;
     using System.Security.Cryptography;
@@ -33,102 +33,161 @@ namespace Crimson.OpenSsl
     /// <summary>
     /// Documentation can be found here: http://www.openssl.org/docs/crypto/EVP_DigestInit.html
     /// </summary>
-    internal class Native
-    {
-        const string Dllname = "libcrypto";
-
-        public static int ExpectSuccess(int ret)
-        {
-            if (ret <= 0)
-            {
-                throw new CryptographicException();
+    internal static class Native {
+        const string DllName = "libcrypto";
+
+        public static int ExpectSuccess (int ret) {
+            if (ret <= 0) {
+                throw new CryptographicException ();
             }
 
             return ret;
         }
 
-		//
-		// Version
-		//
+        //
+        // Version
+        //
 
-		public const int SSLEAY_VERSION = 0;
-		public const int SSLEAY_CFLAGS = 2;
-		public const int SSLEAY_BUILT_ON = 3;
-		public const int SSLEAY_PLATFORM = 4;
-		public const int SSLEAY_DIR = 5;
+        [Serializable]
+        public enum SSLeayVersionType {
+            SSLEAY_VERSION = 0,
+            SSLEAY_CFLAGS = 2,
+            SSLEAY_BUILT_ON = 3,
+            SSLEAY_PLATFORM = 4,
+            SSLEAY_DIR = 5,
+        }
 
-		[DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-		[return : MarshalAs(UnmanagedType.LPStr)]
-		public extern static IntPtr SSLeay_version(int type);
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false, CharSet = CharSet.Ansi)]
+        [return: MarshalAs (UnmanagedType.LPStr)]
+        public extern static string SSLeay_version (SSLeayVersionType type);
 
         //
         // Digests
         //
 
-		public const int EVP_MAX_MD_SIZE = 64;
+        public const int MaximumDigestSize = 64;
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeDigestHandle EVP_md5 ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeDigestHandle EVP_sha1 ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeDigestHandle EVP_sha256 ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeDigestContextHandle EVP_MD_CTX_create ();
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_md5();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        private extern static void EVP_MD_CTX_destroy (IntPtr ctx);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_sha1();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_DigestInit_ex (SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_sha256();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_DigestUpdate (SafeDigestContextHandle ctx, IntPtr d, uint cnt);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_MD_CTX_create();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_DigestFinal_ex (SafeDigestContextHandle ctx, IntPtr md, out uint s);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static void EVP_MD_CTX_destroy(IntPtr ctx);
+        internal sealed class SafeDigestHandle : SafeHandleZeroOrMinusOneIsInvalid {
+            private SafeDigestHandle () :
+                base (false) {
+            }
+
+            protected override bool ReleaseHandle () {
+                return false;
+            }
+        }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_DigestInit_ex(IntPtr ctx, IntPtr type, IntPtr impl);
+        internal sealed class SafeDigestContextHandle : SafeHandleZeroOrMinusOneIsInvalid {
+            internal SafeDigestContextHandle (IntPtr handle, bool ownsHandle) :
+                base(ownsHandle) {
+                this.SetHandle(handle);
+            }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_DigestUpdate(IntPtr ctx, IntPtr d, uint cnt);
+            private SafeDigestContextHandle () :
+                base (true) {
+            }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_DigestFinal_ex(IntPtr ctx, IntPtr md, out uint s);
+            protected override bool ReleaseHandle () {
+                EVP_MD_CTX_destroy (this.handle);
+                return true;
+            }
+        }
 
         //
         // Ciphers
         //
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_128_cbc();
+        [Serializable]
+        public enum CipherOperation {
+            Unchanged = -1,
+            Decrypt = 0,
+            Encrypt = 1,
+        }
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_128_cbc ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_192_cbc ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_256_cbc ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_128_ecb ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_192_ecb ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherHandle EVP_aes_256_ecb ();
+
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static SafeCipherContextHandle EVP_CIPHER_CTX_new ();
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_192_cbc();
-        
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_256_cbc();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        private extern static void EVP_CIPHER_CTX_free (IntPtr a);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_128_ecb();
-        
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_192_ecb();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_CIPHER_CTX_set_key_length (SafeCipherContextHandle x, int keylen);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_aes_256_ecb();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_CIPHER_CTX_set_padding (SafeCipherContextHandle x, int padding);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static IntPtr EVP_CIPHER_CTX_new();
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_CipherInit_ex (SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static void EVP_CIPHER_CTX_free(IntPtr a);
+        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+        public extern static int EVP_CipherUpdate (SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_CIPHER_CTX_set_key_length(IntPtr x, int keylen);
+        internal sealed class SafeCipherHandle : SafeHandleZeroOrMinusOneIsInvalid {
+            private SafeCipherHandle () :
+                base (false) {
+            }
+
+            protected override bool ReleaseHandle () {
+                return false;
+            }
+        }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding);
+        internal sealed class SafeCipherContextHandle : SafeHandleZeroOrMinusOneIsInvalid {
+            internal SafeCipherContextHandle (IntPtr handle, bool ownsHandle) :
+                base (ownsHandle) {
+                this.SetHandle(handle);
+            }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_CipherInit_ex(IntPtr ctx, IntPtr type, IntPtr impl, IntPtr key, IntPtr iv, int enc);
+            private SafeCipherContextHandle () :
+                base (true) {
+            }
 
-        [DllImport(Dllname, CallingConvention = CallingConvention.Cdecl)]
-        public extern static int EVP_CipherUpdate(IntPtr ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
+            protected override bool ReleaseHandle () {
+                EVP_CIPHER_CTX_free (this.handle);
+                return true;
+            }
+        }
     }
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -24,88 +24,76 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-namespace Crimson.OpenSsl
-{
+namespace Crimson.OpenSsl {
     using System;
     using System.Security.Cryptography;
     using Crimson.Common;
 
-    internal unsafe class OpenSslCryptoTransform : CryptoTransformBase
-    {
-        private IntPtr context;
+    internal unsafe class OpenSslCryptoTransform : CryptoTransformBase {
+        private readonly Native.SafeCipherContextHandle context;
 
-        public OpenSslCryptoTransform(SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
-            : base(algo, encrypt, rgbKey, rgbIV)
-        {
-			OpenSslUtil.EnsureAvailability ();
+        public OpenSslCryptoTransform (SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
+            : base (algo, encrypt, rgbKey, rgbIV) {
 
-            this.context = Native.EVP_CIPHER_CTX_new();
+            OpenSslUtil.EnsureAvailability ();
 
-            var cptr = this.GetCipher(algo.Mode, rgbKey.Length);
+            this.context = Native.EVP_CIPHER_CTX_new ();
 
-            fixed (byte *pkey = &rgbKey[0])
-            fixed (byte* piv = &iv[0])
-            {
-                Native.ExpectSuccess(Native.EVP_CipherInit_ex(this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, encrypt? 1: 0));
+            var cptr = this.GetCipher (algo.Mode, rgbKey.Length);
+            var op = encrypt ? Native.CipherOperation.Encrypt : Native.CipherOperation.Decrypt;
+
+            fixed (byte* pkey = &rgbKey[0])
+            fixed (byte* piv = &iv[0]) {
+                Native.ExpectSuccess (Native.EVP_CipherInit_ex (this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, op));
             }
 
-            Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_key_length(this.context, rgbKey.Length));
-            Native.ExpectSuccess(Native.EVP_CIPHER_CTX_set_padding(this.context, 0));
+            Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_key_length (this.context, rgbKey.Length));
+            Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_padding (this.context, 0));
         }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (this.context != IntPtr.Zero)
-            {
-                Native.EVP_CIPHER_CTX_free(this.context);
-                this.context = IntPtr.Zero;
+        protected override void Dispose (bool disposing) {
+            if (disposing) {
+                this.context.Dispose();
             }
 
             base.Dispose(disposing);
         }
 
-        protected override void Transform(byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount)
-        {
+        protected override void Transform (byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount) {
             fixed (byte* input = &inputBuffer[inputOffset])
-            fixed (byte* output = &outputBuffer[outputOffset])
-            {
+            fixed (byte* output = &outputBuffer[outputOffset]) {
                 int outputCount;
-                Native.ExpectSuccess(Native.EVP_CipherUpdate(this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
+                Native.ExpectSuccess (Native.EVP_CipherUpdate (this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
             }
         }
 
-        private IntPtr GetCipher(CipherMode mode, int keyLength)
-        {
-            if (mode == CipherMode.CBC)
-            {
-                switch (keyLength)
-                {
+        private Native.SafeCipherHandle GetCipher (CipherMode mode, int keyLength) {
+            if (mode == CipherMode.CBC) {
+                switch (keyLength) {
                     case 16:
-                        return Native.EVP_aes_128_cbc();
+                        return Native.EVP_aes_128_cbc ();
 
                     case 24:
-                        return Native.EVP_aes_192_cbc();
+                        return Native.EVP_aes_192_cbc ();
 
                     case 32:
-                        return Native.EVP_aes_256_cbc();
+                        return Native.EVP_aes_256_cbc ();
                 }
             }
-            else if (mode == CipherMode.ECB)
-            {
-                switch (keyLength)
-                {
+            else if (mode == CipherMode.ECB) {
+                switch (keyLength) {
                     case 16:
-                        return Native.EVP_aes_128_ecb();
+                        return Native.EVP_aes_128_ecb ();
 
                     case 24:
-                        return Native.EVP_aes_192_ecb();
+                        return Native.EVP_aes_192_ecb ();
 
                     case 32:
-                        return Native.EVP_aes_256_ecb();
+                        return Native.EVP_aes_256_ecb ();
                 }
             }
 
-            throw new CryptographicException(string.Format("{0} not supported", mode));
+            throw new CryptographicException (string.Format ("{0} not supported", mode));
         }
     }
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -24,38 +24,31 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-namespace Crimson.OpenSsl
-{
+namespace Crimson.OpenSsl {
 	using System;
 	using System.Runtime.InteropServices;
 	using System.Security.Cryptography;
 
-	public class OpenSslUtil
-	{
-		public static bool IsAvailable()
-		{
-			try
-			{
+	public class OpenSslUtil {
+		public static bool IsAvailable () {
+			try {
 				GetVersionInfo();
 			}
-			catch (DllNotFoundException)
-			{
+			catch (DllNotFoundException) {
 				return false;
 			}
 			
 			return true;
 		}
 
-		public static void EnsureAvailability()
-		{
+		public static void EnsureAvailability () {
 			if (!IsAvailable ()) {
-				throw new CryptographicException ("libcrypto was not found");
+				throw new CryptographicException("libcrypto was not found");
 			}
 		}
 
-		public static string GetVersionInfo()
-		{
-			return Marshal.PtrToStringAuto(Native.SSLeay_version (Native.SSLEAY_VERSION));
+		public static string GetVersionInfo () {
+			return Native.SSLeay_version (Native.SSLeayVersionType.SSLEAY_VERSION);
 		}
 	}
 }

   Commit: 3b2f3ea61da245f0d4e163093175e29c3851a971
   Author: Chris Araman <[email protected]> (chris-araman)
     Date: 2013-10-01 18:53:14 GMT
      URL: https://github.com/mono/crimson/commit/3b2f3ea61da245f0d4e163093175e29c3851a971

P/Invoke marshaling improvements

Changed paths:
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -36,12 +36,10 @@ namespace Crimson.OpenSsl {
     internal static class Native {
         const string DllName = "libcrypto";
 
-        public static int ExpectSuccess (int ret) {
-            if (ret <= 0) {
+        public static void ExpectSuccess (bool ret) {
+            if (!ret) {
                 throw new CryptographicException ();
             }
-
-            return ret;
         }
 
         //
@@ -83,13 +81,16 @@ public enum SSLeayVersionType {
         private extern static void EVP_MD_CTX_destroy (IntPtr ctx);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_DigestInit_ex (SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_DigestInit_ex(SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_DigestUpdate (SafeDigestContextHandle ctx, IntPtr d, uint cnt);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_DigestUpdate(SafeDigestContextHandle ctx, IntPtr d, uint cnt);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_DigestFinal_ex (SafeDigestContextHandle ctx, IntPtr md, out uint s);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_DigestFinal_ex(SafeDigestContextHandle ctx, IntPtr md, out uint s);
 
         internal sealed class SafeDigestHandle : SafeHandleZeroOrMinusOneIsInvalid {
             private SafeDigestHandle () :
@@ -153,16 +154,20 @@ public enum CipherOperation {
         private extern static void EVP_CIPHER_CTX_free (IntPtr a);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_CIPHER_CTX_set_key_length (SafeCipherContextHandle x, int keylen);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_CIPHER_CTX_set_key_length(SafeCipherContextHandle x, int keylen);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_CIPHER_CTX_set_padding (SafeCipherContextHandle x, int padding);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_CIPHER_CTX_set_padding(SafeCipherContextHandle x, int padding);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_CipherInit_ex (SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public extern static bool EVP_CipherInit_ex(SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static int EVP_CipherUpdate (SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
+        [return: MarshalAs (UnmanagedType.Bool)]
+        public extern static bool EVP_CipherUpdate(SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
 
         internal sealed class SafeCipherHandle : SafeHandleZeroOrMinusOneIsInvalid {
             private SafeCipherHandle () :


   Commit: 24258685e0a22480be98ffe6a67bcc34d8d88e32
   Author: Chris Araman <[email protected]> (chris-araman)
     Date: 2013-10-01 19:03:30 GMT
      URL: https://github.com/mono/crimson/commit/24258685e0a22480be98ffe6a67bcc34d8d88e32

fix marshaling of SSLeay_version return value

Changed paths:
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -56,8 +56,7 @@ public enum SSLeayVersionType {
         }
 
         [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false, CharSet = CharSet.Ansi)]
-        [return: MarshalAs (UnmanagedType.LPStr)]
-        public extern static string SSLeay_version (SSLeayVersionType type);
+        public extern static IntPtr SSLeay_version (SSLeayVersionType type);
 
         //
         // Digests


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -48,7 +48,7 @@ public class OpenSslUtil {
 		}
 
 		public static string GetVersionInfo () {
-			return Native.SSLeay_version (Native.SSLeayVersionType.SSLEAY_VERSION);
+			return Marshal.PtrToStringAnsi (Native.SSLeay_version (Native.SSLeayVersionType.SSLEAY_VERSION));
 		}
 	}
 }

   Commit: 39237f1e65c5ad5e82c384bb079ccdfdd44cce3b
   Author: Bassam Tabbara <[email protected]> (bassamtabbara)
     Date: 2013-10-01 19:42:38 GMT
      URL: https://github.com/mono/crimson/commit/39237f1e65c5ad5e82c384bb079ccdfdd44cce3b

Style fixes to match mono's guidelines.

Changed paths:
  M class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  M class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
  M class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
  M class/Crimson.OpenSsl/Tests/OpenSslTests.cs
  M class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
  M class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
  M class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs

Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -23,61 +23,67 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-namespace Crimson.OpenSsl {
-    using System;
+namespace Crimson.OpenSsl
+{
+	using System;
 	using System.Security.Cryptography;
 
-    internal sealed class HashHelper : IDisposable {
-        private readonly Native.SafeDigestContextHandle context;
-        private readonly int hashSize;
+	internal sealed class HashHelper : IDisposable
+	{
+		private readonly Native.SafeDigestContextHandle context;
+		private readonly int hashSize;
 
-        public HashHelper (Native.SafeDigestHandle digest, int hashSize) {
-            this.hashSize = hashSize >> 3;
-            if (this.hashSize > Native.MaximumDigestSize) {
-                throw new ArgumentOutOfRangeException("hashSize");
-            }
+		public HashHelper (Native.SafeDigestHandle digest, int hashSize)
+		{
+			this.hashSize = hashSize >> 3;
+			if (this.hashSize > Native.MaximumDigestSize) {
+				throw new ArgumentOutOfRangeException ("hashSize");
+			}
 
-            this.context = Native.EVP_MD_CTX_create ();
-            Native.ExpectSuccess (Native.EVP_DigestInit_ex (this.context, digest, IntPtr.Zero));
-        }
+			this.context = Native.EVP_MD_CTX_create ();
+			Native.ExpectSuccess (Native.EVP_DigestInit_ex (this.context, digest, IntPtr.Zero));
+		}
 
-        public void Dispose () {
-            this.context.Dispose ();
-        }
+		public void Dispose ()
+		{
+			this.context.Dispose ();
+		}
 
-        public unsafe void Update (byte[] data, int start, int length) {
-            if (length == 0) {
-                return;
-            }
+		public unsafe void Update (byte[] data, int start, int length)
+		{
+			if (length == 0) {
+				return;
+			}
 
-            if (length < uint.MinValue) {
-                throw new ArgumentOutOfRangeException("length");
-            }
+			if (length < uint.MinValue) {
+				throw new ArgumentOutOfRangeException ("length");
+			}
 
-            fixed (byte* p = &data[start]) {
-                Native.ExpectSuccess (Native.EVP_DigestUpdate(this.context, (IntPtr)p, (uint)length));
-            }
-        }
+			fixed (byte* p = &data[start]) {
+				Native.ExpectSuccess (Native.EVP_DigestUpdate (this.context, (IntPtr)p, (uint)length));
+			}
+		}
 
-        public unsafe byte[] Final () {
-            var digest = new byte[Native.MaximumDigestSize];
-            uint len;
+		public unsafe byte[] Final ()
+		{
+			var digest = new byte[Native.MaximumDigestSize];
+			uint len;
 
-            fixed (byte* p = &digest[0]) {
-                Native.ExpectSuccess (Native.EVP_DigestFinal_ex (this.context, (IntPtr)p, out len));
-            }
+			fixed (byte* p = &digest[0]) {
+				Native.ExpectSuccess (Native.EVP_DigestFinal_ex (this.context, (IntPtr)p, out len));
+			}
 
-            if (len != this.hashSize) {
-                throw new CryptographicException (string.Format ("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
-            }
+			if (len != this.hashSize) {
+				throw new CryptographicException (string.Format ("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
+			}
 
-            if (len == digest.Length) {
-                return digest;
-            }
+			if (len == digest.Length) {
+				return digest;
+			}
 
-            var trimmed = new byte[this.hashSize];
-            Buffer.BlockCopy (digest, 0, trimmed, 0, this.hashSize);
-            return trimmed;
-        }
-    }
+			var trimmed = new byte[this.hashSize];
+			Buffer.BlockCopy (digest, 0, trimmed, 0, this.hashSize);
+			return trimmed;
+		}
+	}
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -23,175 +23,187 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
-namespace Crimson.OpenSsl {
-    using Microsoft.Win32.SafeHandles;
-    using System;
-    using System.Runtime.InteropServices;
-    using System.Security.Cryptography;
-
-    /// <summary>
-    /// Documentation can be found here: http://www.openssl.org/docs/crypto/EVP_DigestInit.html
-    /// </summary>
-    internal static class Native {
-        const string DllName = "libcrypto";
-
-        public static void ExpectSuccess (bool ret) {
-            if (!ret) {
-                throw new CryptographicException ();
-            }
-        }
-
-        //
-        // Version
-        //
-
-        [Serializable]
-        public enum SSLeayVersionType {
-            SSLEAY_VERSION = 0,
-            SSLEAY_CFLAGS = 2,
-            SSLEAY_BUILT_ON = 3,
-            SSLEAY_PLATFORM = 4,
-            SSLEAY_DIR = 5,
-        }
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false, CharSet = CharSet.Ansi)]
-        public extern static IntPtr SSLeay_version (SSLeayVersionType type);
-
-        //
-        // Digests
-        //
-
-        public const int MaximumDigestSize = 64;
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeDigestHandle EVP_md5 ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeDigestHandle EVP_sha1 ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeDigestHandle EVP_sha256 ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeDigestContextHandle EVP_MD_CTX_create ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        private extern static void EVP_MD_CTX_destroy (IntPtr ctx);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_DigestInit_ex(SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_DigestUpdate(SafeDigestContextHandle ctx, IntPtr d, uint cnt);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_DigestFinal_ex(SafeDigestContextHandle ctx, IntPtr md, out uint s);
-
-        internal sealed class SafeDigestHandle : SafeHandleZeroOrMinusOneIsInvalid {
-            private SafeDigestHandle () :
-                base (false) {
-            }
-
-            protected override bool ReleaseHandle () {
-                return false;
-            }
-        }
-
-        internal sealed class SafeDigestContextHandle : SafeHandleZeroOrMinusOneIsInvalid {
-            internal SafeDigestContextHandle (IntPtr handle, bool ownsHandle) :
-                base(ownsHandle) {
-                this.SetHandle(handle);
-            }
-
-            private SafeDigestContextHandle () :
-                base (true) {
-            }
-
-            protected override bool ReleaseHandle () {
-                EVP_MD_CTX_destroy (this.handle);
-                return true;
-            }
-        }
-
-        //
-        // Ciphers
-        //
-
-        [Serializable]
-        public enum CipherOperation {
-            Unchanged = -1,
-            Decrypt = 0,
-            Encrypt = 1,
-        }
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_128_cbc ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_192_cbc ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_256_cbc ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_128_ecb ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_192_ecb ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherHandle EVP_aes_256_ecb ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        public extern static SafeCipherContextHandle EVP_CIPHER_CTX_new ();
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        private extern static void EVP_CIPHER_CTX_free (IntPtr a);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_CIPHER_CTX_set_key_length(SafeCipherContextHandle x, int keylen);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_CIPHER_CTX_set_padding(SafeCipherContextHandle x, int padding);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs(UnmanagedType.Bool)]
-        public extern static bool EVP_CipherInit_ex(SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
-
-        [DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
-        [return: MarshalAs (UnmanagedType.Bool)]
-        public extern static bool EVP_CipherUpdate(SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
-
-        internal sealed class SafeCipherHandle : SafeHandleZeroOrMinusOneIsInvalid {
-            private SafeCipherHandle () :
-                base (false) {
-            }
-
-            protected override bool ReleaseHandle () {
-                return false;
-            }
-        }
-
-        internal sealed class SafeCipherContextHandle : SafeHandleZeroOrMinusOneIsInvalid {
-            internal SafeCipherContextHandle (IntPtr handle, bool ownsHandle) :
-                base (ownsHandle) {
-                this.SetHandle(handle);
-            }
-
-            private SafeCipherContextHandle () :
-                base (true) {
-            }
-
-            protected override bool ReleaseHandle () {
-                EVP_CIPHER_CTX_free (this.handle);
-                return true;
-            }
-        }
-    }
+namespace Crimson.OpenSsl
+{
+	using Microsoft.Win32.SafeHandles;
+	using System;
+	using System.Runtime.InteropServices;
+	using System.Security.Cryptography;
+
+	/// <summary>
+	/// Documentation can be found here: http://www.openssl.org/docs/crypto/EVP_DigestInit.html
+	/// </summary>
+	internal static class Native
+	{
+		const string DllName = "libcrypto";
+
+		public static void ExpectSuccess (bool ret)
+		{
+			if (!ret) {
+				throw new CryptographicException ();
+			}
+		}
+		//
+		// Version
+		//
+		[Serializable]
+		public enum SSLeayVersionType
+		{
+			SSLEAY_VERSION = 0,
+			SSLEAY_CFLAGS = 2,
+			SSLEAY_BUILT_ON = 3,
+			SSLEAY_PLATFORM = 4,
+			SSLEAY_DIR = 5,
+		}
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false, CharSet = CharSet.Ansi)]
+		public extern static IntPtr SSLeay_version (SSLeayVersionType type);
+		//
+		// Digests
+		//
+		public const int MaximumDigestSize = 64;
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_md5 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_sha1 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_sha256 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestContextHandle EVP_MD_CTX_create ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		private extern static void EVP_MD_CTX_destroy (IntPtr ctx);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestInit_ex (SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestUpdate (SafeDigestContextHandle ctx, IntPtr d, uint cnt);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestFinal_ex (SafeDigestContextHandle ctx, IntPtr md, out uint s);
+
+		internal sealed class SafeDigestHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			private SafeDigestHandle () :
+                base (false)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				return false;
+			}
+		}
+
+		internal sealed class SafeDigestContextHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			internal SafeDigestContextHandle (IntPtr handle, bool ownsHandle) :
+                base(ownsHandle)
+			{
+				this.SetHandle (handle);
+			}
+
+			private SafeDigestContextHandle () :
+                base (true)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				EVP_MD_CTX_destroy (this.handle);
+				return true;
+			}
+		}
+		//
+		// Ciphers
+		//
+		[Serializable]
+		public enum CipherOperation
+		{
+			Unchanged = -1,
+			Decrypt = 0,
+			Encrypt = 1,
+		}
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_128_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_192_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_256_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_128_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_192_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_256_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherContextHandle EVP_CIPHER_CTX_new ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		private extern static void EVP_CIPHER_CTX_free (IntPtr a);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CIPHER_CTX_set_key_length (SafeCipherContextHandle x, int keylen);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CIPHER_CTX_set_padding (SafeCipherContextHandle x, int padding);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CipherInit_ex (SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs (UnmanagedType.Bool)]
+		public extern static bool EVP_CipherUpdate (SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
+
+		internal sealed class SafeCipherHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			private SafeCipherHandle () :
+                base (false)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				return false;
+			}
+		}
+
+		internal sealed class SafeCipherContextHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			internal SafeCipherContextHandle (IntPtr handle, bool ownsHandle) :
+                base (ownsHandle)
+			{
+				this.SetHandle (handle);
+			}
+
+			private SafeCipherContextHandle () :
+                base (true)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				EVP_CIPHER_CTX_free (this.handle);
+				return true;
+			}
+		}
+	}
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -23,77 +23,80 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
-namespace Crimson.OpenSsl {
-    using System;
-    using System.Security.Cryptography;
-    using Crimson.Common;
-
-    internal unsafe class OpenSslCryptoTransform : CryptoTransformBase {
-        private readonly Native.SafeCipherContextHandle context;
-
-        public OpenSslCryptoTransform (SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
-            : base (algo, encrypt, rgbKey, rgbIV) {
-
-            OpenSslUtil.EnsureAvailability ();
-
-            this.context = Native.EVP_CIPHER_CTX_new ();
-
-            var cptr = this.GetCipher (algo.Mode, rgbKey.Length);
-            var op = encrypt ? Native.CipherOperation.Encrypt : Native.CipherOperation.Decrypt;
-
-            fixed (byte* pkey = &rgbKey[0])
-            fixed (byte* piv = &iv[0]) {
-                Native.ExpectSuccess (Native.EVP_CipherInit_ex (this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, op));
-            }
-
-            Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_key_length (this.context, rgbKey.Length));
-            Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_padding (this.context, 0));
-        }
-
-        protected override void Dispose (bool disposing) {
-            if (disposing) {
-                this.context.Dispose();
-            }
-
-            base.Dispose(disposing);
-        }
-
-        protected override void Transform (byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount) {
-            fixed (byte* input = &inputBuffer[inputOffset])
-            fixed (byte* output = &outputBuffer[outputOffset]) {
-                int outputCount;
-                Native.ExpectSuccess (Native.EVP_CipherUpdate (this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
-            }
-        }
-
-        private Native.SafeCipherHandle GetCipher (CipherMode mode, int keyLength) {
-            if (mode == CipherMode.CBC) {
-                switch (keyLength) {
-                    case 16:
-                        return Native.EVP_aes_128_cbc ();
-
-                    case 24:
-                        return Native.EVP_aes_192_cbc ();
-
-                    case 32:
-                        return Native.EVP_aes_256_cbc ();
-                }
-            }
-            else if (mode == CipherMode.ECB) {
-                switch (keyLength) {
-                    case 16:
-                        return Native.EVP_aes_128_ecb ();
-
-                    case 24:
-                        return Native.EVP_aes_192_ecb ();
-
-                    case 32:
-                        return Native.EVP_aes_256_ecb ();
-                }
-            }
-
-            throw new CryptographicException (string.Format ("{0} not supported", mode));
-        }
-    }
+namespace Crimson.OpenSsl
+{
+	using System;
+	using System.Security.Cryptography;
+	using Crimson.Common;
+
+	internal unsafe class OpenSslCryptoTransform : CryptoTransformBase
+	{
+		private readonly Native.SafeCipherContextHandle context;
+
+		public OpenSslCryptoTransform (SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
+            : base (algo, encrypt, rgbKey, rgbIV)
+		{
+			OpenSslUtil.EnsureAvailability ();
+
+			this.context = Native.EVP_CIPHER_CTX_new ();
+
+			var cptr = this.GetCipher (algo.Mode, rgbKey.Length);
+			var op = encrypt ? Native.CipherOperation.Encrypt : Native.CipherOperation.Decrypt;
+
+			fixed (byte* pkey = &rgbKey[0])
+				fixed (byte* piv = &iv[0]) {
+					Native.ExpectSuccess (Native.EVP_CipherInit_ex (this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, op));
+				}
+
+			Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_key_length (this.context, rgbKey.Length));
+			Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_padding (this.context, 0));
+		}
+
+		protected override void Dispose (bool disposing)
+		{
+			if (disposing) {
+				this.context.Dispose ();
+			}
+
+			base.Dispose (disposing);
+		}
+
+		protected override void Transform (byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount)
+		{
+			fixed (byte* input = &inputBuffer[inputOffset])
+				fixed (byte* output = &outputBuffer[outputOffset]) {
+					int outputCount;
+					Native.ExpectSuccess (Native.EVP_CipherUpdate (this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
+				}
+		}
+
+		private Native.SafeCipherHandle GetCipher (CipherMode mode, int keyLength)
+		{
+			if (mode == CipherMode.CBC) {
+				switch (keyLength) {
+				case 16:
+					return Native.EVP_aes_128_cbc ();
+
+				case 24:
+					return Native.EVP_aes_192_cbc ();
+
+				case 32:
+					return Native.EVP_aes_256_cbc ();
+				}
+			} else if (mode == CipherMode.ECB) {
+				switch (keyLength) {
+				case 16:
+					return Native.EVP_aes_128_ecb ();
+
+				case 24:
+					return Native.EVP_aes_192_ecb ();
+
+				case 32:
+					return Native.EVP_aes_256_ecb ();
+				}
+			}
+
+			throw new CryptographicException (string.Format ("{0} not supported", mode));
+		}
+	}
 }


Modified: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -23,31 +23,34 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
-namespace Crimson.OpenSsl {
+namespace Crimson.OpenSsl
+{
 	using System;
 	using System.Runtime.InteropServices;
 	using System.Security.Cryptography;
 
-	public class OpenSslUtil {
-		public static bool IsAvailable () {
+	public class OpenSslUtil
+	{
+		public static bool IsAvailable ()
+		{
 			try {
-				GetVersionInfo();
-			}
-			catch (DllNotFoundException) {
+				GetVersionInfo ();
+			} catch (DllNotFoundException) {
 				return false;
 			}
 			
 			return true;
 		}
 
-		public static void EnsureAvailability () {
+		public static void EnsureAvailability ()
+		{
 			if (!IsAvailable ()) {
-				throw new CryptographicException("libcrypto was not found");
+				throw new CryptographicException ("libcrypto was not found");
 			}
 		}
 
-		public static string GetVersionInfo () {
+		public static string GetVersionInfo ()
+		{
 			return Marshal.PtrToStringAnsi (Native.SSLeay_version (Native.SSLeayVersionType.SSLEAY_VERSION));
 		}
 	}

Modified: class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
===================================================================
@@ -23,22 +23,20 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
 using System;
 using System.Security.Cryptography;
-
 using Crimson.Security.Cryptography;
 using Crimson.Test.Base;
-
 using NUnit.Framework;
 
-namespace Crimson.Test.OpenSsl {
-
+namespace Crimson.Test.OpenSsl
+{
 	[TestFixture]
-	public class AesKernelTest : AesTest {
+	public class AesKernelTest : AesTest
+	{
 		
 		[SetUp]
-		protected void SetUp () 
+		protected void SetUp ()
 		{
 			algo = Create (); // shared
 		}


Modified: class/Crimson.OpenSsl/Tests/OpenSslTests.cs
===================================================================
@@ -23,16 +23,15 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
 using System;
 using System.IO;
-
 using NUnit.Framework;
 using Crimson.OpenSsl;
 
-namespace Crimson.Test.OpenSsl {
-
-	static class CryptoDevTest {
+namespace Crimson.Test.OpenSsl
+{
+	static class CryptoDevTest
+	{
 		
 		static public void EnsureAvailability ()
 		{

Modified: class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
===================================================================
@@ -23,74 +23,68 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
 using System;
 using System.Security.Cryptography;
-
 using Crimson.Security.Cryptography;
 using Crimson.Test.Base;
-
 using NUnit.Framework;
 
-namespace Crimson.Test.OpenSsl {
-
-    [TestFixture]
-    public class RijndaelOpenSslTests : RijndaelTest
-    {
-        [SetUp]
-        protected void SetUp()
-        {
-            this.algo = this.Create(); // shared
-        }
-
-        protected override SymmetricAlgorithm Create()
-        {
-            return new RijndaelOpenSsl();
-        }
-
-        static bool Compare(byte[] actual, byte[] expected)
-        {
-            if (actual == null)
-                return (expected == null);
-            if (expected == null)
-                return false;
-            if (actual.Length != expected.Length)
-                return false;
-            for (int i = 0; i < actual.Length; i++)
-            {
-                if (actual[i] != expected[i])
-                    return false;
-            }
-            return true;
-        }
-
-        [Test]
-        public void CbcIvBlock()
-        {
-            byte[] key = this.algo.Key;
-            byte[] iv = this.algo.IV;
-            this.algo.Mode = CipherMode.CBC;
-
-            // 1952 = max mv_cesa + one block
-            for (int i = 16; i <= 1952; i += 16)
-            {
-                byte[] data = new byte[i];
-                byte[] enc1 = this.algo.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
-                byte[] enc2 = null;
-                using (Rijndael r = new RijndaelManaged())
-                {
-                    r.Mode = CipherMode.CBC;
-                    r.Key = key;
-                    r.IV = iv;
-                    enc2 = this.algo.CreateEncryptor().TransformFinalBlock(data, 0, data.Length);
-                }
-
-                if (!Compare(enc1, enc2))
-                    Assert.Fail("Data size = " + i);
-            }
-        }
-
-        private static byte[] key1 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+namespace Crimson.Test.OpenSsl
+{
+	[TestFixture]
+	public class RijndaelOpenSslTests : RijndaelTest
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			this.algo = this.Create (); // shared
+		}
+
+		protected override SymmetricAlgorithm Create ()
+		{
+			return new RijndaelOpenSsl ();
+		}
+
+		static bool Compare (byte[] actual, byte[] expected)
+		{
+			if (actual == null)
+				return (expected == null);
+			if (expected == null)
+				return false;
+			if (actual.Length != expected.Length)
+				return false;
+			for (int i = 0; i < actual.Length; i++) {
+				if (actual [i] != expected [i])
+					return false;
+			}
+			return true;
+		}
+
+		[Test]
+		public void CbcIvBlock ()
+		{
+			byte[] key = this.algo.Key;
+			byte[] iv = this.algo.IV;
+			this.algo.Mode = CipherMode.CBC;
+
+			// 1952 = max mv_cesa + one block
+			for (int i = 16; i <= 1952; i += 16) {
+				byte[] data = new byte[i];
+				byte[] enc1 = this.algo.CreateEncryptor ().TransformFinalBlock (data, 0, data.Length);
+				byte[] enc2 = null;
+				using (Rijndael r = new RijndaelManaged()) {
+					r.Mode = CipherMode.CBC;
+					r.Key = key;
+					r.IV = iv;
+					enc2 = this.algo.CreateEncryptor ().TransformFinalBlock (data, 0, data.Length);
+				}
+
+				if (!Compare (enc1, enc2))
+					Assert.Fail ("Data size = " + i);
+			}
+		}
+
+		private static byte[] key1 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
         private static byte[] key2 = { 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01 };
         private static byte[] key3 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
 


Modified: class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
===================================================================
@@ -23,24 +23,21 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
 using System;
 using System.Security.Cryptography;
-
 using Crimson.Security.Cryptography;
 using Crimson.Test.Base;
-
 using NUnit.Framework;
 
 namespace Crimson.Test.OpenSsl
 {
-    [TestFixture]
-    public class SHA1OpenSslTests : SHA1Test
-    {
-        [SetUp]
-        protected void SetUp()
-        {
-            hash = new SHA1OpenSsl();
-        }
-    }
+	[TestFixture]
+	public class SHA1OpenSslTests : SHA1Test
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			hash = new SHA1OpenSsl ();
+		}
+	}
 }


Modified: class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs
===================================================================
@@ -23,24 +23,21 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-
 using System;
 using System.Security.Cryptography;
-
 using Crimson.Security.Cryptography;
 using Crimson.Test.Base;
-
 using NUnit.Framework;
 
 namespace Crimson.Test.OpenSsl
 {
-    [TestFixture]
-    public class SHA256OpenSslTests : SHA256Test
-    {
-        [SetUp]
-        protected void SetUp()
-        {
-            hash = new SHA256OpenSsl();
-        }
-    }
+	[TestFixture]
+	public class SHA256OpenSslTests : SHA256Test
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			hash = new SHA256OpenSsl ();
+		}
+	}
 }


   Commit: b6641f3b460210128ffb9a1d57010c1f4e41a448
   Author: Sebastien Pouliot <[email protected]> (spouliot)
     Date: 2013-10-06 18:29:33 GMT
      URL: https://github.com/mono/crimson/commit/b6641f3b460210128ffb9a1d57010c1f4e41a448

Merge pull request #5 from symform/crimson.openssl

New Crimson.OpenSsl wrapper ontop of openssl (libcrypto)

Changed paths:
  M class/Crimson.CryptoDev/.gitignore
  M class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
  M class/Crimson.CryptoDev/Makefile
  M class/Crimson.CryptoDev/Tests/AesKernelTest.cs
  M class/Crimson.CryptoDev/Tests/CryptoDevTest.cs
  M class/Crimson.CryptoDev/Tests/RijndaelKernelTest.cs
  M class/Crimson.CryptoDev/Tests/SHA1KernelTest.cs
  M class/Crimson.CryptoDev/Tests/SHA256KernelTest.cs
  M class/Crimson.CryptoDev/tools/generator.cs
  M class/README
  M tests/HashAlgorithmTest.cs
  M tests/SHA1Test.cs
  M tests/SHA256Test.cs
  M tests/SymmetricAlgorithmTest.cs
Added paths:
  A class/Crimson.OpenSsl/.gitignore
  A class/Crimson.OpenSsl/AUTHORS
  A class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
  A class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
  A class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
  A class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
  A class/Crimson.OpenSsl/LICENSE
  A class/Crimson.OpenSsl/Makefile
  A class/Crimson.OpenSsl/README
  A class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/OpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
  A class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs
  A class/Crimson.OpenSsl/tools/generator.cs
  A class/Crimson.OpenSsl/tools/torture.cs
  A common/CryptoTransformBase.cs

Modified: class/Crimson.CryptoDev/.gitignore
===================================================================
@@ -4,3 +4,4 @@ CryptoTools.cs
 SymmetricTransform.cs
 TestResult.xml
 AssemblyInfo.cs
+tools/generator.exe
\ No newline at end of file

Modified: class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
===================================================================
@@ -39,46 +39,23 @@
 using System;
 using System.Runtime.InteropServices;
 using System.Security.Cryptography;
+using Crimson.Common;
 
 using Mono.Security.Cryptography;
 
 namespace Crimson.CryptoDev {
 
-	unsafe class CryptoDevTransform : ICryptoTransform {
-		bool encrypt;
-		int BlockSizeByte;
-		byte[] workBuff;
-		bool lastBlock;
+	unsafe class CryptoDevTransform : CryptoTransformBase {
 		Crypt context;
-		PaddingMode padding;
-		byte[] iv;
 		byte[] save_iv;
 
-		public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encryption, byte[] rgbKey, byte[] rgbIV, int bufferBlockSize) 
+		public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encryption, byte[] rgbKey, byte[] rgbIV, int bufferBlockSize)
+			: base(algo, encryption, rgbKey, rgbIV)
+
 		{
 			if (!Helper.IsAvailable (cipher))
 				throw new CryptographicException (String.Format ("{0} not available from /dev/crypto", algo));
 
-			if (rgbKey == null)
-				throw new CryptographicException ("Invalid (null) key");
-
-			BlockSizeByte = (algo.BlockSize >> 3);
-
-			if (rgbIV == null) {
-				rgbIV = KeyBuilder.IV (BlockSizeByte);
-			} else {
-				// 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);
-				}
-				rgbIV = (byte[]) rgbIV.Clone ();
-			}
-
-			encrypt = encryption;
-			padding = algo.Padding;
-
 			// linux does not requires cloning the file descriptor with CRIOGET
 			Session sess = new Session ();
 			sess.cipher = cipher;
@@ -101,32 +78,18 @@ public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encrypti
 				context.op++;
 			
 			if (algo.Mode != CipherMode.ECB) {
-				iv = rgbIV;
 				save_iv = new byte [BlockSizeByte];
 			}
 
-			// transform buffer
-			workBuff = new byte [BlockSizeByte];
 			// change this value if the driver (e.g. mv_cesa) has a limit that 
 			// it can process in a single shot (e.g. 1936 for AES)
 			BufferBlockSize = bufferBlockSize;
 		}
 
-		~CryptoDevTransform () 
-		{
-			Dispose (false);
-		}
-
-		void IDisposable.Dispose () 
-		{
-			Dispose (true);
-		}
-
-		protected virtual void Dispose (bool disposing) 
+		protected override void Dispose (bool disposing) 
 		{
 			if (context.ses != 0) {
 				Helper.CloseSession (ref context.ses);
-				GC.SuppressFinalize (this);
 			}
 		}
 
@@ -134,30 +97,14 @@ protected virtual void Dispose (bool disposing)
 			get; set;
 		}
 
-		public virtual bool CanTransformMultipleBlocks {
-			get { return true; }
-		}
-
-		public virtual bool CanReuseTransform {
-			get { return false; }
-		}
-
-		public virtual int InputBlockSize {
-			get { return BlockSizeByte; }
-		}
-
-		public virtual int OutputBlockSize {
-			get { return BlockSizeByte; }
-		}
-
-		void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
+		protected override void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
 		{
 			while (length > 0) {
 				int size = Math.Min (length, BufferBlockSize);
 				fixed (byte *v = iv)
 				fixed (byte *i = &input [inputOffset])
 				fixed (byte *o = &output [outputOffset]) {
-					if (iv != null) {
+					if (save_iv != null) {
 						context.iv = (IntPtr) v;
 
 						if (!encrypt) {
@@ -180,7 +127,7 @@ void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset,
 					}
 				}
 
-				if (iv != null) {
+				if (save_iv != null) {
 					if (encrypt)
 						Buffer.BlockCopy (output, outputOffset + size - BlockSizeByte, iv, 0, BlockSizeByte);
 					else
@@ -192,266 +139,5 @@ void Transform (byte[] input, int inputOffset, byte[] output, int outputOffset,
 				outputOffset += size;
 			}
 		}
-
-		private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
-		{
-			if (inputBuffer == null)
-				throw new ArgumentNullException ("inputBuffer");
-			if (inputOffset < 0)
-				throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
-			if (inputCount < 0)
-				throw new ArgumentOutOfRangeException ("inputCount", "< 0");
-			// ordered to avoid possible integer overflow
-			if (inputOffset > inputBuffer.Length - inputCount)
-				throw new ArgumentException ("inputBuffer", Locale.GetText ("Overflow"));
-		}
-
-		// this method may get called MANY times so this is the one to optimize
-		public virtual int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
-		{
-			CheckInput (inputBuffer, inputOffset, inputCount);
-			// check output parameters
-			if (outputBuffer == null)
-				throw new ArgumentNullException ("outputBuffer");
-			if (outputOffset < 0)
-				throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
-
-			// ordered to avoid possible integer overflow
-			int len = outputBuffer.Length - inputCount - outputOffset;
-			if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros))) {
-				throw new CryptographicException ("outputBuffer", Locale.GetText ("Overflow"));
-			} else if (KeepLastBlock) {
-				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) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
-			}
-		}
-
-		private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
-		{
-			int offs = inputOffset;
-			int full;
-
-			// this way we don't do a modulo every time we're called
-			// and we may save a division
-			if (inputCount != BlockSizeByte) {
-				if ((inputCount % BlockSizeByte) != 0)
-					throw new CryptographicException ("Invalid input block size.");
-
-				full = inputCount / BlockSizeByte;
-			} else
-				full = 1;
-
-			if (KeepLastBlock)
-				full--;
-
-			int total = 0;
-
-			if (lastBlock) {
-				Transform (workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
-				outputOffset += BlockSizeByte;
-				total += BlockSizeByte;
-				lastBlock = false;
-			}
-
-			if (full > 0) {
-				int length = full * BlockSizeByte;
-				Transform (inputBuffer, offs, outputBuffer, outputOffset, length);
-				offs += length;
-				outputOffset += length;
-				total += length;
-			}
-
-			if (KeepLastBlock) {
-				Buffer.BlockCopy (inputBuffer, offs, workBuff, 0, BlockSizeByte);
-				lastBlock = true;
-			}
-
-			return total;
-		}
-
-		RandomNumberGenerator _rng;
-
-		private void Random (byte[] buffer, int start, int length)
-		{
-			if (_rng == null) {
-				_rng = RandomNumberGenerator.Create ();
-			}
-			byte[] random = new byte [length];
-			_rng.GetBytes (random);
-			Buffer.BlockCopy (random, 0, buffer, start, length);
-		}
-
-		private void ThrowBadPaddingException (PaddingMode padding, int length, int position)
-		{
-			string msg = String.Format (Locale.GetText ("Bad {0} padding."), padding);
-			if (length >= 0)
-				msg += String.Format (Locale.GetText (" Invalid length {0}."), length);
-			if (position >= 0)
-				msg += String.Format (Locale.GetText (" Error found at position {0}."), position);
-			throw new CryptographicException (msg);
-		}
-
-		private byte[] FinalEncrypt (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			// are there still full block to process ?
-			int full = (inputCount / BlockSizeByte) * BlockSizeByte;
-			int rem = inputCount - full;
-			int total = full;
-
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-			case PaddingMode.ISO10126:
-			case PaddingMode.PKCS7:
-				// we need to add an extra block for padding
-				total += BlockSizeByte;
-				break;
-			default:
-				if (inputCount == 0)
-					return new byte [0];
-				if (rem != 0) {
-					if (padding == PaddingMode.None)
-						throw new CryptographicException ("invalid block length");
-					// zero padding the input (by adding a block for the partial data)
-					byte[] paddedInput = new byte [full + BlockSizeByte];
-					Buffer.BlockCopy (inputBuffer, inputOffset, paddedInput, 0, inputCount);
-					inputBuffer = paddedInput;
-					inputOffset = 0;
-					inputCount = paddedInput.Length;
-					total = inputCount;
-				}
-				break;
-			}
-
-			byte[] res = new byte [total];
-			int outputOffset = 0;
-
- 			// process all blocks except the last (final) block
-			if (total > BlockSizeByte) {
-				outputOffset = InternalTransformBlock (inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
-				inputOffset += outputOffset;
-			}
-
-			// now we only have a single last block to encrypt
-			byte pad = (byte) (BlockSizeByte - rem);
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-				// XX 00 00 00 00 00 00 07 (zero + padding length)
-				res [res.Length - 1] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			case PaddingMode.ISO10126:
-				// XX 3F 52 2A 81 AB F7 07 (random + padding length)
-				Random (res, res.Length - pad, pad - 1);
-				res [res.Length - 1] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			case PaddingMode.PKCS7:
-				// XX 07 07 07 07 07 07 07 (padding length)
-				for (int i = res.Length; --i >= (res.Length - pad);) 
-					res [i] = pad;
-				Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
-				// the last padded block will be transformed in-place
-				InternalTransformBlock (res, full, BlockSizeByte, res, full);
-				break;
-			default:
-				InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
-				break;
-			}
-			return res;
-		}
-
-		private byte[] FinalDecrypt (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			if ((inputCount % BlockSizeByte) > 0)
-				throw new CryptographicException ("Invalid input block size.");
-
-			int total = inputCount;
-			if (lastBlock)
-				total += BlockSizeByte;
-
-			byte[] res = new byte [total];
-			int outputOffset = 0;
-
-			if (inputCount > 0)
-				outputOffset = InternalTransformBlock (inputBuffer, inputOffset, inputCount, res, 0);
-
-			if (lastBlock) {
-				Transform (workBuff, 0, res, outputOffset, BlockSizeByte);
-				outputOffset += BlockSizeByte;
-				lastBlock = false;
-			}
-
-			// total may be 0 (e.g. PaddingMode.None)
-			byte pad = ((total > 0) ? res [total - 1] : (byte) 0);
-			switch (padding) {
-			case PaddingMode.ANSIX923:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				for (int i = pad - 1; i > 0; i--) {
-					if (res [total - 1 - i] != 0x00)
-						ThrowBadPaddingException (padding, -1, i);
-				}
-				total -= pad;
-				break;
-			case PaddingMode.ISO10126:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				total -= pad;
-				break;
-			case PaddingMode.PKCS7:
-				if ((pad == 0) || (pad > BlockSizeByte))
-					ThrowBadPaddingException (padding, pad, -1);
-				for (int i = pad - 1; i > 0; i--) {
-					if (res [total - 1 - i] != pad)
-						ThrowBadPaddingException (padding, -1, i);
-				}
-				total -= pad;
-				break;
-			case PaddingMode.None:	// nothing to do - it's a multiple of block size
-			case PaddingMode.Zeros:	// nothing to do - user must unpad himself
-				break;
-			}
-
-			// return output without padding
-			if (total > 0) {
-				byte[] data = new byte [total];
-				Buffer.BlockCopy (res, 0, data, 0, total);
-				// zeroize decrypted data (copy with padding)
-				Array.Clear (res, 0, res.Length);
-				return data;
-			}
-			else
-				return new byte [0];
-		}
-
-		public virtual byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) 
-		{
-			CheckInput (inputBuffer, inputOffset, inputCount);
-
-			if (encrypt)
-				return FinalEncrypt (inputBuffer, inputOffset, inputCount);
-			else
-				return FinalDecrypt (inputBuffer, inputOffset, inputCount);
-		}
 	}
 }

Modified: class/Crimson.CryptoDev/Makefile
===================================================================
@@ -12,7 +12,8 @@ SOURCES = \
 	Crimson.Security.Cryptography/RijndaelKernel.cs	\
 	CryptoTools.cs 					\
 	AssemblyInfo.cs					\
-	../../common/Locale.cs
+	../../common/Locale.cs          \
+	../../common/CryptoTransformBase.cs
 
 all: Crimson.CryptoDev.dll
 

Modified: class/Crimson.CryptoDev/Tests/AesKernelTest.cs
===================================================================
@@ -40,7 +40,7 @@ public class AesKernelTest : AesTest {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.AES_CBC);
 			algo = Create (); // shared
 		}
 

Modified: class/Crimson.CryptoDev/Tests/CryptoDevTest.cs
===================================================================
@@ -26,6 +26,7 @@
 
 using System;
 using System.IO;
+using Crimson.CryptoDev;
 
 using NUnit.Framework;
 
@@ -51,5 +52,14 @@ static public void EnsureAvailability ()
 				// fix by doing "sudo chmod 600 /dev/crypto"
 			}
 		}
+
+		static public void EnsureAvailability (Cipher cipher)
+		{
+			EnsureAvailability();
+
+			if (!Crimson.CryptoDev.Helper.IsAvailable (cipher)) {
+				Assert.Ignore (string.Format("{0} not available on this platform", cipher));
+			}
+		}
 	}
 }

Modified: class/Crimson.CryptoDev/Tests/RijndaelKernelTest.cs
===================================================================
@@ -41,7 +41,7 @@ public class RijndaelKernelTest : RijndaelTest {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.AES_CBC);
 			algo = Create (); // shared
 		}
 

Modified: class/Crimson.CryptoDev/Tests/SHA1KernelTest.cs
===================================================================
@@ -39,7 +39,7 @@ public class SHA1KernelTest : SHA1Test {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.SHA1);
 			hash = new SHA1Kernel ();
 		}
 	}

Modified: class/Crimson.CryptoDev/Tests/SHA256KernelTest.cs
===================================================================
@@ -39,7 +39,7 @@ public class SHA256KernelTest : SHA256Test {
 		[SetUp]
 		protected void SetUp () 
 		{
-			CryptoDevTest.EnsureAvailability ();
+			CryptoDevTest.EnsureAvailability (Crimson.CryptoDev.Cipher.SHA256);
 			hash = new SHA256Kernel ();
 		}
 	}

Modified: class/Crimson.CryptoDev/tools/generator.cs
===================================================================
@@ -76,21 +76,11 @@ public class {0}Kernel : {0} {
 
 		public static int BufferBlockSize { get; set; }
 
-		public {0}Kernel ()
-		{
-		}
-
-		~{0}Kernel ()
-		{
-			Dispose (false);
-		}
-
 		protected override void Dispose (bool disposing)
 		{
-			if (disposing && (helper != null)) {
+			if (disposing && helper != null) {
 				helper.Dispose ();
-				helper = null;
-				GC.SuppressFinalize (this);
+                helper = null;
 			}
 			base.Dispose (disposing);
 		}

Added: class/Crimson.OpenSsl/.gitignore
===================================================================
@@ -0,0 +1,6 @@
+*.dll*
+Crimson.Security.Cryptography/*.g.cs
+TestResult.xml
+AssemblyInfo.cs
+tools/generator.exe
+torture.exe*

Added: class/Crimson.OpenSsl/AUTHORS
===================================================================
@@ -0,0 +1,2 @@
+Sebastien Pouliot  <[email protected]>
+Bassam Tabbara <[email protected]>
\ No newline at end of file

Added: class/Crimson.OpenSsl/Crimson.OpenSsl/HashHelper.cs
===================================================================
@@ -0,0 +1,89 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Crimson.OpenSsl
+{
+	using System;
+	using System.Security.Cryptography;
+
+	internal sealed class HashHelper : IDisposable
+	{
+		private readonly Native.SafeDigestContextHandle context;
+		private readonly int hashSize;
+
+		public HashHelper (Native.SafeDigestHandle digest, int hashSize)
+		{
+			this.hashSize = hashSize >> 3;
+			if (this.hashSize > Native.MaximumDigestSize) {
+				throw new ArgumentOutOfRangeException ("hashSize");
+			}
+
+			this.context = Native.EVP_MD_CTX_create ();
+			Native.ExpectSuccess (Native.EVP_DigestInit_ex (this.context, digest, IntPtr.Zero));
+		}
+
+		public void Dispose ()
+		{
+			this.context.Dispose ();
+		}
+
+		public unsafe void Update (byte[] data, int start, int length)
+		{
+			if (length == 0) {
+				return;
+			}
+
+			if (length < uint.MinValue) {
+				throw new ArgumentOutOfRangeException ("length");
+			}
+
+			fixed (byte* p = &data[start]) {
+				Native.ExpectSuccess (Native.EVP_DigestUpdate (this.context, (IntPtr)p, (uint)length));
+			}
+		}
+
+		public unsafe byte[] Final ()
+		{
+			var digest = new byte[Native.MaximumDigestSize];
+			uint len;
+
+			fixed (byte* p = &digest[0]) {
+				Native.ExpectSuccess (Native.EVP_DigestFinal_ex (this.context, (IntPtr)p, out len));
+			}
+
+			if (len != this.hashSize) {
+				throw new CryptographicException (string.Format ("Mismatched hash length was expecting {0} but got {1}", this.hashSize, len));
+			}
+
+			if (len == digest.Length) {
+				return digest;
+			}
+
+			var trimmed = new byte[this.hashSize];
+			Buffer.BlockCopy (digest, 0, trimmed, 0, this.hashSize);
+			return trimmed;
+		}
+	}
+}


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/Native.cs
===================================================================
@@ -0,0 +1,209 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Crimson.OpenSsl
+{
+	using Microsoft.Win32.SafeHandles;
+	using System;
+	using System.Runtime.InteropServices;
+	using System.Security.Cryptography;
+
+	/// <summary>
+	/// Documentation can be found here: http://www.openssl.org/docs/crypto/EVP_DigestInit.html
+	/// </summary>
+	internal static class Native
+	{
+		const string DllName = "libcrypto";
+
+		public static void ExpectSuccess (bool ret)
+		{
+			if (!ret) {
+				throw new CryptographicException ();
+			}
+		}
+		//
+		// Version
+		//
+		[Serializable]
+		public enum SSLeayVersionType
+		{
+			SSLEAY_VERSION = 0,
+			SSLEAY_CFLAGS = 2,
+			SSLEAY_BUILT_ON = 3,
+			SSLEAY_PLATFORM = 4,
+			SSLEAY_DIR = 5,
+		}
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false, CharSet = CharSet.Ansi)]
+		public extern static IntPtr SSLeay_version (SSLeayVersionType type);
+		//
+		// Digests
+		//
+		public const int MaximumDigestSize = 64;
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_md5 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_sha1 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestHandle EVP_sha256 ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeDigestContextHandle EVP_MD_CTX_create ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		private extern static void EVP_MD_CTX_destroy (IntPtr ctx);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestInit_ex (SafeDigestContextHandle ctx, SafeDigestHandle type, IntPtr impl);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestUpdate (SafeDigestContextHandle ctx, IntPtr d, uint cnt);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_DigestFinal_ex (SafeDigestContextHandle ctx, IntPtr md, out uint s);
+
+		internal sealed class SafeDigestHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			private SafeDigestHandle () :
+                base (false)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				return false;
+			}
+		}
+
+		internal sealed class SafeDigestContextHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			internal SafeDigestContextHandle (IntPtr handle, bool ownsHandle) :
+                base(ownsHandle)
+			{
+				this.SetHandle (handle);
+			}
+
+			private SafeDigestContextHandle () :
+                base (true)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				EVP_MD_CTX_destroy (this.handle);
+				return true;
+			}
+		}
+		//
+		// Ciphers
+		//
+		[Serializable]
+		public enum CipherOperation
+		{
+			Unchanged = -1,
+			Decrypt = 0,
+			Encrypt = 1,
+		}
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_128_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_192_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_256_cbc ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_128_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_192_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherHandle EVP_aes_256_ecb ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		public extern static SafeCipherContextHandle EVP_CIPHER_CTX_new ();
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		private extern static void EVP_CIPHER_CTX_free (IntPtr a);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CIPHER_CTX_set_key_length (SafeCipherContextHandle x, int keylen);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CIPHER_CTX_set_padding (SafeCipherContextHandle x, int padding);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs(UnmanagedType.Bool)]
+		public extern static bool EVP_CipherInit_ex (SafeCipherContextHandle ctx, SafeCipherHandle type, IntPtr impl, IntPtr key, IntPtr iv, CipherOperation enc);
+
+		[DllImport (DllName, CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
+		[return: MarshalAs (UnmanagedType.Bool)]
+		public extern static bool EVP_CipherUpdate (SafeCipherContextHandle ctx, IntPtr outb, out int outl, IntPtr inb, int inl);
+
+		internal sealed class SafeCipherHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			private SafeCipherHandle () :
+                base (false)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				return false;
+			}
+		}
+
+		internal sealed class SafeCipherContextHandle : SafeHandleZeroOrMinusOneIsInvalid
+		{
+			internal SafeCipherContextHandle (IntPtr handle, bool ownsHandle) :
+                base (ownsHandle)
+			{
+				this.SetHandle (handle);
+			}
+
+			private SafeCipherContextHandle () :
+                base (true)
+			{
+			}
+
+			protected override bool ReleaseHandle ()
+			{
+				EVP_CIPHER_CTX_free (this.handle);
+				return true;
+			}
+		}
+	}
+}


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslCryptoTransform.cs
===================================================================
@@ -0,0 +1,102 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Crimson.OpenSsl
+{
+	using System;
+	using System.Security.Cryptography;
+	using Crimson.Common;
+
+	internal unsafe class OpenSslCryptoTransform : CryptoTransformBase
+	{
+		private readonly Native.SafeCipherContextHandle context;
+
+		public OpenSslCryptoTransform (SymmetricAlgorithm algo, bool encrypt, byte[] rgbKey, byte[] rgbIV)
+            : base (algo, encrypt, rgbKey, rgbIV)
+		{
+			OpenSslUtil.EnsureAvailability ();
+
+			this.context = Native.EVP_CIPHER_CTX_new ();
+
+			var cptr = this.GetCipher (algo.Mode, rgbKey.Length);
+			var op = encrypt ? Native.CipherOperation.Encrypt : Native.CipherOperation.Decrypt;
+
+			fixed (byte* pkey = &rgbKey[0])
+				fixed (byte* piv = &iv[0]) {
+					Native.ExpectSuccess (Native.EVP_CipherInit_ex (this.context, cptr, IntPtr.Zero, (IntPtr)pkey, (IntPtr)piv, op));
+				}
+
+			Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_key_length (this.context, rgbKey.Length));
+			Native.ExpectSuccess (Native.EVP_CIPHER_CTX_set_padding (this.context, 0));
+		}
+
+		protected override void Dispose (bool disposing)
+		{
+			if (disposing) {
+				this.context.Dispose ();
+			}
+
+			base.Dispose (disposing);
+		}
+
+		protected override void Transform (byte[] inputBuffer, int inputOffset, byte[] outputBuffer, int outputOffset, int inputCount)
+		{
+			fixed (byte* input = &inputBuffer[inputOffset])
+				fixed (byte* output = &outputBuffer[outputOffset]) {
+					int outputCount;
+					Native.ExpectSuccess (Native.EVP_CipherUpdate (this.context, (IntPtr)output, out outputCount, (IntPtr)input, inputCount));
+				}
+		}
+
+		private Native.SafeCipherHandle GetCipher (CipherMode mode, int keyLength)
+		{
+			if (mode == CipherMode.CBC) {
+				switch (keyLength) {
+				case 16:
+					return Native.EVP_aes_128_cbc ();
+
+				case 24:
+					return Native.EVP_aes_192_cbc ();
+
+				case 32:
+					return Native.EVP_aes_256_cbc ();
+				}
+			} else if (mode == CipherMode.ECB) {
+				switch (keyLength) {
+				case 16:
+					return Native.EVP_aes_128_ecb ();
+
+				case 24:
+					return Native.EVP_aes_192_ecb ();
+
+				case 32:
+					return Native.EVP_aes_256_ecb ();
+				}
+			}
+
+			throw new CryptographicException (string.Format ("{0} not supported", mode));
+		}
+	}
+}


Added: class/Crimson.OpenSsl/Crimson.OpenSsl/OpenSslUtil.cs
===================================================================
@@ -0,0 +1,57 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace Crimson.OpenSsl
+{
+	using System;
+	using System.Runtime.InteropServices;
+	using System.Security.Cryptography;
+
+	public class OpenSslUtil
+	{
+		public static bool IsAvailable ()
+		{
+			try {
+				GetVersionInfo ();
+			} catch (DllNotFoundException) {
+				return false;
+			}
+			
+			return true;
+		}
+
+		public static void EnsureAvailability ()
+		{
+			if (!IsAvailable ()) {
+				throw new CryptographicException ("libcrypto was not found");
+			}
+		}
+
+		public static string GetVersionInfo ()
+		{
+			return Marshal.PtrToStringAnsi (Native.SSLeay_version (Native.SSLeayVersionType.SSLEAY_VERSION));
+		}
+	}
+}

Added: class/Crimson.OpenSsl/LICENSE
===================================================================
@@ -0,0 +1,20 @@
+Copyright 2013 Symform Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: class/Crimson.OpenSsl/Makefile
===================================================================
@@ -0,0 +1,85 @@
+CSC=gmcs
+
+CSC_FLAGS= -optimize
+#CSC_FLAGS= -debug
+
+SOURCES = \
+	Crimson.OpenSsl/Native.cs			\
+	Crimson.OpenSsl/HashHelper.cs		\
+	Crimson.OpenSsl/OpenSslCryptoTransform.cs \
+	Crimson.OpenSsl/OpenSslUtil.cs \
+	AssemblyInfo.cs					\
+	../../common/Locale.cs \
+	../../common/CryptoTransformBase.cs
+
+all: Crimson.OpenSsl.dll
+
+GENERATED_SOURCES = \
+	Crimson.Security.Cryptography/AesOpenSsl.g.cs	\
+	Crimson.Security.Cryptography/RijndaelOpenSsl.g.cs	\
+	Crimson.Security.Cryptography/SHA1OpenSsl.g.cs	\
+	Crimson.Security.Cryptography/SHA256OpenSsl.g.cs
+
+tools/generator.exe: tools/generator.cs
+	$(CSC) -t:exe -out:$@ $^
+
+$(GENERATED_SOURCES): tools/generator.exe
+	mono tools/generator.exe Crimson.Security.Cryptography
+
+AssemblyInfo.cs:
+	@ver='tarball'; \
+	if test -d $(CURDIR)/../../.git; then \
+	  cd $(CURDIR)/../..; \
+	  LANG=C; export LANG; \
+	  branch=`git branch | grep '^\*' | cut -d ' ' -f 2`; \
+	  version=`git log --no-color --first-parent -n1 --pretty=format:%h`; \
+	  if [ "$$branch" = '(no' ]; then \
+	    ver="$$version"; \
+	  else \
+	    ver="$$branch/$$version"; \
+	  fi; \
+	  cd $(CURDIR); \
+	fi; \
+	( \
+	  echo "using System.Reflection;"; \
+	  echo "[assembly:AssemblyInformationalVersionAttribute(\"$${ver}\")]"; \
+	) > $@
+
+Crimson.OpenSsl.dll: $(SOURCES) $(GENERATED_SOURCES)
+	$(CSC) $(CSC_FLAGS) $^ -t:library -unsafe -out:$@ -keyfile:../crimson.snk
+
+torture.exe: Crimson.OpenSsl.dll tools/torture.cs
+	dmcs -debug tools/torture.cs -r:Crimson.OpenSsl.dll -out:torture.exe
+
+torture: torture.exe
+	mono --debug torture.exe -v
+
+clean:
+	rm -f torture.exe*
+	rm -f tools/generator.exe
+	rm -f $(GENERATED_SOURCES) AssemblyInfo.cs
+	rm -f *.dll*
+
+BASE_TESTS = \
+	../../tests/AesTest.cs			\
+	../../tests/HashAlgorithmTest.cs	\
+	../../tests/RijndaelTest.cs		\
+	../../tests/SHA1Test.cs			\
+	../../tests/SHA256Test.cs		\
+	../../tests/SymmetricAlgorithmTest.cs
+
+TESTS = \
+	Tests/AesOpenSslTests.cs		\
+	Tests/RijndaelOpenSslTests.cs	\
+	Tests/SHA1OpenSslTests.cs		\
+	Tests/SHA256OpenSslTests.cs	\
+	Tests/OpenSslTests.cs
+
+Crimson.OpenSsl.Tests.dll: $(BASE_TESTS) $(TESTS) Crimson.OpenSsl.dll
+	mcs -debug $(BASE_TESTS) $(TESTS) -t:library -out:$@ -r:Crimson.OpenSsl.dll -pkg:mono-nunit
+
+test: Crimson.OpenSsl.Tests.dll
+
+run-test: test
+	@echo running tests
+	nunit-console Crimson.OpenSsl.Tests.dll

Added: class/Crimson.OpenSsl/README
===================================================================
@@ -0,0 +1,19 @@
+This assembly goal is to provide a managed wrapper on top of libcrypto[1].
+
+References:
+[1] http://www.openssl.org/
+
+libcrypto Availability
+----------------------
+
+Most Linux distributions ship with openssl. 
+
+Building
+--------
+
+If a recent mono is available then 'make' should be enough to build
+the generator (creating the source files) and then build the assembly
+
+You can verify that everything works, if nunit is available, by doing
+'make run-test'
+

Added: class/Crimson.OpenSsl/Tests/AesOpenSslTests.cs
===================================================================
@@ -0,0 +1,49 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Security.Cryptography;
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+	[TestFixture]
+	public class AesKernelTest : AesTest
+	{
+		
+		[SetUp]
+		protected void SetUp ()
+		{
+			algo = Create (); // shared
+		}
+
+		protected override SymmetricAlgorithm Create ()
+		{
+			return new AesOpenSsl ();
+		}
+	}
+}
\ No newline at end of file

Added: class/Crimson.OpenSsl/Tests/OpenSslTests.cs
===================================================================
@@ -0,0 +1,43 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.IO;
+using NUnit.Framework;
+using Crimson.OpenSsl;
+
+namespace Crimson.Test.OpenSsl
+{
+	static class CryptoDevTest
+	{
+		
+		static public void EnsureAvailability ()
+		{
+			if (!OpenSslUtil.IsAvailable ()) {
+				Assert.Ignore ("libcrypto not found.");
+			}
+		}
+	}
+}

Added: class/Crimson.OpenSsl/Tests/RijndaelOpenSslTests.cs
===================================================================
@@ -0,0 +1,512 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Security.Cryptography;
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+	[TestFixture]
+	public class RijndaelOpenSslTests : RijndaelTest
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			this.algo = this.Create (); // shared
+		}
+
+		protected override SymmetricAlgorithm Create ()
+		{
+			return new RijndaelOpenSsl ();
+		}
+
+		static bool Compare (byte[] actual, byte[] expected)
+		{
+			if (actual == null)
+				return (expected == null);
+			if (expected == null)
+				return false;
+			if (actual.Length != expected.Length)
+				return false;
+			for (int i = 0; i < actual.Length; i++) {
+				if (actual [i] != expected [i])
+					return false;
+			}
+			return true;
+		}
+
+		[Test]
+		public void CbcIvBlock ()
+		{
+			byte[] key = this.algo.Key;
+			byte[] iv = this.algo.IV;
+			this.algo.Mode = CipherMode.CBC;
+
+			// 1952 = max mv_cesa + one block
+			for (int i = 16; i <= 1952; i += 16) {
+				byte[] data = new byte[i];
+				byte[] enc1 = this.algo.CreateEncryptor ().TransformFinalBlock (data, 0, data.Length);
+				byte[] enc2 = null;
+				using (Rijndael r = new RijndaelManaged()) {
+					r.Mode = CipherMode.CBC;
+					r.Key = key;
+					r.IV = iv;
+					enc2 = this.algo.CreateEncryptor ().TransformFinalBlock (data, 0, data.Length);
+				}
+
+				if (!Compare (enc1, enc2))
+					Assert.Fail ("Data size = " + i);
+			}
+		}
+
+		private static byte[] key1 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+        private static byte[] key2 = { 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01 };
+        private static byte[] key3 = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+
+        protected byte[] CombineKeys(byte[] key1, byte[] key2, byte[] key3)
+        {
+            int k1l = key1.Length;
+            int k2l = key2.Length;
+            int k3l = key3.Length;
+            byte[] key = new byte[k1l + k2l + k3l];
+            Array.Copy(key1, 0, key, 0, k1l);
+            Array.Copy(key2, 0, key, k1l, k2l);
+            Array.Copy(key3, 0, key, k1l + k2l, k3l);
+            return key;
+        }
+
+        private Rijndael GetAES()
+        {
+            Rijndael aes = (Rijndael)this.Create();
+            aes.Key = this.CombineKeys(key1, key2, key3);
+            return aes;
+        }
+
+        private byte[] GetData(byte size)
+        {
+            byte[] data = new byte[size];
+            for (byte i = 0; i < size; i++)
+            {
+                data[i] = i;
+            }
+            return data;
+        }
+
+        private byte[] Decrypt(SymmetricAlgorithm algo, PaddingMode padding, byte[] data)
+        {
+            algo.IV = new byte[algo.BlockSize >> 3];
+            algo.Mode = CipherMode.CBC;
+            algo.Padding = padding;
+            ICryptoTransform ct = algo.CreateDecryptor();
+            return ct.TransformFinalBlock(data, 0, data.Length);
+        }
+
+        private byte[] Encrypt(SymmetricAlgorithm algo, PaddingMode padding, byte[] data)
+        {
+            algo.IV = new byte[algo.BlockSize >> 3];
+            algo.Mode = CipherMode.CBC;
+            algo.Padding = padding;
+            ICryptoTransform ct = algo.CreateEncryptor();
+            return ct.TransformFinalBlock(data, 0, data.Length);
+        }
+
+        [Test]
+        [ExpectedException(typeof(CryptographicException))]
+        public void RijndaelNone_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            this.Encrypt(aes, PaddingMode.None, data);
+        }
+
+        [Test]
+        public void RijndaelNone_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB", BitConverter.ToString(encdata), "RijndaelNone_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.None, encdata);
+            this.AssertEquals("RijndaelNone_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        [ExpectedException(typeof(CryptographicException))]
+        public void RijndaelNone_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            this.Encrypt(aes, PaddingMode.None, data);
+        }
+
+        [Test]
+        public void RijndaelNone_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.None, data);
+            // note: encrypted data is truncated to a multiple of block size
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF", BitConverter.ToString(encdata), "RijndaelNone_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.None, encdata);
+            this.AssertEquals("RijndaelNone_ExactMultipleBlockSize_Decrypt", this.GetData(48), decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("AB-E0-20-5E-BC-28-A0-B7-A7-56-A3-BF-13-55-13-7E", BitConverter.ToString(encdata), "RijndaelPKCS7_SmallerThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_SmallerThanOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-60-CE-9F-E0-72-3B-D6-D1-A5-F8-33-D8-25-31-7F-D4", BitConverter.ToString(encdata), "RijndaelPKCS7_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-06-3F-D3-51-8D-55-E9-2F-02-4A-4E-F2-91-55-31-83", BitConverter.ToString(encdata), "RijndaelPKCS7_MoreThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_MoreThanOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelPKCS7_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.PKCS7, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF-37-42-81-21-47-A7-E0-AA-64-A7-8B-65-25-95-AA-54", BitConverter.ToString(encdata), "RijndaelPKCS7_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.PKCS7, encdata);
+            this.AssertEquals("RijndaelPKCS7_ExactMultipleBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelZeros_SmallerThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(8);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("DD-BE-D7-CE-E2-DD-5C-A3-3E-44-A1-76-00-E5-5B-5D", BitConverter.ToString(encdata), "RijndaelZeros_SmallerThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            Assert.AreEqual("00-01-02-03-04-05-06-07-00-00-00-00-00-00-00-00", BitConverter.ToString(decdata), "RijndaelZeros_SmallerThanOneBlockSize_Decrypt");
+        }
+
+        [Test]
+        public void RijndaelZeros_ExactlyOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(16);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB", BitConverter.ToString(encdata), "RijndaelZeros_ExactlyOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            this.AssertEquals("RijndaelZeros_ExactlyOneBlockSize_Decrypt", data, decdata);
+        }
+
+        [Test]
+        public void RijndaelZeros_MoreThanOneBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(20);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-04-6C-F7-A5-DE-FF-B4-30-29-7A-0E-04-3B-D4-B8-F2", BitConverter.ToString(encdata), "RijndaelZeros_MoreThanOneBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            Assert.AreEqual("00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F-10-11-12-13-00-00-00-00-00-00-00-00-00-00-00-00", BitConverter.ToString(decdata), "RijndaelZeros_MoreThanOneBlockSize_Decrypt");
+        }
+
+        [Test]
+        public void RijndaelZeros_ExactMultipleBlockSize()
+        {
+            Rijndael aes = this.GetAES();
+            byte[] data = this.GetData(48);
+            byte[] encdata = this.Encrypt(aes, PaddingMode.Zeros, data);
+            Assert.AreEqual("79-42-36-2F-D6-DB-F1-0C-87-99-58-06-D5-F6-B0-BB-E1-27-3E-21-5A-BE-D5-12-F4-AF-06-8D-0A-BD-02-64-02-CB-FF-D7-32-19-5E-69-3C-54-C2-8C-A1-D7-72-FF", BitConverter.ToString(encdata), "RijndaelZeros_ExactMultipleBlockSize_Encrypt");
+            byte[] decdata = this.Decrypt(aes, PaddingMode.Zeros, encdata);
+            this.AssertEquals("RijndaelZeros_ExactMultipleBlockSize_Decrypt", this.GetData(48), decdata);
+        }
+
+        private byte[] GetKey(SymmetricAlgorithm sa)
+        {
+            byte[] key = new byte[sa.KeySize >> 3];
+            // no weak key this way (DES, TripleDES)
+            for (byte i = 0; i < key.Length; i++)
+                key[i] = i;
+            return key;
+        }
+
+        private byte[] GetIV(SymmetricAlgorithm sa)
+        {
+            return new byte[sa.BlockSize >> 3];
+        }
+
+        private ICryptoTransform GetEncryptor(SymmetricAlgorithm sa, PaddingMode mode)
+        {
+            sa.Mode = CipherMode.ECB; // basic (no) mode
+            sa.Padding = mode;
+            return sa.CreateEncryptor(this.GetKey(sa), this.GetIV(sa));
+        }
+
+        private ICryptoTransform GetDecryptor(SymmetricAlgorithm sa, PaddingMode mode)
+        {
+            sa.Mode = CipherMode.ECB; // basic (no) mode
+            sa.Padding = mode;
+            return sa.CreateDecryptor(this.GetKey(sa), this.GetIV(sa));
+        }
+
+        // the best way to verify padding is to:
+        // a. encrypt data larger than one block with a padding mode "X"
+        // b. decrypt the data with padding mode "None"
+        // c. compare the last (padding) bytes with the expected padding
+
+        private void ANSIX923_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ANSIX923);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ANSI X.923 is all 0 except last byte (length)
+            for (int i = 0; i < bs - 1; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ANSIX923_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ANSIX923);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ANSI X.923 is all 0 except last byte (length)
+            for (int i = 0; i < pd - 1; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ISO10126_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ISO10126);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ISO10126 is all random except last byte (length)
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void ISO10126_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.ISO10126);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - ISO10126 is all random except last byte (length)
+            Assert.AreEqual(pd, decdata[decdata.Length - 1], "last byte");
+        }
+
+        private void PKCS7_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.PKCS7);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(data.Length * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - PKCS7 is all padding char
+            for (int i = 0; i < bs; i++)
+                Assert.AreEqual(pd, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        private void PKCS7_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.PKCS7);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - PKCS7 is all padding char
+            for (int i = 0; i < pd; i++)
+                Assert.AreEqual(pd, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        private void Zeros_Full(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one full block
+            byte[] data = new byte[bs]; // in bytes
+            for (int i = 0; i < data.Length; i++)
+                data[i] = 0xFF;
+
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.Zeros);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // NO extra block is used for zero padding
+            Assert.AreEqual(data.Length, encdata.Length, "no extra block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            // now validate absence of padding
+            Assert.AreEqual(0xFF, decdata[decdata.Length - 1], "no padding");
+        }
+
+        private void Zeros_Partial(SymmetricAlgorithm sa)
+        {
+            int bs = (sa.BlockSize >> 3);
+            // one and an half block
+            byte[] data = new byte[bs + (bs >> 1)]; // in bytes
+            for (int i = 0; i < data.Length; i++)
+                data[i] = 0xFF;
+
+            ICryptoTransform enc = this.GetEncryptor(sa, PaddingMode.Zeros);
+            byte[] encdata = enc.TransformFinalBlock(data, 0, data.Length);
+            // one block of padding is added			
+            Assert.AreEqual(bs * 2, encdata.Length, "one more block added");
+
+            ICryptoTransform dec = this.GetDecryptor(sa, PaddingMode.None);
+            byte[] decdata = dec.TransformFinalBlock(encdata, 0, encdata.Length);
+            Assert.AreEqual(encdata.Length, decdata.Length, "no unpadding");
+
+            int pd = decdata.Length - data.Length;
+            // now validate padding - Zeros is all 0x00 char
+            for (int i = 0; i < pd; i++)
+                Assert.AreEqual(0x00, decdata[decdata.Length - pd + i], i.ToString());
+        }
+
+        [Test]
+        public void Rijndael_ANSIX923_Full()
+        {
+            this.ANSIX923_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ANSIX923_Partial()
+        {
+            this.ANSIX923_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ISO10126_Full()
+        {
+            this.ISO10126_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_ISO10126_Partial()
+        {
+            this.ISO10126_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_PKCS7_Full()
+        {
+            this.PKCS7_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_PKCS7_Partial()
+        {
+            this.PKCS7_Partial(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_Zeros_Full()
+        {
+            this.Zeros_Full(this.Create());
+        }
+
+        [Test]
+        public void Rijndael_Zeros_Partial()
+        {
+            this.Zeros_Partial(this.Create());
+        }
+    }
+}


Added: class/Crimson.OpenSsl/Tests/SHA1OpenSslTests.cs
===================================================================
@@ -0,0 +1,43 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Security.Cryptography;
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+	[TestFixture]
+	public class SHA1OpenSslTests : SHA1Test
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			hash = new SHA1OpenSsl ();
+		}
+	}
+}


Added: class/Crimson.OpenSsl/Tests/SHA256OpenSslTests.cs
===================================================================
@@ -0,0 +1,43 @@
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Security.Cryptography;
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+using NUnit.Framework;
+
+namespace Crimson.Test.OpenSsl
+{
+	[TestFixture]
+	public class SHA256OpenSslTests : SHA256Test
+	{
+		[SetUp]
+		protected void SetUp ()
+		{
+			hash = new SHA256OpenSsl ();
+		}
+	}
+}


Added: class/Crimson.OpenSsl/tools/generator.cs
===================================================================
@@ -0,0 +1,241 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+class Program {
+
+	static void GenerateHash (string name)
+	{
+		string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// 'Software'), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Security.Cryptography;
+using Crimson.OpenSsl;
+
+namespace Crimson.Security.Cryptography {
+
+	public class {0}OpenSsl : {0} {
+
+        private HashHelper helper;
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && helper != null)
+            {
+                helper.Dispose();
+                helper = null;
+            }
+            base.Dispose(disposing);
+        }
+
+        public override void Initialize()
+        {
+            helper = new HashHelper(Native.EVP_{1}(), this.HashSize);
+        }
+
+        protected override void HashCore(byte[] data, int start, int length)
+        {
+            if (this.helper == null)
+            {
+                this.Initialize();
+            }
+
+            helper.Update(data, start, length);
+        }
+
+        protected override byte[] HashFinal()
+        {
+            if (this.helper == null)
+            {
+                this.Initialize();
+            }
+
+            return helper.Final();
+        }
+	}
+}";
+		string filename = Path.Combine (OutputDirectory,
+			String.Format ("{0}OpenSsl.g.cs", name));
+		string content = template.Replace ("{0}", name).
+			Replace ("{1}", name.ToLowerInvariant ());
+		File.WriteAllText (filename, content);
+	}
+
+	static void GenerateSymmetricAlgorithm (string name, string fallback)
+	{
+		string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author: 
+//	Bassam Tabbara  <[email protected]>
+// 
+// Copyright 2013 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// 'Software'), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Security.Cryptography;
+using Crimson.OpenSsl;
+
+namespace Crimson.Security.Cryptography {
+
+	public class {0}OpenSsl : {0} {
+		
+        public static RandomNumberGenerator Rng = RandomNumberGenerator.Create();
+
+        public override void GenerateIV()
+        {
+            IVValue = new byte[BlockSizeValue >> 3];
+            Rng.GetBytes(IVValue);
+        }
+
+        public override void GenerateKey()
+        {
+            KeyValue = new byte[KeySizeValue >> 3];
+            Rng.GetBytes(KeyValue);
+        }
+
+        public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
+        {
+            try
+            {
+                if (BlockSize == 128)
+                {
+                    return new OpenSslCryptoTransform(this, false, rgbKey, rgbIV);
+                }
+            }
+            catch (CryptographicException)
+            {
+            }
+
+            using (var r = this.Fallback())
+            {
+                return r.CreateDecryptor(rgbKey, rgbIV);
+            }
+        }
+
+        public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)
+        {
+            try
+            {
+                if (BlockSize == 128)
+                {
+                    return new OpenSslCryptoTransform(this, true, rgbKey, rgbIV);
+                }
+            }
+            catch (CryptographicException)
+            {
+            }
+
+            using (var r = this.Fallback())
+            {
+                return r.CreateEncryptor(rgbKey, rgbIV);
+            }
+        }
+
+		private {1} Fallback ()
+		{
+			{1} r = new {1} ();
+			r.Mode = Mode;
+			r.Padding = Padding;
+			r.BlockSize = BlockSize;
+			return r;
+		}
+	}
+}";
+		string filename = Path.Combine (OutputDirectory, String.Format ("{0}OpenSsl.g.cs", name));
+		string content = template.Replace ("{0}", name).Replace ("{1}", fallback);
+		File.WriteAllText (filename, content);
+	}
+
+	static string OutputDirectory { get; set; }
+
+	static void Main (string[] args)
+	{
+		OutputDirectory = args.Length == 0 ? "." : args [0];
+
+		System.IO.Directory.CreateDirectory (OutputDirectory);
+
+		GenerateHash ("SHA1");		// CRYPTO_SHA1
+		GenerateHash ("SHA256");	// CRYPTO_SHA256
+#if UNTESTED
+		GenerateHash ("MD5");		// CRYPTO_MD5
+		GenerateHash ("RIPEMD160");	// CRYPTO_RIPEMD160
+		GenerateHash ("SHA384");	// CRYPTO_SHA2_384
+		GenerateHash ("SHA512");	// CRYPTO_SHA2_512
+#endif
+		GenerateSymmetricAlgorithm ("Rijndael", "RijndaelManaged");
+		GenerateSymmetricAlgorithm ("Aes", "RijndaelManaged");
+#if UNTESTED
+		GenerateSymmetricAlgorithm ("Des", "DESCryptoServiceProvider", null, "DES_CBC");
+		GenerateSymmetricAlgorithm ("TripleDes", "TripleDESCryptoServiceProvider", null, "3DES_CBC");
+		// BLF (Blowfish), CAST, SKIPJACK and Camellia are not part of the .NET framework 
+		// and would require a additional base classes and fallbacks
+#endif
+	}
+}

Added: class/Crimson.OpenSsl/tools/torture.cs
===================================================================
@@ -0,0 +1,256 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2012 Symform Inc.
+// 
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Crimson.Security.Cryptography;
+
+class Program {
+
+	static bool verbose;
+
+	static byte[] sha_a_input = Encoding.Default.GetBytes ("abc");
+	static byte[] sha_b_input = Encoding.Default.GetBytes ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+	static byte[] sha_c_input;
+
+	static Program ()
+	{
+		sha_c_input = new byte [1000000];
+		for (int i = 0; i < 1000000; i++)
+			sha_c_input[i] = 0x61; // a
+	}
+
+	static void Main (string [] args)
+	{
+		verbose = args.Length > 0;
+
+		Parallel.Invoke (
+			() => { SHA1a ();	},
+			() => { SHA1b ();	},
+			() => { SHA1c ();	},
+			() => { SHA256a ();	},
+			() => { SHA256b ();	},
+			() => { SHA256c ();	},
+			() => { AESa ();	},
+			() => { AESb ();	},
+			() => { AESc ();	},
+			() => { AESd ();	}
+		);
+		Console.WriteLine ("End");
+        }
+
+	static void SHA1 (string name, int max, byte[] input, byte[] output)
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (SHA1 digest = new SHA1OpenSsl ()) {
+					if (!Compare (output, digest.ComputeHash (input)))
+						throw new Exception (name + " " + i.ToString ());
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+	static byte[] sha1_a_output = new byte [] {
+		0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, 0xba, 0x3e, 
+		0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, 0x9c, 0xd0, 0xd8, 0x9d };
+
+	static void SHA1a ()
+	{
+		SHA1 ("SHA1a", 10000, sha_a_input, sha1_a_output);
+	}
+
+	static byte[] sha1_b_output = new byte [] {
+		0x84, 0x98, 0x3e, 0x44, 0x1c, 0x3b, 0xd2, 0x6e, 0xba, 0xae, 
+		0x4a, 0xa1, 0xf9, 0x51, 0x29, 0xe5, 0xe5, 0x46, 0x70, 0xf1 };
+
+	static void SHA1b ()
+	{
+		SHA1 ("SHA1b", 5000, sha_b_input, sha1_b_output);
+	}
+
+	static byte[] sha1_c_output = new byte [] {
+		0x34, 0xaa, 0x97, 0x3c, 0xd4, 0xc4, 0xda, 0xa4, 0xf6, 0x1e, 
+		0xeb, 0x2b, 0xdb, 0xad, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6f };
+
+	static void SHA1c ()
+	{
+		SHA1 ("SHA1c", 2000, sha_c_input, sha1_c_output);
+	}
+
+	static void SHA256 (string name, int max, byte[] input, byte[] output)
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (SHA256 digest = new SHA256OpenSsl ()) {
+					if (!Compare (output, digest.ComputeHash (input)))
+						throw new Exception (name + " " + i.ToString ());
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+	static byte[] sha256_a_output = new byte [] {
+		0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 
+		0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 
+		0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 
+		0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad };
+
+	static void SHA256a ()
+	{
+		SHA256 ("SHA256a", 8000, sha_a_input, sha256_a_output);
+	}
+
+	static byte[] sha256_b_output = new byte [] {
+		0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 
+		0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 
+		0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 
+		0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 };
+
+	static void SHA256b ()
+	{
+		SHA256 ("SHA256b", 4000, sha_b_input, sha256_b_output);
+	}
+
+	static byte[] sha256_c_output = new byte [] {
+		0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 
+		0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 
+		0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 
+		0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 };
+
+	static void SHA256c ()
+	{
+		SHA256 ("SHA256c", 2000, sha_c_input, sha256_c_output);
+	}
+
+	static void Process (string name, int iteration, int max)
+	{
+		if (!verbose)
+			return;
+		if (iteration % 1000 == 0)
+			Console.WriteLine ("{0} {1}/{2} ({3})", name, iteration, max, Thread.CurrentThread.ManagedThreadId);
+	}
+
+	static byte[] aes_iv = new byte [16];
+
+	static void AES (string name, int max, byte[] key, byte[] input, byte[] expected) 
+	{
+		int i = 0;
+		try {
+			for (; i < max; i++) {
+				using (Aes cipher = new AesOpenSsl ()) {
+					cipher.Mode = CipherMode.ECB;
+					cipher.KeySize = key.Length * 8;
+					cipher.Padding = PaddingMode.Zeros;
+
+					byte[] output = new byte [input.Length];
+					ICryptoTransform encryptor = cipher.CreateEncryptor (key, aes_iv);
+					encryptor.TransformBlock (input, 0, input.Length, output, 0);
+					if (!Compare (output, expected))
+						throw new Exception ("encryptor");
+	
+					byte[] original = new byte [output.Length];
+					ICryptoTransform decryptor = cipher.CreateDecryptor (key, aes_iv); 
+					decryptor.TransformBlock (output, 0, output.Length, original, 0);
+					if (!Compare (original, input))
+						throw new Exception ("decryptor");
+				}
+				Process (name, i, max);
+			}
+		}
+		catch (Exception e) {
+			Console.WriteLine ("{0} #{1} : {2}", name, i, e);
+		}
+	}
+
+
+	static byte[] aes_a_key = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
+	static byte[] aes_a_input = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
+	static byte[] aes_a_expected = { 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32 };
+
+	static void AESa () 
+	{
+		AES ("AESa", 4000, aes_a_key, aes_a_input, aes_a_expected);
+	}
+
+	static byte[] aes_b_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+	static byte[] aes_b_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_b_expected = { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a };
+
+	static void AESb () 
+	{
+		AES ("AESb", 4000, aes_b_key, aes_b_input, aes_b_expected);
+	}
+
+	static byte[] aes_c_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+	static byte[] aes_c_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_c_expected = { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 };
+
+	static void AESc () 
+	{
+		AES ("AESc", 3000, aes_c_key, aes_c_input, aes_c_expected);
+	}
+
+	static byte[] aes_d_key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+	static byte[] aes_d_input = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+	static byte[] aes_d_expected = { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 };
+
+	static void AESd () 
+	{
+		AES ("AESc", 2000, aes_d_key, aes_d_input, aes_d_expected);
+	}
+
+	static bool Compare (byte[] actual, byte[] expected)
+	{
+		if (actual == null)
+			return (expected == null);
+		if (expected == null)
+			return false;
+		if (actual.Length != expected.Length)
+			return false;
+		for (int i=0; i < actual.Length; i++) {
+			if (actual [i] != expected [i])
+				return false;
+		}
+		return true;
+	}
+}

Modified: class/README
===================================================================
@@ -6,6 +6,11 @@ The following assemblies are available in Crimson:
 	algorithm implementations, either native or hardware accelerated.
 	Ref: http://home.gna.org/cryptodev-linux/
 
+* Crimson.OpenSsl.dll
+
+	This assembly provides a wrapper around libcrypto.
+	Ref: http://www.openssl.org/
+	
 * Crimson.MHash.dll
 
 	This assembly provides wrapper around the native hash implementations 

Added: common/CryptoTransformBase.cs
===================================================================
@@ -0,0 +1,407 @@
+//
+// Author: 
+//	Sebastien Pouliot  <[email protected]>
+// 
+// Copyright 2012 Symform Inc.
+//
+// This code is based on:
+
+//
+// Mono.Security.Cryptography.SymmetricTransform implementation
+//
+// Authors:
+//	Thomas Neidhart ([email protected])
+//	Sebastien Pouliot <[email protected]>
+//
+// Portions (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security.Cryptography;
+
+namespace Crimson.Common
+{
+    public abstract class CryptoTransformBase : ICryptoTransform
+    {
+        byte[] workBuff;
+        bool lastBlock;
+        PaddingMode padding;
+
+        protected bool encrypt;
+        protected int BlockSizeByte;
+        protected byte[] iv;
+
+        public CryptoTransformBase(SymmetricAlgorithm algo, bool encryption, byte[] rgbKey, byte[] rgbIV)
+        {
+            if (rgbKey == null)
+                throw new CryptographicException("Invalid (null) key");
+
+            BlockSizeByte = (algo.BlockSize >> 3);
+
+            if (rgbIV == null)
+            {
+                iv = new byte[BlockSizeByte];
+                this.Random(iv, 0, BlockSizeByte);
+            }
+            else
+            {
+                // 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);
+                }
+                iv = (byte[])rgbIV.Clone();
+            }
+
+            encrypt = encryption;
+            padding = algo.Padding;
+
+            // transform buffer
+            workBuff = new byte[BlockSizeByte];
+        }
+
+        ~CryptoTransformBase()
+        {
+            Dispose(false);
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+        }
+
+        public virtual bool CanTransformMultipleBlocks
+        {
+            get { return true; }
+        }
+
+        public virtual bool CanReuseTransform
+        {
+            get { return false; }
+        }
+
+        public virtual int InputBlockSize
+        {
+            get { return BlockSizeByte; }
+        }
+
+        public virtual int OutputBlockSize
+        {
+            get { return BlockSizeByte; }
+        }
+
+        protected abstract void Transform(byte[] input, int inputOffset, byte[] output, int outputOffset, int length);
+
+        private void CheckInput(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            if (inputBuffer == null)
+                throw new ArgumentNullException("inputBuffer");
+            if (inputOffset < 0)
+                throw new ArgumentOutOfRangeException("inputOffset", "< 0");
+            if (inputCount < 0)
+                throw new ArgumentOutOfRangeException("inputCount", "< 0");
+            // ordered to avoid possible integer overflow
+            if (inputOffset > inputBuffer.Length - inputCount)
+                throw new ArgumentException("inputBuffer", Locale.GetText("Overflow"));
+        }
+
+        // this method may get called MANY times so this is the one to optimize
+        public virtual int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+        {
+            CheckInput(inputBuffer, inputOffset, inputCount);
+            // check output parameters
+            if (outputBuffer == null)
+                throw new ArgumentNullException("outputBuffer");
+            if (outputOffset < 0)
+                throw new ArgumentOutOfRangeException("outputOffset", "< 0");
+
+            // ordered to avoid possible integer overflow
+            int len = outputBuffer.Length - inputCount - outputOffset;
+            if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros)))
+            {
+                throw new CryptographicException("outputBuffer", Locale.GetText("Overflow"));
+            }
+            else if (KeepLastBlock)
+            {
+                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) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
+            }
+        }
+
+        private int InternalTransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+        {
+            int offs = inputOffset;
+            int full;
+
+            // this way we don't do a modulo every time we're called
+            // and we may save a division
+            if (inputCount != BlockSizeByte)
+            {
+                if ((inputCount % BlockSizeByte) != 0)
+                    throw new CryptographicException("Invalid input block size.");
+
+                full = inputCount / BlockSizeByte;
+            }
+            else
+                full = 1;
+
+            if (KeepLastBlock)
+                full--;
+
+            int total = 0;
+
+            if (lastBlock)
+            {
+                Transform(workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
+                outputOffset += BlockSizeByte;
+                total += BlockSizeByte;
+                lastBlock = false;
+            }
+
+            if (full > 0)
+            {
+                int length = full * BlockSizeByte;
+                Transform(inputBuffer, offs, outputBuffer, outputOffset, length);
+                offs += length;
+                outputOffset += length;
+                total += length;
+            }
+
+            if (KeepLastBlock)
+            {
+                Buffer.BlockCopy(inputBuffer, offs, workBuff, 0, BlockSizeByte);
+                lastBlock = true;
+            }
+
+            return total;
+        }
+
+        RandomNumberGenerator _rng;
+
+        private void Random(byte[] buffer, int start, int length)
+        {
+            if (_rng == null)
+            {
+                _rng = RandomNumberGenerator.Create();
+            }
+            byte[] random = new byte[length];
+            _rng.GetBytes(random);
+            Buffer.BlockCopy(random, 0, buffer, start, length);
+        }
+
+        private void ThrowBadPaddingException(PaddingMode padding, int length, int position)
+        {
+            string msg = String.Format(Locale.GetText("Bad {0} padding."), padding);
+            if (length >= 0)
+                msg += String.Format(Locale.GetText(" Invalid length {0}."), length);
+            if (position >= 0)
+                msg += String.Format(Locale.GetText(" Error found at position {0}."), position);
+            throw new CryptographicException(msg);
+        }
+
+        private byte[] FinalEncrypt(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            // are there still full block to process ?
+            int full = (inputCount / BlockSizeByte) * BlockSizeByte;
+            int rem = inputCount - full;
+            int total = full;
+
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                case PaddingMode.ISO10126:
+                case PaddingMode.PKCS7:
+                    // we need to add an extra block for padding
+                    total += BlockSizeByte;
+                    break;
+                default:
+                    if (inputCount == 0)
+                        return new byte[0];
+                    if (rem != 0)
+                    {
+                        if (padding == PaddingMode.None)
+                            throw new CryptographicException("invalid block length");
+                        // zero padding the input (by adding a block for the partial data)
+                        byte[] paddedInput = new byte[full + BlockSizeByte];
+                        Buffer.BlockCopy(inputBuffer, inputOffset, paddedInput, 0, inputCount);
+                        inputBuffer = paddedInput;
+                        inputOffset = 0;
+                        inputCount = paddedInput.Length;
+                        total = inputCount;
+                    }
+                    break;
+            }
+
+            byte[] res = new byte[total];
+            int outputOffset = 0;
+
+            // process all blocks except the last (final) block
+            if (total > BlockSizeByte)
+            {
+                outputOffset = InternalTransformBlock(inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
+                inputOffset += outputOffset;
+            }
+
+            // now we only have a single last block to encrypt
+            byte pad = (byte)(BlockSizeByte - rem);
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                    // XX 00 00 00 00 00 00 07 (zero + padding length)
+                    res[res.Length - 1] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                case PaddingMode.ISO10126:
+                    // XX 3F 52 2A 81 AB F7 07 (random + padding length)
+                    Random(res, res.Length - pad, pad - 1);
+                    res[res.Length - 1] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                case PaddingMode.PKCS7:
+                    // XX 07 07 07 07 07 07 07 (padding length)
+                    for (int i = res.Length; --i >= (res.Length - pad); )
+                        res[i] = pad;
+                    Buffer.BlockCopy(inputBuffer, inputOffset, res, full, rem);
+                    // the last padded block will be transformed in-place
+                    InternalTransformBlock(res, full, BlockSizeByte, res, full);
+                    break;
+                default:
+                    InternalTransformBlock(inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
+                    break;
+            }
+            return res;
+        }
+
+        private byte[] FinalDecrypt(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            if ((inputCount % BlockSizeByte) > 0)
+                throw new CryptographicException("Invalid input block size.");
+
+            int total = inputCount;
+            if (lastBlock)
+                total += BlockSizeByte;
+
+            byte[] res = new byte[total];
+            int outputOffset = 0;
+
+            if (inputCount > 0)
+                outputOffset = InternalTransformBlock(inputBuffer, inputOffset, inputCount, res, 0);
+
+            if (lastBlock)
+            {
+                Transform(workBuff, 0, res, outputOffset, BlockSizeByte);
+                outputOffset += BlockSizeByte;
+                lastBlock = false;
+            }
+
+            // total may be 0 (e.g. PaddingMode.None)
+            byte pad = ((total > 0) ? res[total - 1] : (byte)0);
+            switch (padding)
+            {
+                case PaddingMode.ANSIX923:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    for (int i = pad - 1; i > 0; i--)
+                    {
+                        if (res[total - 1 - i] != 0x00)
+                            ThrowBadPaddingException(padding, -1, i);
+                    }
+                    total -= pad;
+                    break;
+                case PaddingMode.ISO10126:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    total -= pad;
+                    break;
+                case PaddingMode.PKCS7:
+                    if ((pad == 0) || (pad > BlockSizeByte))
+                        ThrowBadPaddingException(padding, pad, -1);
+                    for (int i = pad - 1; i > 0; i--)
+                    {
+                        if (res[total - 1 - i] != pad)
+                            ThrowBadPaddingException(padding, -1, i);
+                    }
+                    total -= pad;
+                    break;
+                case PaddingMode.None:	// nothing to do - it's a multiple of block size
+                case PaddingMode.Zeros:	// nothing to do - user must unpad himself
+                    break;
+            }
+
+            // return output without padding
+            if (total > 0)
+            {
+                byte[] data = new byte[total];
+                Buffer.BlockCopy(res, 0, data, 0, total);
+                // zeroize decrypted data (copy with padding)
+                Array.Clear(res, 0, res.Length);
+                return data;
+            }
+            else
+                return new byte[0];
+        }
+
+        public virtual byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
+        {
+            CheckInput(inputBuffer, inputOffset, inputCount);
+
+            if (encrypt)
+                return FinalEncrypt(inputBuffer, inputOffset, inputCount);
+            else
+                return FinalDecrypt(inputBuffer, inputOffset, inputCount);
+        }
+    }
+}
\ No newline at end of file

Modified: tests/HashAlgorithmTest.cs
===================================================================
@@ -36,7 +36,7 @@
 
 namespace Crimson.Test.Base {
 
-	public class HashAlgorithmTest {
+	public abstract class HashAlgorithmTest {
 	
 		protected HashAlgorithm hash;
 	

Modified: tests/SHA1Test.cs
===================================================================
@@ -21,7 +21,7 @@ namespace Crimson.Test.Base {
 // a.	FIPS PUB 180-1: Secure Hash Standard
 //	http://csrc.nist.gov/publications/fips/fips180-1/fip180-1.txt
 
-	public class SHA1Test : HashAlgorithmTest {
+	public abstract class SHA1Test : HashAlgorithmTest {
 	
 		// test vectors from NIST FIPS 186-2
 	

Modified: tests/SHA256Test.cs
===================================================================
@@ -21,7 +21,7 @@ namespace Crimson.Test.Base {
 // a.	FIPS PUB 180-2: Secure Hash Standard
 //	http://csrc.nist.gov/publications/fips/fips180-2/fip180-2.txt
 
-	public class SHA256Test : HashAlgorithmTest {
+	public abstract class SHA256Test : HashAlgorithmTest {
 	
 		// test vectors from NIST FIPS 186-2
 	

Modified: tests/SymmetricAlgorithmTest.cs
===================================================================
@@ -5,7 +5,7 @@
 
 namespace Crimson.Test.Base {
 
-	public class SymmetricAlgorithmTest {
+	public abstract class SymmetricAlgorithmTest {
 	
 		protected SymmetricAlgorithm algo;
 
_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.