Permalink
Browse files

Push CryptoDev wrapper to github

  • Loading branch information...
1 parent 6fa8937 commit 1e27ce66673d38d19be658ee8947555432323a6a @spouliot spouliot committed Feb 16, 2012
View
5 class/Crimson.CryptoDev/.gitignore
@@ -0,0 +1,5 @@
+*.dll*
+Crimson.Security.Cryptography/
+CryptoTools.cs
+SymmetricTransform.cs
+TestResult.xml
View
1 class/Crimson.CryptoDev/AUTHORS
@@ -0,0 +1 @@
+Sebastien Pouliot <sebastien.pouliot@gmail.com>
View
95 class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDev.cs
@@ -0,0 +1,95 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+namespace Crimson.CryptoDev {
+
+ // from cryptodev.h
+
+ // CRYPTO_*
+ enum Cipher : uint {
+ SHA1 = 14,
+ SHA256 = 103,
+ // ciphers
+ AES_CBC = 11,
+ AES_ECB = 23
+ }
+
+ // session_op
+ struct Session {
+ public Cipher cipher;
+ public Cipher mac;
+ public uint keylen;
+ public IntPtr key; // 32/64 bits size diff
+ public uint mackeylen;
+ public IntPtr mackey; // 32/64 bits size diff
+ public uint ses;
+#if DEBUG
+ public override string ToString ()
+ {
+ return String.Format ("{0} {1} {2} {3} {4} {5} {6}",
+ cipher, mac, keylen, key, mackeylen, mackey, ses);
+ }
+#endif
+ }
+
+ // COP_*
+ enum CryptoOperation : ushort {
+ Encrypt, // 0
+ Decrypt // 1
+ }
+
+ // COP_FLAG_*
+ [Flags]
+ enum CryptoFlags : ushort {
+ None = 0,
+ Update = 1,
+ Final = 2,
+ WriteIv = 4
+ }
+
+ // crypt_op
+ struct Crypt {
+ public uint ses;
+ public CryptoOperation op;
+ public CryptoFlags flags;
+ public uint len;
+ public IntPtr src; // 32/64 bits size diff
+ public IntPtr dst; // 32/64 bits size diff
+ public IntPtr mac; // 32/64 bits size diff
+ public IntPtr iv; // 32/64 bits size diff
+#if DEBUG
+ public override string ToString ()
+ {
+ return String.Format ("{0} {1} {2} {3} {4} {5} {6} {7}",
+ ses, op, flags, len, src, dst, mac, iv);
+ }
+#endif
+ }
+}
View
448 class/Crimson.CryptoDev/Crimson.CryptoDev/CryptoDevTransform.cs
@@ -0,0 +1,448 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// Copyright 2012 Symform Inc.
+//
+// This code is based on:
+
+//
+// Mono.Security.Cryptography.SymmetricTransform implementation
+//
+// Authors:
+// Thomas Neidhart (tome@sbox.tugraz.at)
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// 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.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+using Mono.Security.Cryptography;
+
+namespace Crimson.CryptoDev {
+
+ unsafe class CryptoDevTransform : ICryptoTransform {
+ bool encrypt;
+ int BlockSizeByte;
+ byte[] workBuff;
+ bool lastBlock;
+ Crypt context;
+ PaddingMode padding;
+ byte[] iv;
+ byte[] save_iv;
+
+ public CryptoDevTransform (SymmetricAlgorithm algo, Cipher cipher, bool encryption, byte[] rgbKey, byte[] rgbIV, int bufferBlockSize)
+ {
+ if (!Helper.CryptoDevAvailable)
+ throw new CryptographicException ("Cannot access /dev/crypto");
+
+ 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;
+ sess.keylen = (uint) rgbKey.Length;
+ fixed (byte* k = &rgbKey [0])
+ sess.key = (IntPtr) k;
+
+ if (Helper.SessionOp (ref sess) < 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+
+ context.ses = sess.ses;
+ context.op = encryption ? CryptoOperation.Encrypt : CryptoOperation.Decrypt;
+ if (algo.Mode != CipherMode.ECB) {
+ iv = rgbIV;
+ save_iv = new byte [BlockSizeByte];
+ fixed (byte* i = &iv [0])
+ context.iv = (IntPtr) i;
+ }
+
+ // 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)
+ {
+ if (context.ses != 0) {
+ Helper.CloseSession (ref context.ses);
+ GC.SuppressFinalize (this);
+ }
+ }
+
+ public int BufferBlockSize {
+ 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)
+ {
+ while (length > 0) {
+ int size = Math.Min (length, BufferBlockSize);
+ if (iv != null) {
+ fixed (byte *i = &iv [0])
+ context.iv = (IntPtr) i;
+
+ if (!encrypt)
+ Buffer.BlockCopy (input, length - BlockSizeByte, save_iv, 0, BlockSizeByte);
+ }
+
+ fixed (byte *i = &input [inputOffset])
+ fixed (byte *o = &output [outputOffset]) {
+ context.len = (uint) size;
+ context.src = (IntPtr) i;
+ context.dst = (IntPtr) o;
+ }
+
+ if (Helper.CryptOp (ref context) < 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+
+ if (iv != null) {
+ if (encrypt)
+ Buffer.BlockCopy (output, outputOffset + size - BlockSizeByte, iv, 0, BlockSizeByte);
+ else
+ Buffer.BlockCopy (save_iv, 0, iv, 0, BlockSizeByte);
+ }
+
+ length -= size;
+ inputOffset += size;
+ 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
+ while (total > BlockSizeByte) {
+ InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
+ inputOffset += BlockSizeByte;
+ outputOffset += BlockSizeByte;
+ total -= BlockSizeByte;
+ }
+
+ // 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;
+
+ while (inputCount > 0) {
+ int len = InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
+ inputOffset += BlockSizeByte;
+ outputOffset += len;
+ inputCount -= BlockSizeByte;
+ }
+
+ 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 -= padding;
+ break;
+ case PaddingMode.ISO10126:
+ if ((pad == 0) || (pad > BlockSizeByte))
+ ThrowBadPaddingException (padding, pad, -1);
+ total -= padding;
+ 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 -= padding;
+ 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);
+ }
+ }
+}
View
104 class/Crimson.CryptoDev/Crimson.CryptoDev/HashHelper.cs
@@ -0,0 +1,104 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+namespace Crimson.CryptoDev {
+
+ unsafe class HashHelper : IDisposable {
+
+ Crypt context;
+
+ public HashHelper (Cipher algo)
+ {
+ if (!Helper.CryptoDevAvailable)
+ throw new CryptographicException ("Cannot access /dev/crypto");
+
+ // linux does not requires cloning the file descriptor with CRIOGET
+ Session sess = new Session ();
+ sess.mac = algo;
+
+ if (Helper.SessionOp (ref sess) < 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+
+ context.ses = sess.ses;
+ context.op = CryptoOperation.Encrypt;
+ // change this value if the driver (e.g. mv_cesa) has a limit that
+ // it can process in a single shot (e.g. 1932 for SHA1)
+ BufferBlockSize = Int32.MaxValue;
+ }
+
+ ~HashHelper ()
+ {
+ Dispose ();
+ }
+
+ public int BufferBlockSize {
+ get; set;
+ }
+
+ public void Dispose ()
+ {
+ if (context.ses != 0) {
+ Helper.CloseSession (ref context.ses);
+ GC.SuppressFinalize (this);
+ }
+ }
+
+ public void Update (byte[] data, int start, int length)
+ {
+ while (length > 0) {
+ int size = Math.Min (length, BufferBlockSize);
+ fixed (byte* p = &data [start]) {
+ context.len = (uint) size;
+ context.src = (IntPtr) p;
+ context.flags = CryptoFlags.Update;
+ }
+ if (Helper.CryptOp (ref context) < 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+ length -= size;
+ start += size;
+ }
+ }
+
+ public byte[] Final (int hashSize)
+ {
+ byte[] digest = new byte [hashSize];
+ fixed (byte* p = &digest [0]) {
+ context.len = 0;
+ context.src = IntPtr.Zero;
+ context.mac = (IntPtr) p;
+ }
+ if (Helper.CryptOp (ref context) < 0)
+ throw new CryptographicException (Marshal.GetLastWin32Error ());
+
+ context.mac = IntPtr.Zero;
+ return digest;
+ }
+ }
+}
View
101 class/Crimson.CryptoDev/Crimson.CryptoDev/Helper.cs
@@ -0,0 +1,101 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Runtime.InteropServices;
+using System.Security.Cryptography;
+
+namespace Crimson.CryptoDev {
+
+ // hide platform differences, e.g. 32/64 bits
+ static unsafe class Helper {
+
+ // shared file descriptor
+ static int fildes = Helper.open ("/dev/crypto", 2 /* O_RDWR */);
+
+ static public bool CryptoDevAvailable {
+ get { return (fildes != -1); }
+ }
+
+ // size will vary for 32/64 bits
+ static ulong CIOCGSESSION = Ioctl.IOWR ('c', 102, sizeof (Session));
+ static ulong CIOCFSESSION = Ioctl.IOW ('c', 103, sizeof (UInt32));
+ static ulong CIOCCRYPT = Ioctl.IOWR ('c', 104, sizeof (Crypt));
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="open")]
+ static public extern int open (string path, int oflag);
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl32 (int fd, int request, ref int fdc);
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl64 (int fd, ulong request, ref int fdc);
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl32 (int fdc, int request, ref Session session);
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl64 (int fdc, ulong request, ref Session session);
+
+ static public int SessionOp (ref Session session)
+ {
+ if (IntPtr.Size == 4)
+ return ioctl32 (fildes, (int) CIOCGSESSION, ref session);
+ else
+ return ioctl64 (fildes, CIOCGSESSION, ref session);
+ }
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl32 (int fdc, int request, ref UInt32 session);
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl64 (int fdc, ulong request, ref UInt32 session);
+
+ static public int CloseSession (ref UInt32 session)
+ {
+ int result = -1;
+ if (IntPtr.Size == 4)
+ result = ioctl32 (fildes, (int) CIOCFSESSION, ref session);
+ else
+ result = ioctl64 (fildes, CIOCFSESSION, ref session);
+ session = 0;
+ return result;
+ }
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="close")]
+ static public extern int close (int filedes);
+
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl32 (int fd, int request, ref Crypt crypt);
+ [DllImport ("libc", SetLastError=true, EntryPoint="ioctl")]
+ static extern int ioctl64 (int fd, ulong request, ref Crypt crypt);
+
+ static public int CryptOp (ref Crypt crypt)
+ {
+ if (IntPtr.Size == 4)
+ return ioctl32 (fildes, (int) CIOCCRYPT, ref crypt);
+ else
+ return ioctl64 (fildes, CIOCCRYPT, ref crypt);
+ }
+ }
+}
View
80 class/Crimson.CryptoDev/Crimson.CryptoDev/Ioctl.cs
@@ -0,0 +1,80 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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;
+
+namespace Crimson.CryptoDev {
+
+ // from ioctl.h
+
+ class Ioctl {
+
+ const ulong IOC_READ = 2;
+ const ulong IOC_WRITE = 1;
+
+ const int IOC_NRBITS = 8;
+ const int IOC_TYPEBITS = 8;
+ const int IOC_SIZEBITS = 14;
+ const int IOC_DIRBITS = 2;
+
+ const ulong IOC_NRMASK = (((ulong)1 << IOC_NRBITS)-1);
+ const ulong IOC_TYPEMASK = (((ulong)1 << IOC_TYPEBITS)-1);
+ const ulong IOC_SIZEMASK = (((ulong)1 << IOC_SIZEBITS)-1);
+ const ulong IOC_DIRMASK = (((ulong)1 << IOC_DIRBITS)-1);
+
+ const int IOC_NRSHIFT = 0;
+ const int IOC_TYPESHIFT = (IOC_NRSHIFT + IOC_NRBITS);
+ const int IOC_SIZESHIFT = (IOC_TYPESHIFT + IOC_TYPEBITS);
+ const int IOC_DIRSHIFT = (IOC_SIZESHIFT + IOC_SIZEBITS);
+
+ static ulong IOC (ulong dir, ulong type, ulong nr, ulong size)
+ {
+ return (((dir) << IOC_DIRSHIFT) |
+ ((type) << IOC_TYPESHIFT) |
+ ((nr) << IOC_NRSHIFT) |
+ ((size) << IOC_SIZESHIFT));
+ }
+
+ static public ulong IOWR (ulong type, ulong nr, int size)
+ {
+ return IOC (IOC_READ | IOC_WRITE, type, nr, (ulong) size);
+ }
+
+ static public ulong IOW (ulong type, ulong nr, int size)
+ {
+ return IOC (IOC_WRITE, type, nr, (ulong) size);
+ }
+#if TEST
+ static unsafe void Main ()
+ {
+ // IOWR('c', 102, struct session_op)
+ Console.WriteLine ("CIOCGSESSION = {0}", IOWR ('c', 102, sizeof (Session)));
+ Console.WriteLine ("CIOCFSESSION = {0}", IOW ('c', 103, sizeof (System.UInt32)));
+ Console.WriteLine ("CIOCCRYPT = {0}", IOWR ('c', 104, sizeof (Crypt)));
+ }
+#endif
+ }
+}
View
20 class/Crimson.CryptoDev/LICENSE
@@ -0,0 +1,20 @@
+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.
View
66 class/Crimson.CryptoDev/Makefile
@@ -0,0 +1,66 @@
+CSC=gmcs
+
+SOURCES = \
+ Crimson.CryptoDev/CryptoDev.cs \
+ Crimson.CryptoDev/CryptoDevTransform.cs \
+ Crimson.CryptoDev/Ioctl.cs \
+ Crimson.CryptoDev/HashHelper.cs \
+ Crimson.CryptoDev/Helper.cs \
+ Crimson.Security.Cryptography/RijndaelKernel.cs \
+ CryptoTools.cs \
+ ../../common/Locale.cs
+
+all: Crimson.CryptoDev.dll
+
+CryptoTools.cs:
+ wget https://raw.github.com/mono/mono/master/mcs/class/corlib/Mono.Security.Cryptography/CryptoTools.cs
+
+GENERATED_SOURCES = \
+ Crimson.Security.Cryptography/AesKernel.g.cs \
+ Crimson.Security.Cryptography/SHA1Kernel.g.cs \
+ Crimson.Security.Cryptography/SHA256Kernel.g.cs
+
+tools/generator.exe: tools/generator.cs
+ $(CSC) -t:exe -out:$@ $^
+
+$(GENERATED_SOURCES): tools/generator.exe
+ mono tools/generator.exe Crimson.Security.Cryptography
+
+Crimson.CryptoDev.dll: $(SOURCES) $(GENERATED_SOURCES)
+ $(CSC) -debug $(SOURCES) $(GENERATED_SOURCES) -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
+
+torture: torture.exe
+ mono --debug torture.exe -v
+
+clean:
+ rm -f torture.exe
+ rm -f tools/generator.exe
+ rm -f $(GENERATED_SOURCES) CryptoTools.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/AesKernelTest.cs \
+ Tests/CryptoDevTest.cs \
+ Tests/RijndaelKernelTest.cs \
+ Tests/SHA1KernelTest.cs \
+ Tests/SHA256KernelTest.cs \
+
+Crimson.CryptoDev.Tests.dll: $(BASE_TESTS) $(GENERATED_TESTS) Crimson.CryptoDev.dll
+ mcs -debug $(BASE_TESTS) $(GENERATED_TESTS) -t:library -out:$@ -r:Crimson.CryptoDev.dll -pkg:mono-nunit
+
+test: Crimson.CryptoDev.Tests.dll
+
+run-test: test
+ nunit-console Crimson.CryptoDev.Tests.dll
+
View
42 class/Crimson.CryptoDev/README
@@ -0,0 +1,42 @@
+This assembly goal is to provide a managed wrapper on to of /dev/crypto
+known as `cryptodev`.
+
+References:
+* http://home.gna.org/cryptodev-linux/
+
+
+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).
+
+Generated code for symmetric ciphers (e.g. AES) will, by default, contain:
+
+ const int BufferBlockSize = Int32.MaxValue;
+
+and this can be changed to:
+
+ const int BufferBlockSize = 1936; // mv_cesa limit
+
+Generated code for digest algorithms (e.g. SHA1) can be modified by
+adding a new line in their constructor, like:
+
+ public SHA1Kernel ()
+ {
+ BufferBlockSize = 1920; // add this line
+ }
+
+Since having those limits potentially requires a lot more native/kernels
+calls, reducing overall performance, it should only be used if required.
+
View
112 class/Crimson.CryptoDev/Tests/AesKernelTest.cs
@@ -0,0 +1,112 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.CryptoDev {
+
+ [TestFixture]
+ public class AesKernelTest : AesTest {
+
+ [SetUp]
+ protected void SetUp ()
+ {
+ CryptoDevTest.EnsureAvailability ();
+ algo = Create (); // shared
+ }
+
+ protected override SymmetricAlgorithm Create ()
+ {
+ return new AesKernel ();
+ }
+
+ static bool TestBlockSize (SymmetricAlgorithm cipher, int keySize, int dataSize)
+ {
+ RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider ();
+ byte[] key = new byte [keySize];
+ rng.GetBytes (key);
+ byte[] iv = new byte [16]; // empty - not used for ECB
+ byte[] input = new byte [dataSize];
+ rng.GetBytes (input);
+ return Test (cipher, key, iv, input, null);
+ }
+
+ static bool Test (SymmetricAlgorithm cipher, byte[] key, byte[] iv, byte[] input, byte[] expected)
+ {
+ cipher.Mode = CipherMode.ECB;
+ cipher.KeySize = key.Length * 8;
+ cipher.Padding = PaddingMode.Zeros;
+
+ byte[] output = new byte [input.Length];
+ ICryptoTransform encryptor = cipher.CreateEncryptor (key, iv);
+ encryptor.TransformBlock (input, 0, input.Length, output, 0);
+ if (expected != null && !Compare (output, expected))
+ return false;
+
+ byte[] original = new byte [output.Length];
+ ICryptoTransform decryptor = cipher.CreateDecryptor (key, iv);
+ decryptor.TransformBlock (output, 0, output.Length, original, 0);
+ return Compare (original, input);
+ }
+
+ 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;
+ }
+
+ // mv_cesa has an hardware buffer limit (and the driver does not do the looping)
+ [Test]
+ public void MvCesaLimit ()
+ {
+ // max mv_cesa size
+ Assert.IsTrue (TestBlockSize (algo, 16, 1936), "128-1936");
+ Assert.IsTrue (TestBlockSize (algo, 24, 1936), "192-1936");
+ Assert.IsTrue (TestBlockSize (algo, 32, 1936), "256-1936");
+ // over the mv_cesa limit, works only if
+ // (a) mv_cesa is not used (or fixed); or
+ // (b) BufferBlockSize is set to 1936 or lower
+ Assert.IsTrue (TestBlockSize (algo, 16, 1952), "128-1952");
+ Assert.IsTrue (TestBlockSize (algo, 24, 1952), "192-1952");
+ Assert.IsTrue (TestBlockSize (algo, 32, 1952), "256-1952");
+ }
+ }
+}
View
55 class/Crimson.CryptoDev/Tests/CryptoDevTest.cs
@@ -0,0 +1,55 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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 NUnit.Framework;
+
+namespace Crimson.Test.CryptoDev {
+
+ static class CryptoDevTest {
+
+ static public void EnsureAvailability ()
+ {
+ if (!File.Exists ("/dev/crypto")) {
+ Assert.Ignore ("Missing /dev/crypto");
+ // fix by doing "sudo insmod cryptodev.ko"
+ return;
+ }
+
+ try {
+ using (var fs = new FileStream ("/dev/crypto",
+ FileMode.Open, FileAccess.Write,
+ FileShare.ReadWrite));
+ }
+ catch {
+ Assert.Ignore ("Can't access /dev/crypto");
+ // fix by doing "sudo chmod 600 /dev/crypto"
+ }
+ }
+ }
+}
View
91 class/Crimson.CryptoDev/Tests/RijndaelKernelTest.cs
@@ -0,0 +1,91 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Security.Cryptography;
+
+using Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.CryptoDev {
+
+ [TestFixture]
+ public class RijndaelKernelTest : RijndaelTest {
+
+ [SetUp]
+ protected void SetUp ()
+ {
+ CryptoDevTest.EnsureAvailability ();
+ algo = Create (); // shared
+ }
+
+ protected override SymmetricAlgorithm Create ()
+ {
+ return new RijndaelKernel ();
+ }
+
+ 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 = algo.Key;
+ byte[] iv = algo.IV;
+ 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 = 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 = algo.CreateEncryptor ().TransformFinalBlock (data, 0, data.Length);
+ }
+
+ if (!Compare (enc1, enc2))
+ Assert.Fail ("Data size = " + i);
+ }
+ }
+ }
+}
View
46 class/Crimson.CryptoDev/Tests/SHA1KernelTest.cs
@@ -0,0 +1,46 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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 Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.CryptoDev {
+
+ [TestFixture]
+ public class SHA1KernelTest : SHA1Test {
+
+ [SetUp]
+ protected void SetUp ()
+ {
+ CryptoDevTest.EnsureAvailability ();
+ hash = new SHA1Kernel ();
+ }
+ }
+}
View
46 class/Crimson.CryptoDev/Tests/SHA256KernelTest.cs
@@ -0,0 +1,46 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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 Crimson.Security.Cryptography;
+using Crimson.Test.Base;
+
+using NUnit.Framework;
+
+namespace Crimson.Test.CryptoDev {
+
+ [TestFixture]
+ public class SHA256KernelTest : SHA256Test {
+
+ [SetUp]
+ protected void SetUp ()
+ {
+ CryptoDevTest.EnsureAvailability ();
+ hash = new SHA256Kernel ();
+ }
+ }
+}
View
237 class/Crimson.CryptoDev/Tests/SymmetricAlgorithmTest.cs
@@ -0,0 +1,237 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// Copyright 2012 Symform Inc.
+//
+// Based on Mono unit tests
+// * SymmetricAlgorithm2Test.cs
+// * RijndaelTest.cs
+// * RijndaelManagedTest.cs
+//
+// Authors:
+// Andrew Birkett (andy@nobugs.org)
+// Sebastien Pouliot <spouliot@ximian.com>
+//
+// (C) 2002 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2007 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 NUnit.Framework;
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Crimson.Test.Base {
+
+ public class SymmetricAlgorithmTest {
+
+ protected SymmetricAlgorithm algo;
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ public void CreateEncryptor_KeyNull ()
+ {
+ ICryptoTransform encryptor = algo.CreateEncryptor (null, algo.IV);
+ byte[] data = new byte[encryptor.InputBlockSize];
+ byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length);
+
+ ICryptoTransform decryptor = algo.CreateDecryptor (algo.Key, algo.IV);
+ byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length);
+ // null key != SymmetricAlgorithm.Key
+ }
+
+ [Test]
+ public void CreateEncryptor_IvNull ()
+ {
+ ICryptoTransform encryptor = algo.CreateEncryptor (algo.Key, null);
+ byte[] data = new byte[encryptor.InputBlockSize];
+ byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length);
+
+ ICryptoTransform decryptor = algo.CreateDecryptor (algo.Key, algo.IV);
+ byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length);
+ Assert.IsFalse (BitConverter.ToString (data) == BitConverter.ToString (decdata), "Compare");
+ // null iv != SymmetricAlgorithm.IV
+ }
+
+ [Test]
+ public void CreateEncryptor_KeyIv ()
+ {
+ byte[] originalKey = algo.Key;
+ byte[] originalIV = algo.IV;
+
+ byte[] key = (byte[]) algo.Key.Clone ();
+ Array.Reverse (key);
+ byte[] iv = (byte[]) algo.IV.Clone ();
+ Array.Reverse (iv);
+
+ Assert.IsNotNull (algo.CreateEncryptor (key, iv), "CreateEncryptor");
+
+ Assert.AreEqual (originalKey, algo.Key, "Key");
+ Assert.AreEqual (originalIV, algo.IV, "IV");
+ // SymmetricAlgorithm Key and IV not changed by CreateEncryptor
+ }
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ [Category ("NotWorking")] // data is bad but no exception is thrown
+ public void CreateDecryptor_KeyNull ()
+ {
+ ICryptoTransform encryptor = algo.CreateEncryptor (algo.Key, algo.IV);
+ byte[] data = new byte[encryptor.InputBlockSize];
+ byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length);
+
+ ICryptoTransform decryptor = algo.CreateDecryptor (null, algo.IV);
+ byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length);
+ // null key != SymmetricAlgorithm.Key
+ }
+
+ [Test]
+ public void CreateDecryptor_IvNull ()
+ {
+ ICryptoTransform encryptor = algo.CreateEncryptor (algo.Key, algo.IV);
+ byte[] data = new byte[encryptor.InputBlockSize];
+ byte[] encdata = encryptor.TransformFinalBlock (data, 0, data.Length);
+
+ ICryptoTransform decryptor = algo.CreateDecryptor (algo.Key, null);
+ byte[] decdata = decryptor.TransformFinalBlock (encdata, 0, encdata.Length);
+ Assert.IsFalse (BitConverter.ToString (data) == BitConverter.ToString (decdata), "Compare");
+ // null iv != SymmetricAlgorithm.IV
+ }
+
+ [Test]
+ public void CreateDecryptor_KeyIv ()
+ {
+ byte[] originalKey = algo.Key;
+ byte[] originalIV = algo.IV;
+
+ byte[] key = (byte[]) algo.Key.Clone ();
+ Array.Reverse (key);
+ byte[] iv = (byte[]) algo.IV.Clone ();
+ Array.Reverse (iv);
+
+ Assert.IsNotNull (algo.CreateEncryptor (key, iv), "CreateDecryptor");
+
+ Assert.AreEqual (originalKey, algo.Key, "Key");
+ Assert.AreEqual (originalIV, algo.IV, "IV");
+ // SymmetricAlgorithm Key and IV not changed by CreateDecryptor
+ }
+
+ // Setting the IV is more restrictive than supplying an IV to
+ // CreateEncryptor and CreateDecryptor. See bug #76483
+
+ private ICryptoTransform CreateEncryptor_IV (int size)
+ {
+ byte[] iv = (size == -1) ? null : new byte[size];
+ return algo.CreateEncryptor (algo.Key, iv);
+ }
+
+ [Test]
+ public void CreateEncryptor_IV_Null ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateEncryptor_IV (-1);
+ }
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ public void CreateEncryptor_IV_Zero ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateEncryptor_IV (0);
+ }
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ public void CreateEncryptor_IV_TooSmall ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateEncryptor_IV (size);
+ }
+
+ [Test]
+ public void CreateEncryptor_IV_BlockSize ()
+ {
+ int size = (algo.BlockSize >> 3);
+ CreateEncryptor_IV (size);
+ }
+#if false
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ // Rijndael is the only implementation that has
+ // this behaviour for IV that are too large
+ [Category ("NotWorking")]
+ public void CreateEncryptor_IV_TooBig ()
+ {
+ int size = algo.BlockSize; // 8 times too big
+ CreateEncryptor_IV (size);
+ }
+#endif
+ private ICryptoTransform CreateDecryptor_IV (int size)
+ {
+ byte[] iv = (size == -1) ? null : new byte[size];
+ return algo.CreateDecryptor (algo.Key, iv);
+ }
+
+ [Test]
+ public void CreateDecryptor_IV_Null ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateDecryptor_IV (-1);
+ }
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ public void CreateDecryptor_IV_Zero ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateDecryptor_IV (0);
+ }
+
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ public void CreateDecryptor_IV_TooSmall ()
+ {
+ int size = (algo.BlockSize >> 3) - 1;
+ CreateDecryptor_IV (size);
+ }
+
+ [Test]
+ public void CreateDecryptor_IV_BlockSize ()
+ {
+ int size = (algo.BlockSize >> 3);
+ CreateDecryptor_IV (size);
+ }
+#if false
+ [Test]
+ [ExpectedException (typeof (CryptographicException))]
+ // Rijndael is the only implementation that has
+ // this behaviour for IV that are too large
+ [Category ("NotWorking")]
+ public void CreateDecryptor_IV_TooBig ()
+ {
+ int size = algo.BlockSize; // 8 times too big
+ CreateDecryptor_IV (size);
+ }
+#endif
+ }
+}
View
227 class/Crimson.CryptoDev/tools/generator.cs
@@ -0,0 +1,227 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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;
+
+class Program {
+
+ static void GenerateHash (string name)
+ {
+ string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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.Security.Cryptography;
+using Crimson.CryptoDev;
+
+namespace Crimson.Security.Cryptography {
+
+ public class {0}Kernel : {0} {
+
+ HashHelper helper;
+
+
+ public {0}Kernel ()
+ {
+ }
+
+ ~{0}Kernel ()
+ {
+ Dispose (false);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && (helper != null)) {
+ helper.Dispose ();
+ helper = null;
+ GC.SuppressFinalize (this);
+ }
+ base.Dispose (disposing);
+ }
+
+ public override void Initialize ()
+ {
+ helper = new HashHelper (Cipher.{0});
+ }
+
+ protected override void HashCore (byte[] data, int start, int length)
+ {
+ if (helper == null)
+ Initialize ();
+ helper.Update (data, start, length);
+ }
+
+ protected override byte[] HashFinal ()
+ {
+ if (helper == null)
+ Initialize ();
+ return helper.Final (HashSize >> 3);
+ }
+ }
+}";
+ string filename = Path.Combine (OutputDirectory,
+ String.Format ("{0}Kernel.g.cs", name));
+ string content = template.Replace ("{0}", name);
+ File.WriteAllText (filename, content);
+ }
+
+ static void GenerateSymmetricAlgorithm (string name, string fallback, string ecb, string cbc)
+ {
+ string template = @"// NOTE: Generated code DO NOT EDIT
+//
+// Author: Sebastien Pouliot <sebastien@gmail.com>
+// See LICENSE for copyrights and restrictions
+//
+using System;
+using System.Security.Cryptography;
+using System.Runtime.InteropServices;
+
+using Mono.Security.Cryptography;
+using Crimson.CryptoDev;
+
+namespace Crimson.Security.Cryptography {
+
+ public class {0}Kernel : {0} {
+
+ const int BufferBlockSize = Int32.MaxValue;
+
+ public {0}Kernel ()
+ {
+ }
+
+ public override void GenerateIV ()
+ {
+ IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
+ }
+
+ public override void GenerateKey ()
+ {
+ KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
+ }
+
+ {1} Fallback ()
+ {
+ {1} r = new {1} ();
+ r.Mode = Mode;
+ r.Padding = Padding;
+ return r;
+ }
+
+ public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ try {
+ switch (Mode) {
+ case CipherMode.CBC:
+ return new CryptoDevTransform (this, Cipher.{3}, false, rgbKey, rgbIV, BufferBlockSize);
+ case CipherMode.ECB:
+ return new CryptoDevTransform (this, Cipher.{2}, false, rgbKey, rgbIV, BufferBlockSize);
+ }
+ }
+ catch (CryptographicException) {
+ // the kernel might not have the required mode (even for 'generic') available
+ }
+ // other modes, effectivelty CFB, will be implemented on top
+ // on ECB, one block at the time
+ return Fallback ().CreateDecryptor (rgbKey, rgbIV);
+ }
+
+ public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
+ {
+ try {
+ switch (Mode) {
+ case CipherMode.CBC:
+ return new CryptoDevTransform (this, Cipher.{3}, true, rgbKey, rgbIV, BufferBlockSize);
+ case CipherMode.ECB:
+ return new CryptoDevTransform (this, Cipher.{2}, true, rgbKey, rgbIV, BufferBlockSize);
+ }
+ }
+ catch (CryptographicException) {
+ // the kernel might not have the required mode (even for 'generic') available
+ }
+ // other modes, effectivelty CFB, will be implemented on top
+ // on ECB, one block at the time
+ return Fallback ().CreateEncryptor (rgbKey, rgbIV);
+ }
+ }
+}";
+ string filename = Path.Combine (OutputDirectory,
+ String.Format ("{0}Kernel.g.cs", name));
+ string content = template.Replace ("{0}", name).
+ Replace ("{1}", fallback).
+ Replace ("{2}", ecb).
+ Replace ("{3}", cbc);
+ 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
+#if UNTESTED
+ GenerateHash ("MD5"); // CRYPTO_MD5
+ GenerateHash ("RIPEMD160"); // CRYPTO_RIPEMD160
+ GenerateHash ("SHA384"); // CRYPTO_SHA2_384
+ GenerateHash ("SHA512"); // CRYPTO_SHA2_512
+#endif
+ 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
+ }
+}
View
256 class/Crimson.CryptoDev/tools/torture.cs
@@ -0,0 +1,256 @@
+//
+// Author:
+// Sebastien Pouliot <sebastien@gmail.com>
+//
+// 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;
+ }
+}

0 comments on commit 1e27ce6

Please sign in to comment.