diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs
new file mode 100644
index 000000000..b24fb3995
--- /dev/null
+++ b/crypto/src/crypto/digests/SkeinDigest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /// <summary>
+ /// Implementation of the Skein parameterised hash function in 256, 512 and 1024 bit block sizes,
+ /// based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+ /// </summary>
+ /// <remarks>
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ /// <p/>
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ /// </remarks>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+ public class SkeinDigest
+ : IDigest//, IMemoable
+ {
+ /// <summary>
+ /// 256 bit block size - Skein-256
+ /// </summary>
+ public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+ /// <summary>
+ /// 512 bit block size - Skein-512
+ /// </summary>
+ public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+ /// <summary>
+ /// 1024 bit block size - Skein-1024
+ /// </summary>
+ public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+ private readonly SkeinEngine engine;
+
+ /// <summary>
+ /// Constructs a Skein digest with an internal state size and output size.
+ /// </summary>
+ /// <param name="stateSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+ /// <see cref="SKEIN_1024"/>.</param>
+ /// <param name="digestSizeBits">the output/digest size to produce in bits, which must be an integral number of
+ /// bytes.</param>
+ public SkeinDigest(int stateSizeBits, int digestSizeBits)
+ {
+ this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+ Init(null);
+ }
+
+ public SkeinDigest(SkeinDigest digest)
+ {
+ this.engine = new SkeinEngine(digest.engine);
+ }
+
+ // public void Reset(IMemoable other)
+ // {
+ // SkeinDigest d = (SkeinDigest)other;
+ // engine.reset(d.engine);
+ // }
+ //
+ // public IMemoable copy()
+ // {
+ // return new SkeinDigest(this);
+ // }
+
+ public String AlgorithmName
+ {
+ get { return "Skein-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+ }
+
+ public int GetDigestSize()
+ {
+ return engine.OutputSize;
+ }
+
+ public int GetByteLength()
+ {
+ return engine.BlockSize;
+ }
+
+ /// <summary>
+ /// Optionally initialises the Skein digest with the provided parameters.
+ /// </summary>
+ /// See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"></see> for details on the parameterisation of the Skein hash function.
+ /// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+ public void Init(SkeinParameters parameters)
+ {
+ engine.Init(parameters);
+ }
+
+ public void Reset()
+ {
+ engine.Reset();
+ }
+
+ public void Update(byte inByte)
+ {
+ engine.Update(inByte);
+ }
+
+ public void BlockUpdate(byte[] inBytes, int inOff, int len)
+ {
+ engine.Update(inBytes, inOff, len);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ return engine.DoFinal(outBytes, outOff);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
new file mode 100644
index 000000000..94529bcf6
--- /dev/null
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -0,0 +1,803 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /// <summary>
+ /// Implementation of the Skein family of parameterised hash functions in 256, 512 and 1024 bit block
+ /// sizes, based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+ /// </summary>
+ /// <remarks>
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ /// <p/>
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ /// <p/>
+ /// This implementation is the basis for <see cref="Org.BouncyCastle.Crypto.Digests.SkeinDigest"/> and <see cref="Org.BouncyCastle.Crypto.Macs.SkeinMac"/>, implementing the
+ /// parameter based configuration system that allows Skein to be adapted to multiple applications. <br>
+ /// Initialising the engine with <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/> allows standard and arbitrary parameters to
+ /// be applied during the Skein hash function.
+ /// <p/>
+ /// Implemented:
+ /// <ul>
+ /// <li>256, 512 and 1024 bit internal states.</li>
+ /// <li>Full 96 bit input length.</li>
+ /// <li>Parameters defined in the Skein specification, and arbitrary other pre and post message
+ /// parameters.</li>
+ /// <li>Arbitrary output size in 1 byte intervals.</li>
+ /// </ul>
+ /// <p/>
+ /// Not implemented:
+ /// <ul>
+ /// <li>Sub-byte length input (bit padding).</li>
+ /// <li>Tree hashing.</li>
+ /// </ul>
+ /// </remarks>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+ public class SkeinEngine
+ // : IMemoable
+ {
+ /// <summary>
+ /// 256 bit block size - Skein-256
+ /// </summary>
+ public const int SKEIN_256 = ThreefishEngine.BLOCKSIZE_256;
+ /// <summary>
+ /// 512 bit block size - Skein-512
+ /// </summary>
+ public const int SKEIN_512 = ThreefishEngine.BLOCKSIZE_512;
+ /// <summary>
+ /// 1024 bit block size - Skein-1024
+ /// </summary>
+ public const int SKEIN_1024 = ThreefishEngine.BLOCKSIZE_1024;
+
+ // Minimal at present, but more complex when tree hashing is implemented
+ private class Configuration
+ {
+ private byte[] bytes = new byte[32];
+
+ public Configuration(long outputSizeBits)
+ {
+ // 0..3 = ASCII SHA3
+ bytes[0] = (byte)'S';
+ bytes[1] = (byte)'H';
+ bytes[2] = (byte)'A';
+ bytes[3] = (byte)'3';
+
+ // 4..5 = version number in LSB order
+ bytes[4] = 1;
+ bytes[5] = 0;
+
+ // 8..15 = output length
+ ThreefishEngine.WordToBytes((ulong)outputSizeBits, bytes, 8);
+ }
+
+ public byte[] Bytes
+ {
+ get { return bytes; }
+ }
+
+ }
+
+ public class Parameter
+ {
+ private int type;
+ private byte[] value;
+
+ public Parameter(int type, byte[] value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public int Type
+ {
+ get { return type; }
+ }
+
+ public byte[] Value
+ {
+ get { return value; }
+ }
+
+ }
+
+ /**
+ * The parameter type for the Skein key.
+ */
+ private const int PARAM_TYPE_KEY = 0;
+
+ /**
+ * The parameter type for the Skein configuration block.
+ */
+ private const int PARAM_TYPE_CONFIG = 4;
+
+ /**
+ * The parameter type for the message.
+ */
+ private const int PARAM_TYPE_MESSAGE = 48;
+
+ /**
+ * The parameter type for the output transformation.
+ */
+ private const int PARAM_TYPE_OUTPUT = 63;
+
+ /**
+ * Precalculated UBI(CFG) states for common state/output combinations without key or other
+ * pre-message params.
+ */
+ private static readonly IDictionary INITIAL_STATES = Platform.CreateHashtable();
+
+ static SkeinEngine()
+ {
+ // From Appendix C of the Skein 1.3 NIST submission
+ InitialState(SKEIN_256, 128, new ulong[]{
+ 0xe1111906964d7260UL,
+ 0x883daaa77c8d811cUL,
+ 0x10080df491960f7aUL,
+ 0xccf7dde5b45bc1c2UL});
+
+ InitialState(SKEIN_256, 160, new ulong[]{
+ 0x1420231472825e98UL,
+ 0x2ac4e9a25a77e590UL,
+ 0xd47a58568838d63eUL,
+ 0x2dd2e4968586ab7dUL});
+
+ InitialState(SKEIN_256, 224, new ulong[]{
+ 0xc6098a8c9ae5ea0bUL,
+ 0x876d568608c5191cUL,
+ 0x99cb88d7d7f53884UL,
+ 0x384bddb1aeddb5deUL});
+
+ InitialState(SKEIN_256, 256, new ulong[]{
+ 0xfc9da860d048b449UL,
+ 0x2fca66479fa7d833UL,
+ 0xb33bc3896656840fUL,
+ 0x6a54e920fde8da69UL});
+
+ InitialState(SKEIN_512, 128, new ulong[]{
+ 0xa8bc7bf36fbf9f52UL,
+ 0x1e9872cebd1af0aaUL,
+ 0x309b1790b32190d3UL,
+ 0xbcfbb8543f94805cUL,
+ 0x0da61bcd6e31b11bUL,
+ 0x1a18ebead46a32e3UL,
+ 0xa2cc5b18ce84aa82UL,
+ 0x6982ab289d46982dUL});
+
+ InitialState(SKEIN_512, 160, new ulong[]{
+ 0x28b81a2ae013bd91UL,
+ 0xc2f11668b5bdf78fUL,
+ 0x1760d8f3f6a56f12UL,
+ 0x4fb747588239904fUL,
+ 0x21ede07f7eaf5056UL,
+ 0xd908922e63ed70b8UL,
+ 0xb8ec76ffeccb52faUL,
+ 0x01a47bb8a3f27a6eUL});
+
+ InitialState(SKEIN_512, 224, new ulong[]{
+ 0xccd0616248677224UL,
+ 0xcba65cf3a92339efUL,
+ 0x8ccd69d652ff4b64UL,
+ 0x398aed7b3ab890b4UL,
+ 0x0f59d1b1457d2bd0UL,
+ 0x6776fe6575d4eb3dUL,
+ 0x99fbc70e997413e9UL,
+ 0x9e2cfccfe1c41ef7UL});
+
+ InitialState(SKEIN_512, 384, new ulong[]{
+ 0xa3f6c6bf3a75ef5fUL,
+ 0xb0fef9ccfd84faa4UL,
+ 0x9d77dd663d770cfeUL,
+ 0xd798cbf3b468fddaUL,
+ 0x1bc4a6668a0e4465UL,
+ 0x7ed7d434e5807407UL,
+ 0x548fc1acd4ec44d6UL,
+ 0x266e17546aa18ff8UL});
+
+ InitialState(SKEIN_512, 512, new ulong[]{
+ 0x4903adff749c51ceUL,
+ 0x0d95de399746df03UL,
+ 0x8fd1934127c79bceUL,
+ 0x9a255629ff352cb1UL,
+ 0x5db62599df6ca7b0UL,
+ 0xeabe394ca9d5c3f4UL,
+ 0x991112c71a75b523UL,
+ 0xae18a40b660fcc33UL});
+ }
+
+ private static void InitialState(int blockSize, int outputSize, ulong[] state)
+ {
+ INITIAL_STATES.Add(VariantIdentifier(blockSize / 8, outputSize / 8), state);
+ }
+
+ private static int VariantIdentifier(int blockSizeBytes, int outputSizeBytes)
+ {
+ return (outputSizeBytes << 16) | blockSizeBytes;
+ }
+
+ private class UbiTweak
+ {
+ /**
+ * Point at which position might overflow long, so switch to add with carry logic
+ */
+ private const ulong LOW_RANGE = UInt64.MaxValue - UInt32.MaxValue;
+
+ /**
+ * Bit 127 = final
+ */
+ private const ulong T1_FINAL = 1UL << 63;
+
+ /**
+ * Bit 126 = first
+ */
+ private const ulong T1_FIRST = 1UL << 62;
+
+ /**
+ * UBI uses a 128 bit tweak
+ */
+ private ulong[] tweak = new ulong[2];
+
+ /**
+ * Whether 64 bit position exceeded
+ */
+ private bool extendedPosition;
+
+ public UbiTweak()
+ {
+ Reset();
+ }
+
+ public void Reset(UbiTweak tweak)
+ {
+ this.tweak = Arrays.Clone(tweak.tweak, this.tweak);
+ this.extendedPosition = tweak.extendedPosition;
+ }
+
+ public void Reset()
+ {
+ tweak[0] = 0;
+ tweak[1] = 0;
+ extendedPosition = false;
+ First = true;
+ }
+
+ public uint Type
+ {
+ get
+ {
+ return (uint)((tweak[1] >> 56) & 0x3FUL);
+ }
+
+ set
+ {
+ // Bits 120..125 = type
+ tweak[1] = (tweak[1] & 0xFFFFFFC000000000UL) | ((value & 0x3FUL) << 56);
+ }
+ }
+
+ public bool First
+ {
+ get
+ {
+ return ((tweak[1] & T1_FIRST) != 0);
+ }
+ set
+ {
+ if (value)
+ {
+ tweak[1] |= T1_FIRST;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FIRST;
+ }
+ }
+ }
+
+ public bool Final
+ {
+ get
+ {
+ return ((tweak[1] & T1_FINAL) != 0);
+ }
+ set
+ {
+ if (value)
+ {
+ tweak[1] |= T1_FINAL;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FINAL;
+ }
+ }
+ }
+
+ /**
+ * Advances the position in the tweak by the specified value.
+ */
+ public void AdvancePosition(int advance)
+ {
+ // Bits 0..95 = position
+ if (extendedPosition)
+ {
+ ulong[] parts = new ulong[3];
+ parts[0] = tweak[0] & 0xFFFFFFFFUL;
+ parts[1] = (tweak[0] >> 32) & 0xFFFFFFFFUL;
+ parts[2] = tweak[1] & 0xFFFFFFFFUL;
+
+ ulong carry = (ulong)advance;
+ for (int i = 0; i < parts.Length; i++)
+ {
+ carry += parts[i];
+ parts[i] = carry;
+ carry >>= 32;
+ }
+ tweak[0] = ((parts[1] & 0xFFFFFFFFUL) << 32) | (parts[0] & 0xFFFFFFFFUL);
+ tweak[1] = (tweak[1] & 0xFFFFFFFF00000000UL) | (parts[2] & 0xFFFFFFFFUL);
+ }
+ else
+ {
+ ulong position = tweak[0];
+ position += (uint)advance;
+ tweak[0] = position;
+ if (position > LOW_RANGE)
+ {
+ extendedPosition = true;
+ }
+ }
+ }
+
+ public ulong[] GetWords()
+ {
+ return tweak;
+ }
+
+ public override string ToString()
+ {
+ return Type + " first: " + First + ", final: " + Final;
+ }
+
+ }
+
+ /**
+ * The Unique Block Iteration chaining mode.
+ */
+ // TODO: This might be better as methods...
+ private class UBI
+ {
+ private readonly UbiTweak tweak = new UbiTweak();
+
+ private readonly SkeinEngine engine;
+
+ /**
+ * Buffer for the current block of message data
+ */
+ private byte[] currentBlock;
+
+ /**
+ * Offset into the current message block
+ */
+ private int currentOffset;
+
+ /**
+ * Buffer for message words for feedback into encrypted block
+ */
+ private ulong[] message;
+
+ public UBI(SkeinEngine engine, int blockSize)
+ {
+ this.engine = engine;
+ currentBlock = new byte[blockSize];
+ message = new ulong[currentBlock.Length / 8];
+ }
+
+ public void Reset(UBI ubi)
+ {
+ currentBlock = Arrays.Clone(ubi.currentBlock, currentBlock);
+ currentOffset = ubi.currentOffset;
+ message = Arrays.Clone(ubi.message, this.message);
+ tweak.Reset(ubi.tweak);
+ }
+
+ public void Reset(int type)
+ {
+ tweak.Reset();
+ tweak.Type = (uint)type;
+ currentOffset = 0;
+ }
+
+ public void Update(byte[] value, int offset, int len, ulong[] output)
+ {
+ /*
+ * Buffer complete blocks for the underlying Threefish cipher, only flushing when there
+ * are subsequent bytes (last block must be processed in doFinal() with final=true set).
+ */
+ int copied = 0;
+ while (len > copied)
+ {
+ if (currentOffset == currentBlock.Length)
+ {
+ ProcessBlock(output);
+ tweak.First = false;
+ currentOffset = 0;
+ }
+
+ int toCopy = System.Math.Min((len - copied), currentBlock.Length - currentOffset);
+ Array.Copy(value, offset + copied, currentBlock, currentOffset, toCopy);
+ copied += toCopy;
+ currentOffset += toCopy;
+ tweak.AdvancePosition(toCopy);
+ }
+ }
+
+ private void ProcessBlock(ulong[] output)
+ {
+ engine.threefish.Init(true, engine.chain, tweak.GetWords());
+ for (int i = 0; i < message.Length; i++)
+ {
+ message[i] = ThreefishEngine.BytesToWord(currentBlock, i * 8);
+ }
+
+ engine.threefish.ProcessBlock(message, output);
+
+ for (int i = 0; i < output.Length; i++)
+ {
+ output[i] ^= message[i];
+ }
+ }
+
+ public void DoFinal(ulong[] output)
+ {
+ // Pad remainder of current block with zeroes
+ for (int i = currentOffset; i < currentBlock.Length; i++)
+ {
+ currentBlock[i] = 0;
+ }
+
+ tweak.Final = true;
+ ProcessBlock(output);
+ }
+
+ }
+
+ /**
+ * Underlying Threefish tweakable block cipher
+ */
+ private readonly ThreefishEngine threefish;
+
+ /**
+ * Size of the digest output, in bytes
+ */
+ private readonly int outputSizeBytes;
+
+ /**
+ * The current chaining/state value
+ */
+ private ulong[] chain;
+
+ /**
+ * The initial state value
+ */
+ private ulong[] initialState;
+
+ /**
+ * The (optional) key parameter
+ */
+ private byte[] key;
+
+ /**
+ * Parameters to apply prior to the message
+ */
+ private Parameter[] preMessageParameters;
+
+ /**
+ * Parameters to apply after the message, but prior to output
+ */
+ private Parameter[] postMessageParameters;
+
+ /**
+ * The current UBI operation
+ */
+ private readonly UBI ubi;
+
+ /**
+ * Buffer for single byte update method
+ */
+ private readonly byte[] singleByte = new byte[1];
+
+ /// <summary>
+ /// Constructs a Skein digest with an internal state size and output size.
+ /// </summary>
+ /// <param name="stateSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+ /// <see cref="SKEIN_1024"/>.</param>
+ /// <param name="outputSizeBits">the output/digest size to produce in bits, which must be an integral number of
+ /// bytes.</param>
+ public SkeinEngine(int blockSizeBits, int outputSizeBits)
+ {
+ if (outputSizeBits % 8 != 0)
+ {
+ throw new ArgumentException("Output size must be a multiple of 8 bits. :" + outputSizeBits);
+ }
+ // TODO: Prevent digest sizes > block size?
+ this.outputSizeBytes = outputSizeBits / 8;
+
+ this.threefish = new ThreefishEngine(blockSizeBits);
+ this.ubi = new UBI(this,threefish.GetBlockSize());
+ }
+
+ /// <summary>
+ /// Creates a SkeinEngine as an exact copy of an existing instance.
+ /// </summary>
+ public SkeinEngine(SkeinEngine engine)
+ : this(engine.BlockSize * 8, engine.OutputSize * 8)
+ {
+ CopyIn(engine);
+ }
+
+ private void CopyIn(SkeinEngine engine)
+ {
+ this.ubi.Reset(engine.ubi);
+ this.chain = Arrays.Clone(engine.chain, this.chain);
+ this.initialState = Arrays.Clone(engine.initialState, this.initialState);
+ this.key = Arrays.Clone(engine.key, this.key);
+ this.preMessageParameters = Clone(engine.preMessageParameters, this.preMessageParameters);
+ this.postMessageParameters = Clone(engine.postMessageParameters, this.postMessageParameters);
+ }
+
+ private static Parameter[] Clone(Parameter[] data, Parameter[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ existing = new Parameter[data.Length];
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
+ // public IMemoable Copy()
+ // {
+ // return new SkeinEngine(this);
+ // }
+ //
+ // public void Reset(IMemoable other)
+ // {
+ // SkeinEngine s = (SkeinEngine)other;
+ // if ((getBlockSize() != s.getBlockSize()) || (outputSizeBytes != s.outputSizeBytes))
+ // {
+ // throw new IllegalArgumentException("Incompatible parameters in provided SkeinEngine.");
+ // }
+ // copyIn(s);
+ // }
+
+ public int OutputSize
+ {
+ get { return outputSizeBytes; }
+ }
+
+ public int BlockSize
+ {
+ get { return threefish.GetBlockSize (); }
+ }
+
+ /// <summary>
+ /// Initialises the Skein engine with the provided parameters. See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/> for
+ /// details on the parameterisation of the Skein hash function.
+ /// </summary>
+ /// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+ public void Init(SkeinParameters parameters)
+ {
+ this.chain = null;
+ this.key = null;
+ this.preMessageParameters = null;
+ this.postMessageParameters = null;
+
+ if (parameters != null)
+ {
+ byte[] key = parameters.GetKey();
+ if (key.Length < 16)
+ {
+ throw new ArgumentException("Skein key must be at least 128 bits.");
+ }
+ InitParams(parameters.GetParameters());
+ }
+ CreateInitialState();
+
+ // Initialise message block
+ UbiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void InitParams(IDictionary parameters)
+ {
+ IEnumerator keys = parameters.Keys.GetEnumerator();
+ IList pre = Platform.CreateArrayList();
+ IList post = Platform.CreateArrayList();
+
+ while (keys.MoveNext())
+ {
+ int type = (int)keys.Current;
+ byte[] value = (byte[])parameters[type];
+
+ if (type == PARAM_TYPE_KEY)
+ {
+ this.key = value;
+ }
+ else if (type < PARAM_TYPE_MESSAGE)
+ {
+ pre.Add(new Parameter(type, value));
+ }
+ else
+ {
+ post.Add(new Parameter(type, value));
+ }
+ }
+ preMessageParameters = new Parameter[pre.Count];
+ pre.CopyTo(preMessageParameters, 0);
+ Array.Sort(preMessageParameters);
+
+ postMessageParameters = new Parameter[post.Count];
+ post.CopyTo(postMessageParameters, 0);
+ Array.Sort(postMessageParameters);
+ }
+
+ /**
+ * Calculate the initial (pre message block) chaining state.
+ */
+ private void CreateInitialState()
+ {
+ ulong[] precalc = (ulong[])INITIAL_STATES[VariantIdentifier(BlockSize, OutputSize)];
+ if ((key == null) && (precalc != null))
+ {
+ // Precalculated UBI(CFG)
+ chain = Arrays.Clone(precalc);
+ }
+ else
+ {
+ // Blank initial state
+ chain = new ulong[BlockSize / 8];
+
+ // Process key block
+ if (key != null)
+ {
+ UbiComplete(SkeinParameters.PARAM_TYPE_KEY, key);
+ }
+
+ // Process configuration block
+ UbiComplete(PARAM_TYPE_CONFIG, new Configuration(outputSizeBytes * 8).Bytes);
+ }
+
+ // Process additional pre-message parameters
+ if (preMessageParameters != null)
+ {
+ for (int i = 0; i < preMessageParameters.Length; i++)
+ {
+ Parameter param = preMessageParameters[i];
+ UbiComplete(param.Type, param.Value);
+ }
+ }
+ initialState = Arrays.Clone(chain);
+ }
+
+ /// <summary>
+ /// Reset the engine to the initial state (with the key and any pre-message parameters , ready to
+ /// accept message input.
+ /// </summary>
+ public void Reset()
+ {
+ Array.Copy(initialState, 0, chain, 0, chain.Length);
+
+ UbiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void UbiComplete(int type, byte[] value)
+ {
+ UbiInit(type);
+ this.ubi.Update(value, 0, value.Length, chain);
+ UbiFinal();
+ }
+
+ private void UbiInit(int type)
+ {
+ this.ubi.Reset(type);
+ }
+
+ private void UbiFinal()
+ {
+ ubi.DoFinal(chain);
+ }
+
+ private void CheckInitialised()
+ {
+ if (this.ubi == null)
+ {
+ throw new ArgumentException("Skein engine is not initialised.");
+ }
+ }
+
+ public void Update(byte inByte)
+ {
+ singleByte[0] = inByte;
+ Update(singleByte, 0, 1);
+ }
+
+ public void Update(byte[] inBytes, int inOff, int len)
+ {
+ CheckInitialised();
+ ubi.Update(inBytes, inOff, len, chain);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ CheckInitialised();
+ if (outBytes.Length < (outOff + outputSizeBytes))
+ {
+ throw new DataLengthException("Output buffer is too short to hold output of " + outputSizeBytes + " bytes");
+ }
+
+ // Finalise message block
+ UbiFinal();
+
+ // Process additional post-message parameters
+ if (postMessageParameters != null)
+ {
+ for (int i = 0; i < postMessageParameters.Length; i++)
+ {
+ Parameter param = postMessageParameters[i];
+ UbiComplete(param.Type, param.Value);
+ }
+ }
+
+ // Perform the output transform
+ int blockSize = BlockSize;
+ int blocksRequired = ((outputSizeBytes + blockSize - 1) / blockSize);
+ for (int i = 0; i < blocksRequired; i++)
+ {
+ int toWrite = System.Math.Min(blockSize, outputSizeBytes - (i * blockSize));
+ Output((ulong)i, outBytes, outOff + (i * blockSize), toWrite);
+ }
+
+ Reset();
+
+ return outputSizeBytes;
+ }
+
+ private void Output(ulong outputSequence, byte[] outBytes, int outOff, int outputBytes)
+ {
+ byte[] currentBytes = new byte[8];
+ ThreefishEngine.WordToBytes(outputSequence, currentBytes, 0);
+
+ // Output is a sequence of UBI invocations all of which use and preserve the pre-output
+ // state
+ ulong[] outputWords = new ulong[chain.Length];
+ UbiInit(PARAM_TYPE_OUTPUT);
+ this.ubi.Update(currentBytes, 0, currentBytes.Length, outputWords);
+ ubi.DoFinal(outputWords);
+
+ int wordsRequired = ((outputBytes + 8 - 1) / 8);
+ for (int i = 0; i < wordsRequired; i++)
+ {
+ int toWrite = System.Math.Min(8, outputBytes - (i * 8));
+ if (toWrite == 8)
+ {
+ ThreefishEngine.WordToBytes(outputWords[i], outBytes, outOff + (i * 8));
+ }
+ else
+ {
+ ThreefishEngine.WordToBytes(outputWords[i], currentBytes, 0);
+ Array.Copy(currentBytes, 0, outBytes, outOff + (i * 8), toWrite);
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
new file mode 100644
index 000000000..1d61a41ca
--- /dev/null
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+
+ /// <summary>
+ /// Implementation of the Skein parameterised MAC function in 256, 512 and 1024 bit block sizes,
+ /// based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+ /// </summary>
+ /// <remarks>
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ /// <p/>
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ /// </remarks>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+ public class SkeinMac
+ : IMac
+ {
+ /// <summary>
+ /// 256 bit block size - Skein-256
+ /// </summary>
+ public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+ /// <summary>
+ /// 512 bit block size - Skein-512
+ /// </summary>
+ public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+ /// <summary>
+ /// 1024 bit block size - Skein-1024
+ /// </summary>
+ public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+ private readonly SkeinEngine engine;
+
+ /// <summary>
+ /// Constructs a Skein MAC with an internal state size and output size.
+ /// </summary>
+ /// <param name="stateSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+ /// <see cref="SKEIN_1024"/>.</param>
+ /// <param name="digestSizeBits">the output/MAC size to produce in bits, which must be an integral number of
+ /// bytes.</param>
+ public SkeinMac(int stateSizeBits, int digestSizeBits)
+ {
+ this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+ }
+
+ public SkeinMac(SkeinMac mac)
+ {
+ this.engine = new SkeinEngine(mac.engine);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Skein-MAC-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+ }
+
+ /// <summary>
+ /// Optionally initialises the Skein digest with the provided parameters.
+ /// </summary>
+ /// See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"></see> for details on the parameterisation of the Skein hash function.
+ /// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+ public void Init(ICipherParameters parameters)
+ {
+ SkeinParameters skeinParameters;
+ if (parameters is SkeinParameters)
+ {
+ skeinParameters = (SkeinParameters)parameters;
+ }
+ else if (parameters is KeyParameter)
+ {
+ skeinParameters = new SkeinParameters.Builder().SetKey(((KeyParameter)parameters).GetKey()).Build();
+ }
+ else
+ {
+ throw new ArgumentException("Invalid parameter passed to Skein MAC init - "
+ + parameters.GetType().Name);
+ }
+ if (skeinParameters.GetKey() == null)
+ {
+ throw new ArgumentException("Skein MAC requires a key parameter.");
+ }
+ engine.Init(skeinParameters);
+ }
+
+ public int GetMacSize()
+ {
+ return engine.OutputSize;
+ }
+
+ public void Reset()
+ {
+ engine.Reset();
+ }
+
+ public void Update(byte inByte)
+ {
+ engine.Update(inByte);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ engine.Update(input, inOff, len);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ return engine.DoFinal(output, outOff);
+ }
+
+ }
+}
diff --git a/crypto/src/crypto/parameters/SkeinParameters.cs b/crypto/src/crypto/parameters/SkeinParameters.cs
new file mode 100644
index 000000000..bbd25e0e0
--- /dev/null
+++ b/crypto/src/crypto/parameters/SkeinParameters.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+ /// <summary>
+ /// Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
+ /// </summary>
+ /// <remarks>
+ /// Parameterised Skein can be used for:
+ /// <ul>
+ /// <li>MAC generation, by providing a <see cref="SkeinParameters.Builder.SetKey(byte[])">key</see>.</li>
+ /// <li>Randomised hashing, by providing a <see cref="SkeinParameters.Builder.SetNoce(byte[])">nonce</see>.</li>
+ /// <li>A hash function for digital signatures, associating a
+ /// <see cref="SkeinParameters.Builder.SetPublicKey(byte[])">public key</see> with the message digest.</li>
+ /// <li>A key derivation function, by providing a
+ /// <see cref="SkeinParameters.Builder.SetKeyIdentifier(byte[])">key identifier</see>.</li>
+ /// <li>Personalised hashing, by providing a
+ /// <see cref="SkeinParameters.Builder.SetPersonalisation(DateTime,string,string)">recommended format</see> or
+ /// <see cref="SkeinParameters.Builder.SetPersonalisation(byte[])">arbitrary</see> personalisation string.</li>
+ /// </ul>
+ /// </remarks>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinDigest"/>
+ /// <seealso cref="Org.BouncyCastle.Crypto.Macs.SkeinMac"/>
+ public class SkeinParameters
+ : ICipherParameters
+ {
+ /// <summary>
+ /// The parameter type for a secret key, supporting MAC or KDF functions: 0
+ /// </summary>
+ public const int PARAM_TYPE_KEY = 0;
+
+ /// <summary>
+ /// The parameter type for the Skein configuration block: 4
+ /// </summary>
+ public const int PARAM_TYPE_CONFIG = 4;
+
+ /// <summary>
+ /// The parameter type for a personalisation string: 8
+ /// </summary>
+ public const int PARAM_TYPE_PERSONALISATION = 8;
+
+ /// <summary>
+ /// The parameter type for a public key: 12
+ /// </summary>
+ public const int PARAM_TYPE_PUBLIC_KEY = 12;
+
+ /// <summary>
+ /// The parameter type for a key identifier string: 16
+ /// </summary>
+ public const int PARAM_TYPE_KEY_IDENTIFIER = 16;
+
+ /// <summary>
+ /// The parameter type for a nonce: 20
+ /// </summary>
+ public const int PARAM_TYPE_NONCE = 20;
+
+ /// <summary>
+ /// The parameter type for the message: 48
+ /// </summary>
+ public const int PARAM_TYPE_MESSAGE = 48;
+
+ /// <summary>
+ /// The parameter type for the output transformation: 63
+ /// </summary>
+ public const int PARAM_TYPE_OUTPUT = 63;
+
+ private IDictionary parameters;
+
+ public SkeinParameters()
+ : this(Platform.CreateHashtable())
+
+ {
+ }
+
+ private SkeinParameters(IDictionary parameters)
+ {
+ this.parameters = parameters;
+ }
+
+ /// <summary>
+ /// Obtains a map of type (int) to value (byte[]) for the parameters tracked in this object.
+ /// </summary>
+ public IDictionary GetParameters()
+ {
+ return parameters;
+ }
+
+ /// <summary>
+ /// Obtains the value of the <see cref="PARAM_TYPE_KEY">key parameter</see>, or <code>null</code> if not
+ /// set.
+ /// </summary>
+ /// <returns>The key.</returns>
+ public byte[] GetKey()
+ {
+ return (byte[])parameters[PARAM_TYPE_KEY];
+ }
+
+ /// <summary>
+ /// Obtains the value of the <see cref="PARAM_TYPE_PERSONALISATION">personalisation parameter</see>, or
+ /// <code>null</code> if not set.
+ /// </summary>
+ public byte[] GetPersonalisation()
+ {
+ return (byte[])parameters[PARAM_TYPE_PERSONALISATION];
+ }
+
+ /// <summary>
+ /// Obtains the value of the <see cref="PARAM_TYPE_PUBLIC_KEY">public key parameter</see>, or
+ /// <code>null</code> if not set.
+ /// </summary>
+ public byte[] GetPublicKey()
+ {
+ return (byte[])parameters[PARAM_TYPE_PUBLIC_KEY];
+ }
+
+ /// <summary>
+ /// Obtains the value of the <see cref="PARAM_TYPE_KEY_IDENTIFIER key identifier parameter</see>, or
+ /// <code>null</code> if not set.
+ /// </summary>
+ public byte[] GetKeyIdentifier()
+ {
+ return (byte[])parameters[PARAM_TYPE_KEY_IDENTIFIER];
+ }
+
+ /// <summary>
+ /// Obtains the value of the <see cref="PARAM_TYPE_NONCE nonce parameter</see>, or <code>null</code> if
+ /// not set.
+ /// </summary>
+ public byte[] GetNonce()
+ {
+ return (byte[])parameters[PARAM_TYPE_NONCE];
+ }
+
+ /// <summary>
+ /// A builder for <see cref="SkeinParameters"/>.
+ /// </summary>
+ public class Builder
+ {
+ private IDictionary parameters = Platform.CreateHashtable();
+
+ public Builder()
+ {
+ }
+
+ public Builder(IDictionary paramsMap)
+ {
+ IEnumerator keys = paramsMap.Keys.GetEnumerator();
+ while (keys.MoveNext())
+ {
+ int key = (int)keys.Current;
+ parameters.Add(key, paramsMap[key]);
+ }
+ }
+
+ public Builder(SkeinParameters parameters)
+ {
+ IEnumerator keys = parameters.parameters.Keys.GetEnumerator();
+ while (keys.MoveNext())
+ {
+ int key = (int)keys.Current;
+ this.parameters.Add(key, parameters.parameters[key]);
+ }
+ }
+
+ /// <summary>
+ /// Sets a parameters to apply to the Skein hash function.
+ /// </summary>
+ /// <remarks>
+ /// Parameter types must be in the range 0,5..62, and cannot use the value 48
+ /// (reserved for message body).
+ /// <p/>
+ /// Parameters with type < 48 are processed before
+ /// the message content, parameters with type > 48
+ /// are processed after the message and prior to output.
+ /// </remarks>
+ /// <param name="type">the type of the parameter, in the range 5..62.</param>
+ /// <param name="value">the byte sequence of the parameter.</param>
+ public Builder Set(int type, byte[] value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentException("Parameter value must not be null.");
+ }
+ if ((type != PARAM_TYPE_KEY)
+ && (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
+ {
+ throw new ArgumentException("Parameter types must be in the range 0,5..47,49..62.");
+ }
+ if (type == PARAM_TYPE_CONFIG)
+ {
+ throw new ArgumentException("Parameter type " + PARAM_TYPE_CONFIG
+ + " is reserved for internal use.");
+ }
+ this.parameters.Add(type, value);
+ return this;
+ }
+
+ /// <summary>
+ /// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY"/> parameter.
+ /// </summary>
+ public Builder SetKey(byte[] key)
+ {
+ return Set(PARAM_TYPE_KEY, key);
+ }
+
+ /// <summary>
+ /// Sets the <see cref="SkeinParameters.PARAM_TYPE_PERSONALISATION"/> parameter.
+ /// </summary>
+ public Builder SetPersonalisation(byte[] personalisation)
+ {
+ return Set(PARAM_TYPE_PERSONALISATION, personalisation);
+ }
+
+ /// <summary>
+ /// Implements the recommended personalisation format for Skein defined in Section 4.11 of
+ /// the Skein 1.3 specification.
+ /// </summary>
+ /// <remarks>
+ /// The format is <code>YYYYMMDD email@address distinguisher</code>, encoded to a byte
+ /// sequence using UTF-8 encoding.
+ /// </remarks>
+ /// <param name="date">the date the personalised application of the Skein was defined.</param>
+ /// <param name="emailAddress">the email address of the creation of the personalised application.</param>
+ /// <param name="distinguisher">an arbitrary personalisation string distinguishing the application.</param>
+ public Builder SetPersonalisation(DateTime date, string emailAddress, string distinguisher)
+ {
+ try
+ {
+ MemoryStream bout = new MemoryStream();
+ StreamWriter outBytes = new StreamWriter(bout, System.Text.Encoding.UTF8);
+ outBytes.Write(date.ToString("YYYYMMDD"));
+ outBytes.Write(" ");
+ outBytes.Write(emailAddress);
+ outBytes.Write(" ");
+ outBytes.Write(distinguisher);
+ outBytes.Close();
+ return Set(PARAM_TYPE_PERSONALISATION, bout.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("Byte I/O failed.", e);
+ }
+ }
+
+ /// <summary>
+ /// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY_IDENTIFIER"/> parameter.
+ /// </summary>
+ public Builder SetPublicKey(byte[] publicKey)
+ {
+ return Set(PARAM_TYPE_PUBLIC_KEY, publicKey);
+ }
+
+ /// <summary>
+ /// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY_IDENTIFIER"/> parameter.
+ /// </summary>
+ public Builder SetKeyIdentifier(byte[] keyIdentifier)
+ {
+ return Set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
+ }
+
+ /// <summary>
+ /// Sets the <see cref="SkeinParameters.PARAM_TYPE_NONCE"/> parameter.
+ /// </summary>
+ public Builder SetNonce(byte[] nonce)
+ {
+ return Set(PARAM_TYPE_NONCE, nonce);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="SkeinParameters"/> instance with the parameters provided to this
+ /// builder.
+ /// </summary>
+ public SkeinParameters Build()
+ {
+ return new SkeinParameters(parameters);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 3c083034e..7d211e5dc 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -206,12 +206,52 @@ namespace Org.BouncyCastle.Utilities
return data == null ? null : (byte[]) data.Clone();
}
+ public static byte[] Clone(
+ byte[] data,
+ byte[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ return Clone(data);
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
public static int[] Clone(
int[] data)
{
return data == null ? null : (int[]) data.Clone();
}
+ [CLSCompliantAttribute(false)]
+ public static ulong[] Clone(
+ ulong[] data)
+ {
+ return data == null ? null : (ulong[]) data.Clone();
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static ulong[] Clone(
+ ulong[] data,
+ ulong[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ return Clone(data);
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
public static void Fill(
byte[] buf,
byte b)
|