diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs
index 4887b00b0..87f48dffa 100644
--- a/crypto/src/AssemblyInfo.cs
+++ b/crypto/src/AssemblyInfo.cs
@@ -18,7 +18,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Legion of the Bouncy Castle Inc.")]
[assembly: AssemblyProduct("Bouncy Castle for .NET")]
-[assembly: AssemblyCopyright("Copyright (C) 2000-2017")]
+[assembly: AssemblyCopyright("Copyright (C) 2000-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
index 8128b6952..d344393dd 100644
--- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -75,5 +75,14 @@ namespace Org.BouncyCastle.Asn1.Misc
public static readonly DerObjectIdentifier id_blake2b256 = blake2.Branch("1.8");
public static readonly DerObjectIdentifier id_blake2b384 = blake2.Branch("1.12");
public static readonly DerObjectIdentifier id_blake2b512 = blake2.Branch("1.16");
+
+ public static readonly DerObjectIdentifier id_blake2s128 = blake2.Branch("2.4");
+ public static readonly DerObjectIdentifier id_blake2s160 = blake2.Branch("2.5");
+ public static readonly DerObjectIdentifier id_blake2s224 = blake2.Branch("2.7");
+ public static readonly DerObjectIdentifier id_blake2s256 = blake2.Branch("2.8");
+
+ //
+ // Scrypt
+ public static readonly DerObjectIdentifier id_scrypt = new DerObjectIdentifier("1.3.6.1.4.1.11591.4.11");
}
}
diff --git a/crypto/src/asn1/ua/UAObjectIdentifiers.cs b/crypto/src/asn1/ua/UAObjectIdentifiers.cs
new file mode 100644
index 000000000..9beca3af5
--- /dev/null
+++ b/crypto/src/asn1/ua/UAObjectIdentifiers.cs
@@ -0,0 +1,107 @@
+namespace Org.BouncyCastle.Asn1.UA
+{
+ /**
+ * Ukrainian object identifiers
+ * <p>
+ * {iso(1) member-body(2) Ukraine(804) root(2) security(1) cryptography(1) pki(1)}
+ * <p>
+ * { ... pki-alg(1) pki-alg-sym(3) Dstu4145WithGost34311(1) PB(1)}
+ * <p>
+ * DSTU4145 in polynomial basis has 2 oids, one for little-endian representation and one for big-endian
+ */
+ public abstract class UAObjectIdentifiers
+ {
+ /** Base OID: 1.2.804.2.1.1.1 */
+ public static readonly DerObjectIdentifier UaOid = new DerObjectIdentifier("1.2.804.2.1.1.1");
+
+ /** DSTU4145 Little Endian presentation. OID: 1.2.804.2.1.1.1.1.3.1.1 */
+ public static readonly DerObjectIdentifier dstu4145le = UaOid.Branch("1.3.1.1");
+ /** DSTU4145 Big Endian presentation. OID: 1.2.804.2.1.1.1.1.3.1.1.1 */
+ public static readonly DerObjectIdentifier dstu4145be = UaOid.Branch("1.3.1.1.1.1");
+
+ /** DSTU7564 256-bit digest presentation. */
+ public static readonly DerObjectIdentifier dstu7564digest_256 = UaOid.Branch("1.2.2.1");
+ /** DSTU7564 384-bit digest presentation. */
+ public static readonly DerObjectIdentifier dstu7564digest_384 = UaOid.Branch("1.2.2.2");
+ /** DSTU7564 512-bit digest presentation. */
+ public static readonly DerObjectIdentifier dstu7564digest_512 = UaOid.Branch("1.2.2.3");
+
+ /** DSTU7564 256-bit mac presentation. */
+ public static readonly DerObjectIdentifier dstu7564mac_256 = UaOid.Branch("1.2.2.4");
+ /** DSTU7564 384-bit mac presentation. */
+ public static readonly DerObjectIdentifier dstu7564mac_384 = UaOid.Branch("1.2.2.5");
+ /** DSTU7564 512-bit mac presentation. */
+ public static readonly DerObjectIdentifier dstu7564mac_512 = UaOid.Branch("1.2.2.6");
+
+
+ /** DSTU7624 in ECB mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ecb_128 = UaOid.Branch("1.1.3.1.1");
+ /** DSTU7624 in ECB mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ecb_256 = UaOid.Branch("1.1.3.1.2");
+ /** DSTU7624 in ECB mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ecb_512 = UaOid.Branch("1.1.3.1.3");
+
+ /** DSTU7624 in CTR mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ctr_128 = UaOid.Branch("1.1.3.2.1");
+ /** DSTU7624 in CTR mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ctr_256 = UaOid.Branch("1.1.3.2.2");
+ /** DSTU7624 in CTR mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ctr_512 = UaOid.Branch("1.1.3.2.3");
+
+ /** DSTU7624 in CFB mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cfb_128 = UaOid.Branch("1.1.3.3.1");
+ /** DSTU7624 in CFB mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cfb_256 = UaOid.Branch("1.1.3.3.2");
+ /** DSTU7624 in CFB mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cfb_512 = UaOid.Branch("1.1.3.3.3");
+
+ /** DSTU7624 in MAC mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cmac_128 = UaOid.Branch("1.1.3.4.1");
+ /** DSTU7624 in MAC mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cmac_256 = UaOid.Branch("1.1.3.4.2");
+ /** DSTU7624 in MAC mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cmac_512 = UaOid.Branch("1.1.3.4.3");
+
+ /** DSTU7624 in CBC mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cbc_128 = UaOid.Branch("1.1.3.5.1");
+ /** DSTU7624 in CBC mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cbc_256 = UaOid.Branch("1.1.3.5.2");
+ /** DSTU7624 in CBC mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624cbc_512 = UaOid.Branch("1.1.3.5.3");
+
+ /** DSTU7624 in OFB mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ofb_128 = UaOid.Branch("1.1.3.6.1");
+ /** DSTU7624 in OFB mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ofb_256 = UaOid.Branch("1.1.3.6.2");
+ /** DSTU7624 in OFB mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ofb_512 = UaOid.Branch("1.1.3.6.3");
+
+ /** DSTU7624 in GMAC (GCM witout encryption) mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624gmac_128 = UaOid.Branch("1.1.3.7.1");
+ /** DSTU7624 in GMAC (GCM witout encryption) mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624gmac_256 = UaOid.Branch("1.1.3.7.2");
+ /** DSTU7624 in GMAC (GCM witout encryption) mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624gmac_512 = UaOid.Branch("1.1.3.7.3");
+
+ /** DSTU7624 in CCM mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ccm_128 = UaOid.Branch("1.1.3.8.1");
+ /** DSTU7624 in CCM mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ccm_256 = UaOid.Branch("1.1.3.8.2");
+ /** DSTU7624 in CCM mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624ccm_512 = UaOid.Branch("1.1.3.8.3");
+
+ /** DSTU7624 in XTS mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624xts_128 = UaOid.Branch("1.1.3.9.1");
+ /** DSTU7624 in XTS mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624xts_256 = UaOid.Branch("1.1.3.9.2");
+ /** DSTU7624 in XTS mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624xts_512 = UaOid.Branch("1.1.3.9.3");
+
+ /** DSTU7624 in key wrap (KW) mode with 128 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624kw_128 = UaOid.Branch("1.1.3.10.1");
+ /** DSTU7624 in key wrap (KW) mode with 256 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624kw_256 = UaOid.Branch("1.1.3.10.2");
+ /** DSTU7624 in key wrap (KW) mode with 512 bit block/key presentation */
+ public static readonly DerObjectIdentifier dstu7624kw_512 = UaOid.Branch("1.1.3.10.3");
+ }
+}
diff --git a/crypto/src/crypto/digests/Blake2bDigest.cs b/crypto/src/crypto/digests/Blake2bDigest.cs
new file mode 100644
index 000000000..b8e4f272e
--- /dev/null
+++ b/crypto/src/crypto/digests/Blake2bDigest.cs
@@ -0,0 +1,531 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /* The BLAKE2 cryptographic hash function was designed by Jean-
+ Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian
+ Winnerlein.
+
+ Reference Implementation and Description can be found at: https://blake2.net/
+ Internet Draft: https://tools.ietf.org/html/draft-saarinen-blake2-02
+
+ This implementation does not support the Tree Hashing Mode.
+
+ For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based
+ message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2.
+
+ Algorithm | Target | Collision | Hash | Hash ASN.1 |
+ Identifier | Arch | Security | nn | OID Suffix |
+ ---------------+--------+-----------+------+------------+
+ id-blake2b160 | 64-bit | 2**80 | 20 | x.1.20 |
+ id-blake2b256 | 64-bit | 2**128 | 32 | x.1.32 |
+ id-blake2b384 | 64-bit | 2**192 | 48 | x.1.48 |
+ id-blake2b512 | 64-bit | 2**256 | 64 | x.1.64 |
+ ---------------+--------+-----------+------+------------+
+ */
+
+ /**
+ * Implementation of the cryptographic hash function Blakbe2b.
+ * <p>
+ * Blake2b offers a built-in keying mechanism to be used directly
+ * for authentication ("Prefix-MAC") rather than a HMAC construction.
+ * <p>
+ * Blake2b offers a built-in support for a salt for randomized hashing
+ * and a personal string for defining a unique hash function for each application.
+ * <p>
+ * BLAKE2b is optimized for 64-bit platforms and produces digests of any size
+ * between 1 and 64 bytes.
+ */
+ public class Blake2bDigest
+ : IDigest
+ {
+ // Blake2b Initialization Vector:
+ private static readonly ulong[] blake2b_IV =
+ // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19.
+ // The same as SHA-512 IV.
+ {
+ 0x6a09e667f3bcc908UL, 0xbb67ae8584caa73bUL, 0x3c6ef372fe94f82bUL,
+ 0xa54ff53a5f1d36f1UL, 0x510e527fade682d1UL, 0x9b05688c2b3e6c1fUL,
+ 0x1f83d9abfb41bd6bUL, 0x5be0cd19137e2179UL
+ };
+
+ // Message word permutations:
+ private static readonly byte[,] blake2b_sigma =
+ {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
+ };
+
+ private const int ROUNDS = 12; // to use for Catenas H'
+ private const int BLOCK_LENGTH_BYTES = 128;// bytes
+
+ // General parameters:
+ private int digestLength = 64; // 1- 64 bytes
+ private int keyLength = 0; // 0 - 64 bytes for keyed hashing for MAC
+ private byte[] salt = null;// new byte[16];
+ private byte[] personalization = null;// new byte[16];
+
+ // the key
+ private byte[] key = null;
+
+ // Tree hashing parameters:
+ // Because this class does not implement the Tree Hashing Mode,
+ // these parameters can be treated as constants (see init() function)
+ /*
+ * private int fanout = 1; // 0-255 private int depth = 1; // 1 - 255
+ * private int leafLength= 0; private long nodeOffset = 0L; private int
+ * nodeDepth = 0; private int innerHashLength = 0;
+ */
+
+ // whenever this buffer overflows, it will be processed
+ // in the Compress() function.
+ // For performance issues, long messages will not use this buffer.
+ private byte[] buffer = null;// new byte[BLOCK_LENGTH_BYTES];
+ // Position of last inserted byte:
+ private int bufferPos = 0;// a value from 0 up to 128
+
+ private ulong[] internalState = new ulong[16]; // In the Blake2b paper it is
+ // called: v
+ private ulong[] chainValue = null; // state vector, in the Blake2b paper it
+ // is called: h
+
+ private ulong t0 = 0UL; // holds last significant bits, counter (counts bytes)
+ private ulong t1 = 0UL; // counter: Length up to 2^128 are supported
+ private ulong f0 = 0UL; // finalization flag, for last block: ~0L
+
+ // For Tree Hashing Mode, not used here:
+ // private long f1 = 0L; // finalization flag, for last node: ~0L
+
+ public Blake2bDigest()
+ : this(512)
+ {
+ }
+
+ public Blake2bDigest(Blake2bDigest digest)
+ {
+ this.bufferPos = digest.bufferPos;
+ this.buffer = Arrays.Clone(digest.buffer);
+ this.keyLength = digest.keyLength;
+ this.key = Arrays.Clone(digest.key);
+ this.digestLength = digest.digestLength;
+ this.chainValue = Arrays.Clone(digest.chainValue);
+ this.personalization = Arrays.Clone(digest.personalization);
+ this.salt = Arrays.Clone(digest.salt);
+ this.t0 = digest.t0;
+ this.t1 = digest.t1;
+ this.f0 = digest.f0;
+ }
+
+ /**
+ * Basic sized constructor - size in bits.
+ *
+ * @param digestSize size of the digest in bits
+ */
+ public Blake2bDigest(int digestSize)
+ {
+ if (digestSize != 160 && digestSize != 256 && digestSize != 384 && digestSize != 512)
+ throw new ArgumentException("BLAKE2b digest restricted to one of [160, 256, 384, 512]");
+
+ buffer = new byte[BLOCK_LENGTH_BYTES];
+ keyLength = 0;
+ this.digestLength = digestSize / 8;
+ Init();
+ }
+
+ /**
+ * Blake2b for authentication ("Prefix-MAC mode").
+ * After calling the doFinal() method, the key will
+ * remain to be used for further computations of
+ * this instance.
+ * The key can be overwritten using the clearKey() method.
+ *
+ * @param key A key up to 64 bytes or null
+ */
+ public Blake2bDigest(byte[] key)
+ {
+ buffer = new byte[BLOCK_LENGTH_BYTES];
+ if (key != null)
+ {
+ this.key = new byte[key.Length];
+ Array.Copy(key, 0, this.key, 0, key.Length);
+
+ if (key.Length > 64)
+ throw new ArgumentException("Keys > 64 are not supported");
+
+ keyLength = key.Length;
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ digestLength = 64;
+ Init();
+ }
+
+ /**
+ * Blake2b with key, required digest length (in bytes), salt and personalization.
+ * After calling the doFinal() method, the key, the salt and the personal string
+ * will remain and might be used for further computations with this instance.
+ * The key can be overwritten using the clearKey() method, the salt (pepper)
+ * can be overwritten using the clearSalt() method.
+ *
+ * @param key A key up to 64 bytes or null
+ * @param digestLength from 1 up to 64 bytes
+ * @param salt 16 bytes or null
+ * @param personalization 16 bytes or null
+ */
+ public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization)
+ {
+ if (digestLength < 1 || digestLength > 64)
+ throw new ArgumentException("Invalid digest length (required: 1 - 64)");
+
+ this.digestLength = digestLength;
+ this.buffer = new byte[BLOCK_LENGTH_BYTES];
+
+ if (salt != null)
+ {
+ if (salt.Length != 16)
+ throw new ArgumentException("salt length must be exactly 16 bytes");
+
+ this.salt = new byte[16];
+ Array.Copy(salt, 0, this.salt, 0, salt.Length);
+ }
+ if (personalization != null)
+ {
+ if (personalization.Length != 16)
+ throw new ArgumentException("personalization length must be exactly 16 bytes");
+
+ this.personalization = new byte[16];
+ Array.Copy(personalization, 0, this.personalization, 0, personalization.Length);
+ }
+ if (key != null)
+ {
+ if (key.Length > 64)
+ throw new ArgumentException("Keys > 64 are not supported");
+
+ this.key = new byte[key.Length];
+ Array.Copy(key, 0, this.key, 0, key.Length);
+
+ keyLength = key.Length;
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ Init();
+ }
+
+ // initialize chainValue
+ private void Init()
+ {
+ if (chainValue == null)
+ {
+ chainValue = new ulong[8];
+
+ chainValue[0] = blake2b_IV[0] ^ (ulong)(digestLength | (keyLength << 8) | 0x1010000);
+
+ // 0x1010000 = ((fanout << 16) | (depth << 24) | (leafLength <<
+ // 32));
+ // with fanout = 1; depth = 0; leafLength = 0;
+ chainValue[1] = blake2b_IV[1];// ^ nodeOffset; with nodeOffset = 0;
+ chainValue[2] = blake2b_IV[2];// ^ ( nodeDepth | (innerHashLength << 8) );
+ // with nodeDepth = 0; innerHashLength = 0;
+
+ chainValue[3] = blake2b_IV[3];
+
+ chainValue[4] = blake2b_IV[4];
+ chainValue[5] = blake2b_IV[5];
+ if (salt != null)
+ {
+ chainValue[4] ^= Pack.LE_To_UInt64(salt, 0);
+ chainValue[5] ^= Pack.LE_To_UInt64(salt, 8);
+ }
+
+ chainValue[6] = blake2b_IV[6];
+ chainValue[7] = blake2b_IV[7];
+ if (personalization != null)
+ {
+ chainValue[6] ^= Pack.LE_To_UInt64(personalization, 0);
+ chainValue[7] ^= Pack.LE_To_UInt64(personalization, 8);
+ }
+ }
+ }
+
+ private void InitializeInternalState()
+ {
+ // initialize v:
+ Array.Copy(chainValue, 0, internalState, 0, chainValue.Length);
+ Array.Copy(blake2b_IV, 0, internalState, chainValue.Length, 4);
+ internalState[12] = t0 ^ blake2b_IV[4];
+ internalState[13] = t1 ^ blake2b_IV[5];
+ internalState[14] = f0 ^ blake2b_IV[6];
+ internalState[15] = blake2b_IV[7];// ^ f1 with f1 = 0
+ }
+
+ /**
+ * update the message digest with a single byte.
+ *
+ * @param b the input byte to be entered.
+ */
+ public virtual void Update(byte b)
+ {
+ int remainingLength = 0; // left bytes of buffer
+
+ // process the buffer if full else add to buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength == 0)
+ { // full buffer
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^64
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ buffer[0] = b;
+ bufferPos = 1;
+ }
+ else
+ {
+ buffer[bufferPos] = b;
+ bufferPos++;
+ return;
+ }
+ }
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param message the byte array containing the data.
+ * @param offset the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ public virtual void BlockUpdate(byte[] message, int offset, int len)
+ {
+ if (message == null || len == 0)
+ return;
+
+ int remainingLength = 0; // left bytes of buffer
+
+ if (bufferPos != 0)
+ { // commenced, incomplete buffer
+
+ // complete the buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength < len)
+ { // full buffer + at least 1 byte
+ Array.Copy(message, offset, buffer, bufferPos,
+ remainingLength);
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^64
+ t1++;
+ }
+ Compress(buffer, 0);
+ bufferPos = 0;
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ }
+ else
+ {
+ Array.Copy(message, offset, buffer, bufferPos, len);
+ bufferPos += len;
+ return;
+ }
+ }
+
+ // process blocks except last block (also if last block is full)
+ int messagePos;
+ int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES;
+ for (messagePos = offset + remainingLength; messagePos < blockWiseLastPos; messagePos += BLOCK_LENGTH_BYTES)
+ { // block wise 128 bytes
+ // without buffer:
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ {
+ t1++;
+ }
+ Compress(message, messagePos);
+ }
+
+ // fill the buffer with left bytes, this might be a full block
+ Array.Copy(message, messagePos, buffer, 0, offset + len
+ - messagePos);
+ bufferPos += offset + len - messagePos;
+ }
+
+ /**
+ * close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ * Key, salt and personal string remain.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOffset the offset into the out array the digest is to start at.
+ */
+ public virtual int DoFinal(byte[] output, int outOffset)
+ {
+ f0 = 0xFFFFFFFFFFFFFFFFUL;
+ t0 += (ulong)bufferPos;
+ if (bufferPos > 0 && t0 == 0)
+ {
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
+ Array.Clear(internalState, 0, internalState.Length);
+
+ for (int i = 0; i < chainValue.Length && (i * 8 < digestLength); i++)
+ {
+ byte[] bytes = Pack.UInt64_To_LE(chainValue[i]);
+
+ if (i * 8 < digestLength - 8)
+ {
+ Array.Copy(bytes, 0, output, outOffset + i * 8, 8);
+ }
+ else
+ {
+ Array.Copy(bytes, 0, output, outOffset + i * 8, digestLength - (i * 8));
+ }
+ }
+
+ Array.Clear(chainValue, 0, chainValue.Length);
+
+ Reset();
+
+ return digestLength;
+ }
+
+ /**
+ * Reset the digest back to it's initial state.
+ * The key, the salt and the personal string will
+ * remain for further computations.
+ */
+ public virtual void Reset()
+ {
+ bufferPos = 0;
+ f0 = 0L;
+ t0 = 0L;
+ t1 = 0L;
+ chainValue = null;
+ Array.Clear(buffer, 0, buffer.Length);
+ if (key != null)
+ {
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ Init();
+ }
+
+ private void Compress(byte[] message, int messagePos)
+ {
+ InitializeInternalState();
+
+ ulong[] m = new ulong[16];
+ for (int j = 0; j < 16; j++)
+ {
+ m[j] = Pack.LE_To_UInt64(message, messagePos + j * 8);
+ }
+
+ for (int round = 0; round < ROUNDS; round++)
+ {
+ // G apply to columns of internalState:m[blake2b_sigma[round][2 * blockPos]] /+1
+ G(m[blake2b_sigma[round,0]], m[blake2b_sigma[round,1]], 0, 4, 8, 12);
+ G(m[blake2b_sigma[round,2]], m[blake2b_sigma[round,3]], 1, 5, 9, 13);
+ G(m[blake2b_sigma[round,4]], m[blake2b_sigma[round,5]], 2, 6, 10, 14);
+ G(m[blake2b_sigma[round,6]], m[blake2b_sigma[round,7]], 3, 7, 11, 15);
+ // G apply to diagonals of internalState:
+ G(m[blake2b_sigma[round,8]], m[blake2b_sigma[round,9]], 0, 5, 10, 15);
+ G(m[blake2b_sigma[round,10]], m[blake2b_sigma[round,11]], 1, 6, 11, 12);
+ G(m[blake2b_sigma[round,12]], m[blake2b_sigma[round,13]], 2, 7, 8, 13);
+ G(m[blake2b_sigma[round,14]], m[blake2b_sigma[round,15]], 3, 4, 9, 14);
+ }
+
+ // update chain values:
+ for (int offset = 0; offset < chainValue.Length; offset++)
+ {
+ chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
+ }
+ }
+
+ private void G(ulong m1, ulong m2, int posA, int posB, int posC, int posD)
+ {
+ internalState[posA] = internalState[posA] + internalState[posB] + m1;
+ internalState[posD] = Rotr64(internalState[posD] ^ internalState[posA], 32);
+ internalState[posC] = internalState[posC] + internalState[posD];
+ internalState[posB] = Rotr64(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE
+ internalState[posA] = internalState[posA] + internalState[posB] + m2;
+ internalState[posD] = Rotr64(internalState[posD] ^ internalState[posA], 16);
+ internalState[posC] = internalState[posC] + internalState[posD];
+ internalState[posB] = Rotr64(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE
+ }
+
+ private static ulong Rotr64(ulong x, int rot)
+ {
+ return x >> rot | x << -rot;
+ }
+
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public virtual string AlgorithmName
+ {
+ get { return "BLAKE2b"; }
+ }
+
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ public virtual int GetDigestSize()
+ {
+ return digestLength;
+ }
+
+ /**
+ * Return the size in bytes of the internal buffer the digest applies it's compression
+ * function to.
+ *
+ * @return byte length of the digests internal buffer.
+ */
+ public virtual int GetByteLength()
+ {
+ return BLOCK_LENGTH_BYTES;
+ }
+
+ /**
+ * Overwrite the key
+ * if it is no longer used (zeroization)
+ */
+ public virtual void ClearKey()
+ {
+ if (key != null)
+ {
+ Array.Clear(key, 0, key.Length);
+ Array.Clear(buffer, 0, buffer.Length);
+ }
+ }
+
+ /**
+ * Overwrite the salt (pepper) if it
+ * is secret and no longer used (zeroization)
+ */
+ public virtual void ClearSalt()
+ {
+ if (salt != null)
+ {
+ Array.Clear(salt, 0, salt.Length);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/Blake2sDigest.cs b/crypto/src/crypto/digests/Blake2sDigest.cs
new file mode 100644
index 000000000..f31032874
--- /dev/null
+++ b/crypto/src/crypto/digests/Blake2sDigest.cs
@@ -0,0 +1,552 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /*
+ The BLAKE2 cryptographic hash function was designed by Jean-
+ Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian
+ Winnerlein.
+
+ Reference Implementation and Description can be found at: https://blake2.net/
+ RFC: https://tools.ietf.org/html/rfc7693
+
+ This implementation does not support the Tree Hashing Mode.
+
+ For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based
+ message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2.
+
+ Algorithm | Target | Collision | Hash | Hash ASN.1 |
+ Identifier | Arch | Security | nn | OID Suffix |
+ ---------------+--------+-----------+------+------------+
+ id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 |
+ id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 |
+ id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 |
+ id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 |
+ ---------------+--------+-----------+------+------------+
+ */
+
+ /**
+ * Implementation of the cryptographic hash function BLAKE2s.
+ * <p/>
+ * BLAKE2s offers a built-in keying mechanism to be used directly
+ * for authentication ("Prefix-MAC") rather than a HMAC construction.
+ * <p/>
+ * BLAKE2s offers a built-in support for a salt for randomized hashing
+ * and a personal string for defining a unique hash function for each application.
+ * <p/>
+ * BLAKE2s is optimized for 32-bit platforms and produces digests of any size
+ * between 1 and 32 bytes.
+ */
+ public class Blake2sDigest
+ : IDigest
+ {
+ /**
+ * BLAKE2s Initialization Vector
+ **/
+ private static readonly uint[] blake2s_IV =
+ // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19.
+ // The same as SHA-256 IV.
+ {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372,
+ 0xa54ff53a, 0x510e527f, 0x9b05688c,
+ 0x1f83d9ab, 0x5be0cd19
+ };
+
+ /**
+ * Message word permutations
+ **/
+ private static readonly byte[,] blake2s_sigma =
+ {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
+ };
+
+ private const int ROUNDS = 10; // to use for Catenas H'
+ private const int BLOCK_LENGTH_BYTES = 64;// bytes
+
+ // General parameters:
+ private int digestLength = 32; // 1- 32 bytes
+ private int keyLength = 0; // 0 - 32 bytes for keyed hashing for MAC
+ private byte[] salt = null;
+ private byte[] personalization = null;
+ private byte[] key = null;
+
+ // Tree hashing parameters:
+ // Because this class does not implement the Tree Hashing Mode,
+ // these parameters can be treated as constants (see Init() function)
+ /*
+ * private int fanout = 1; // 0-255
+ * private int depth = 1; // 1 - 255
+ * private int leafLength= 0;
+ * private long nodeOffset = 0L;
+ * private int nodeDepth = 0;
+ * private int innerHashLength = 0;
+ */
+
+ /**
+ * Whenever this buffer overflows, it will be processed in the Compress()
+ * function. For performance issues, long messages will not use this buffer.
+ */
+ private byte[] buffer = null;
+ /**
+ * Position of last inserted byte
+ **/
+ private int bufferPos = 0;// a value from 0 up to BLOCK_LENGTH_BYTES
+
+ /**
+ * Internal state, in the BLAKE2 paper it is called v
+ **/
+ private uint[] internalState = new uint[16];
+ /**
+ * State vector, in the BLAKE2 paper it is called h
+ **/
+ private uint[] chainValue = null;
+
+ // counter (counts bytes): Length up to 2^64 are supported
+ /**
+ * holds least significant bits of counter
+ **/
+ private uint t0 = 0;
+ /**
+ * holds most significant bits of counter
+ **/
+ private uint t1 = 0;
+ /**
+ * finalization flag, for last block: ~0
+ **/
+ private uint f0 = 0;
+
+ // For Tree Hashing Mode, not used here:
+ // private long f1 = 0L; // finalization flag, for last node: ~0L
+
+ /**
+ * BLAKE2s-256 for hashing.
+ */
+ public Blake2sDigest()
+ : this(256)
+ {
+ }
+
+ public Blake2sDigest(Blake2sDigest digest)
+ {
+ this.bufferPos = digest.bufferPos;
+ this.buffer = Arrays.Clone(digest.buffer);
+ this.keyLength = digest.keyLength;
+ this.key = Arrays.Clone(digest.key);
+ this.digestLength = digest.digestLength;
+ this.chainValue = Arrays.Clone(digest.chainValue);
+ this.personalization = Arrays.Clone(digest.personalization);
+ }
+
+ /**
+ * BLAKE2s for hashing.
+ *
+ * @param digestBits the desired digest length in bits. Must be one of
+ * [128, 160, 224, 256].
+ */
+ public Blake2sDigest(int digestBits)
+ {
+ if (digestBits != 128 && digestBits != 160 && digestBits != 224 && digestBits != 256)
+ throw new ArgumentException("BLAKE2s digest restricted to one of [128, 160, 224, 256]");
+
+ buffer = new byte[BLOCK_LENGTH_BYTES];
+ keyLength = 0;
+ digestLength = digestBits / 8;
+ Init();
+ }
+
+ /**
+ * BLAKE2s for authentication ("Prefix-MAC mode").
+ * <p/>
+ * After calling the doFinal() method, the key will remain to be used for
+ * further computations of this instance. The key can be overwritten using
+ * the clearKey() method.
+ *
+ * @param key a key up to 32 bytes or null
+ */
+ public Blake2sDigest(byte[] key)
+ {
+ buffer = new byte[BLOCK_LENGTH_BYTES];
+ if (key != null)
+ {
+ if (key.Length > 32)
+ throw new ArgumentException("Keys > 32 are not supported");
+
+ this.key = new byte[key.Length];
+ Array.Copy(key, 0, this.key, 0, key.Length);
+
+ keyLength = key.Length;
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ digestLength = 32;
+ Init();
+ }
+
+ /**
+ * BLAKE2s with key, required digest length, salt and personalization.
+ * <p/>
+ * After calling the doFinal() method, the key, the salt and the personal
+ * string will remain and might be used for further computations with this
+ * instance. The key can be overwritten using the clearKey() method, the
+ * salt (pepper) can be overwritten using the clearSalt() method.
+ *
+ * @param key a key up to 32 bytes or null
+ * @param digestBytes from 1 up to 32 bytes
+ * @param salt 8 bytes or null
+ * @param personalization 8 bytes or null
+ */
+ public Blake2sDigest(byte[] key, int digestBytes, byte[] salt,
+ byte[] personalization)
+ {
+ if (digestBytes < 1 || digestBytes > 32)
+ throw new ArgumentException("Invalid digest length (required: 1 - 32)");
+
+ this.digestLength = digestBytes;
+ this.buffer = new byte[BLOCK_LENGTH_BYTES];
+
+ if (salt != null)
+ {
+ if (salt.Length != 8)
+ throw new ArgumentException("Salt length must be exactly 8 bytes");
+
+ this.salt = new byte[8];
+ Array.Copy(salt, 0, this.salt, 0, salt.Length);
+ }
+ if (personalization != null)
+ {
+ if (personalization.Length != 8)
+ throw new ArgumentException("Personalization length must be exactly 8 bytes");
+
+ this.personalization = new byte[8];
+ Array.Copy(personalization, 0, this.personalization, 0, personalization.Length);
+ }
+ if (key != null)
+ {
+ if (key.Length > 32)
+ throw new ArgumentException("Keys > 32 bytes are not supported");
+
+ this.key = new byte[key.Length];
+ Array.Copy(key, 0, this.key, 0, key.Length);
+
+ keyLength = key.Length;
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ Init();
+ }
+
+ // initialize chainValue
+ private void Init()
+ {
+ if (chainValue == null)
+ {
+ chainValue = new uint[8];
+
+ chainValue[0] = blake2s_IV[0] ^ (uint)(digestLength | (keyLength << 8) | 0x1010000);
+ // 0x1010000 = ((fanout << 16) | (depth << 24));
+ // with fanout = 1; depth = 0;
+ chainValue[1] = blake2s_IV[1];// ^ leafLength; with leafLength = 0;
+ chainValue[2] = blake2s_IV[2];// ^ nodeOffset; with nodeOffset = 0;
+ chainValue[3] = blake2s_IV[3];// ^ ( (nodeOffset << 32) | (nodeDepth << 16) | (innerHashLength << 24) );
+ // with nodeDepth = 0; innerHashLength = 0;
+
+ chainValue[4] = blake2s_IV[4];
+ chainValue[5] = blake2s_IV[5];
+ if (salt != null)
+ {
+ chainValue[4] ^= Pack.LE_To_UInt32(salt, 0);
+ chainValue[5] ^= Pack.LE_To_UInt32(salt, 4);
+ }
+
+ chainValue[6] = blake2s_IV[6];
+ chainValue[7] = blake2s_IV[7];
+ if (personalization != null)
+ {
+ chainValue[6] ^= Pack.LE_To_UInt32(personalization, 0);
+ chainValue[7] ^= Pack.LE_To_UInt32(personalization, 4);
+ }
+ }
+ }
+
+ private void InitializeInternalState()
+ {
+ // initialize v:
+ Array.Copy(chainValue, 0, internalState, 0, chainValue.Length);
+ Array.Copy(blake2s_IV, 0, internalState, chainValue.Length, 4);
+ internalState[12] = t0 ^ blake2s_IV[4];
+ internalState[13] = t1 ^ blake2s_IV[5];
+ internalState[14] = f0 ^ blake2s_IV[6];
+ internalState[15] = blake2s_IV[7];// ^ f1 with f1 = 0
+ }
+
+ /**
+ * Update the message digest with a single byte.
+ *
+ * @param b the input byte to be entered.
+ */
+ public virtual void Update(byte b)
+ {
+ int remainingLength; // left bytes of buffer
+
+ // process the buffer if full else add to buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength == 0)
+ { // full buffer
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^32
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ buffer[0] = b;
+ bufferPos = 1;
+ }
+ else
+ {
+ buffer[bufferPos] = b;
+ bufferPos++;
+ }
+ }
+
+ /**
+ * Update the message digest with a block of bytes.
+ *
+ * @param message the byte array containing the data.
+ * @param offset the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ public virtual void BlockUpdate(byte[] message, int offset, int len)
+ {
+ if (message == null || len == 0)
+ return;
+
+ int remainingLength = 0; // left bytes of buffer
+
+ if (bufferPos != 0)
+ { // commenced, incomplete buffer
+
+ // complete the buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength < len)
+ { // full buffer + at least 1 byte
+ Array.Copy(message, offset, buffer, bufferPos, remainingLength);
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^32
+ t1++;
+ }
+ Compress(buffer, 0);
+ bufferPos = 0;
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ }
+ else
+ {
+ Array.Copy(message, offset, buffer, bufferPos, len);
+ bufferPos += len;
+ return;
+ }
+ }
+
+ // process blocks except last block (also if last block is full)
+ int messagePos;
+ int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES;
+ for (messagePos = offset + remainingLength;
+ messagePos < blockWiseLastPos;
+ messagePos += BLOCK_LENGTH_BYTES)
+ { // block wise 64 bytes
+ // without buffer:
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ {
+ t1++;
+ }
+ Compress(message, messagePos);
+ }
+
+ // fill the buffer with left bytes, this might be a full block
+ Array.Copy(message, messagePos, buffer, 0, offset + len
+ - messagePos);
+ bufferPos += offset + len - messagePos;
+ }
+
+ /**
+ * Close the digest, producing the final digest value. The doFinal() call
+ * leaves the digest reset. Key, salt and personal string remain.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOffset the offset into the out array the digest is to start at.
+ */
+ public virtual int DoFinal(byte[] output, int outOffset)
+ {
+ f0 = 0xFFFFFFFFU;
+ t0 += (uint)bufferPos;
+ // bufferPos may be < 64, so (t0 == 0) does not work
+ // for 2^32 < message length > 2^32 - 63
+ if ((t0 < 0) && (bufferPos > -t0))
+ {
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
+ Array.Clear(internalState, 0, internalState.Length);
+
+ for (int i = 0; i < chainValue.Length && (i * 4 < digestLength); i++)
+ {
+ byte[] bytes = Pack.UInt32_To_LE(chainValue[i]);
+
+ if (i * 4 < digestLength - 4)
+ {
+ Array.Copy(bytes, 0, output, outOffset + i * 4, 4);
+ }
+ else
+ {
+ Array.Copy(bytes, 0, output, outOffset + i * 4, digestLength - (i * 4));
+ }
+ }
+
+ Array.Clear(chainValue, 0, chainValue.Length);
+
+ Reset();
+
+ return digestLength;
+ }
+
+ /**
+ * Reset the digest back to its initial state. The key, the salt and the
+ * personal string will remain for further computations.
+ */
+ public virtual void Reset()
+ {
+ bufferPos = 0;
+ f0 = 0;
+ t0 = 0;
+ t1 = 0;
+ chainValue = null;
+ Array.Clear(buffer, 0, buffer.Length);
+ if (key != null)
+ {
+ Array.Copy(key, 0, buffer, 0, key.Length);
+ bufferPos = BLOCK_LENGTH_BYTES; // zero padding
+ }
+ Init();
+ }
+
+ private void Compress(byte[] message, int messagePos)
+ {
+ InitializeInternalState();
+
+ uint[] m = new uint[16];
+ for (int j = 0; j < 16; j++)
+ {
+ m[j] = Pack.LE_To_UInt32(message, messagePos + j * 4);
+ }
+
+ for (int round = 0; round < ROUNDS; round++)
+ {
+
+ // G apply to columns of internalState:m[blake2s_sigma[round][2 *
+ // blockPos]] /+1
+ G(m[blake2s_sigma[round,0]], m[blake2s_sigma[round,1]], 0, 4, 8, 12);
+ G(m[blake2s_sigma[round,2]], m[blake2s_sigma[round,3]], 1, 5, 9, 13);
+ G(m[blake2s_sigma[round,4]], m[blake2s_sigma[round,5]], 2, 6, 10, 14);
+ G(m[blake2s_sigma[round,6]], m[blake2s_sigma[round,7]], 3, 7, 11, 15);
+ // G apply to diagonals of internalState:
+ G(m[blake2s_sigma[round,8]], m[blake2s_sigma[round,9]], 0, 5, 10, 15);
+ G(m[blake2s_sigma[round,10]], m[blake2s_sigma[round,11]], 1, 6, 11, 12);
+ G(m[blake2s_sigma[round,12]], m[blake2s_sigma[round,13]], 2, 7, 8, 13);
+ G(m[blake2s_sigma[round,14]], m[blake2s_sigma[round,15]], 3, 4, 9, 14);
+ }
+
+ // update chain values:
+ for (int offset = 0; offset < chainValue.Length; offset++)
+ {
+ chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
+ }
+ }
+
+ private void G(uint m1, uint m2, int posA, int posB, int posC, int posD)
+ {
+ internalState[posA] = internalState[posA] + internalState[posB] + m1;
+ internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 16);
+ internalState[posC] = internalState[posC] + internalState[posD];
+ internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 12);
+ internalState[posA] = internalState[posA] + internalState[posB] + m2;
+ internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 8);
+ internalState[posC] = internalState[posC] + internalState[posD];
+ internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 7);
+ }
+
+ private uint rotr32(uint x, int rot)
+ {
+ return x >> rot | x << -rot;
+ }
+
+ /**
+ * Return the algorithm name.
+ *
+ * @return the algorithm name
+ */
+ public virtual string AlgorithmName
+ {
+ get { return "BLAKE2s"; }
+ }
+
+ /**
+ * Return the size in bytes of the digest produced by this message digest.
+ *
+ * @return the size in bytes of the digest produced by this message digest.
+ */
+ public virtual int GetDigestSize()
+ {
+ return digestLength;
+ }
+
+ /**
+ * Return the size in bytes of the internal buffer the digest applies its
+ * compression function to.
+ *
+ * @return byte length of the digest's internal buffer.
+ */
+ public virtual int GetByteLength()
+ {
+ return BLOCK_LENGTH_BYTES;
+ }
+
+ /**
+ * Overwrite the key if it is no longer used (zeroization).
+ */
+ public virtual void ClearKey()
+ {
+ if (key != null)
+ {
+ Array.Clear(key, 0, key.Length);
+ Array.Clear(buffer, 0, buffer.Length);
+ }
+ }
+
+ /**
+ * Overwrite the salt (pepper) if it is secret and no longer used
+ * (zeroization).
+ */
+ public virtual void ClearSalt()
+ {
+ if (salt != null)
+ {
+ Array.Clear(salt, 0, salt.Length);
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs
index e641af6c2..b2d90799d 100644
--- a/crypto/src/crypto/digests/DSTU7564Digest.cs
+++ b/crypto/src/crypto/digests/DSTU7564Digest.cs
@@ -3,38 +3,36 @@
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
-//using Org.BouncyCastle.Utilities;
-
-using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Digests
{
/**
* implementation of Ukrainian DSTU 7564 hash function
*/
- public class Dstu7564Digest : IDigest, IMemoable
+ public class Dstu7564Digest
+ : IDigest, IMemoable
{
- private const int ROWS = 8;
- private const int BITS_IN_BYTE = 8;
-
private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code.
private const int NB_1024 = 16; //Number of 8-byte words in state for <=512-bit hash code.
private const int NR_512 = 10; //Number of rounds for 512-bit state.
private const int NR_1024 = 14; //Number of rounds for 1024-bit state.
- private const int STATE_BYTE_SIZE_512 = ROWS * NB_512;
- private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024;
-
private int hashSize;
private int blockSize;
+
private int columns;
private int rounds;
- private byte[] padded_;
- private byte[][] state_;
- private ulong inputLength;
+
+ private ulong[] state;
+ private ulong[] tempState1;
+ private ulong[] tempState2;
+
+ // TODO Guard against 'inputBlocks' overflow (2^64 blocks)
+ private ulong inputBlocks;
private int bufOff;
private byte[] buf;
@@ -48,20 +46,23 @@ namespace Org.BouncyCastle.Crypto.Digests
this.hashSize = digest.hashSize;
this.blockSize = digest.blockSize;
- this.columns = digest.columns;
this.rounds = digest.rounds;
-
- this.padded_ = Arrays.Clone(digest.padded_);
- this.state_ = new byte[digest.state_.Length][];
-
- for (int i = 0; i != this.state_.Length; i++)
+ if (columns > 0 && columns == digest.columns)
{
- this.state_[i] = Arrays.Clone(digest.state_[i]);
+ Array.Copy(digest.state, 0, state, 0, columns);
+ Array.Copy(digest.buf, 0, buf, 0, blockSize);
+ }
+ else
+ {
+ this.columns = digest.columns;
+ this.state = Arrays.Clone(digest.state);
+ this.tempState1 = new ulong[columns];
+ this.tempState2 = new ulong[columns];
+ this.buf = Arrays.Clone(digest.buf);
}
- this.inputLength = digest.inputLength;
+ this.inputBlocks = digest.inputBlocks;
this.bufOff = digest.bufOff;
- this.buf = Arrays.Clone(digest.buf);
}
public Dstu7564Digest(int hashSizeBits)
@@ -72,34 +73,28 @@ namespace Org.BouncyCastle.Crypto.Digests
}
else
{
- throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size");
+ throw new ArgumentException("Hash size is not recommended. Use 256/384/512 instead");
}
if (hashSizeBits > 256)
{
- this.blockSize = 1024 / 8;
this.columns = NB_1024;
this.rounds = NR_1024;
- this.state_ = new byte[STATE_BYTE_SIZE_1024][];
}
else
{
- this.blockSize = 512 / 8;
this.columns = NB_512;
this.rounds = NR_512;
- this.state_ = new byte[STATE_BYTE_SIZE_512][];
}
- for (int i = 0; i < state_.Length; i++)
- {
- this.state_[i] = new byte[columns];
- }
+ this.blockSize = columns << 3;
- this.state_[0][0] = (byte)state_.Length;
+ this.state = new ulong[columns];
+ this.state[0] = (ulong)blockSize;
- this.hashSize = hashSizeBits / 8;
+ this.tempState1 = new ulong[columns];
+ this.tempState2 = new ulong[columns];
- this.padded_ = null;
this.buf = new byte[blockSize];
}
@@ -108,128 +103,104 @@ namespace Org.BouncyCastle.Crypto.Digests
get { return "DSTU7564"; }
}
+ public virtual int GetDigestSize()
+ {
+ return hashSize;
+ }
+
+ public virtual int GetByteLength()
+ {
+ return blockSize;
+ }
+
+ public virtual void Update(byte input)
+ {
+ buf[bufOff++] = input;
+ if (bufOff == blockSize)
+ {
+ ProcessBlock(buf, 0);
+ bufOff = 0;
+ ++inputBlocks;
+ }
+ }
+
public virtual void BlockUpdate(byte[] input, int inOff, int length)
{
while (bufOff != 0 && length > 0)
{
Update(input[inOff++]);
- length--;
+ --length;
}
if (length > 0)
{
- while (length > blockSize)
+ while (length >= blockSize)
{
ProcessBlock(input, inOff);
inOff += blockSize;
- inputLength += (ulong)blockSize;
length -= blockSize;
+ ++inputBlocks;
}
while (length > 0)
{
Update(input[inOff++]);
- length--;
+ --length;
}
}
}
- protected virtual byte[] Pad(byte[] input, int inOff, int length)
- {
- byte[] padded;
- if (blockSize - length < 13) // terminator byte + 96 bits of length
- {
- padded = new byte[2 * blockSize];
- }
- else
- {
- padded = new byte[blockSize];
- }
-
- Array.Copy(input, inOff, padded, 0, length);
- padded[length] = 0x80;
- Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
-
- return padded;
- }
-
- protected virtual void ProcessBlock(byte[] input, int inOff)
+ public virtual int DoFinal(byte[] output, int outOff)
{
- byte[][] temp1 = new byte[columns][];
- byte[][] temp2 = new byte[columns][];
-
- int pos = inOff;
- for (int i = 0; i < columns; i++)
+ // Apply padding: terminator byte and 96-bit length field
{
- byte[] S = state_[i];
- byte[] T1 = temp1[i] = new byte[ROWS];
- byte[] T2 = temp2[i] = new byte[ROWS];
+ int inputBytes = bufOff;
+ buf[bufOff++] = (byte)0x80;
- for (int j = 0; j < ROWS; ++j)
+ int lenPos = blockSize - 12;
+ if (bufOff > lenPos)
{
- byte inVal = input[pos++];
- T1[j] = (byte)(S[j] ^ inVal);
- T2[j] = inVal;
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ bufOff = 0;
+ ProcessBlock(buf, 0);
}
- }
- P(temp1);
- Q(temp2);
-
- for (int i = 0; i < columns; ++i)
- {
- byte[] S = state_[i], T1 = temp1[i], T2 = temp2[i];
- for (int j = 0; j < ROWS; ++j)
+ while (bufOff < lenPos)
{
- S[j] ^= (byte)(T1[j] ^ T2[j]);
+ buf[bufOff++] = 0;
}
- }
- }
-
- public virtual int DoFinal(byte[] output, int outOff)
- {
- padded_ = Pad(buf, 0, bufOff);
-
- int paddedLen = padded_.Length;
- int paddedOff = 0;
- while (paddedLen != 0)
- {
- ProcessBlock(padded_, paddedOff);
- paddedOff += blockSize;
- paddedLen -= blockSize;
+ ulong c = ((inputBlocks & 0xFFFFFFFFUL) * (ulong)blockSize + (uint)inputBytes) << 3;
+ Pack.UInt32_To_LE((uint)c, buf, bufOff);
+ bufOff += 4;
+ c >>= 32;
+ c += ((inputBlocks >> 32) * (ulong)blockSize) << 3;
+ Pack.UInt64_To_LE(c, buf, bufOff);
+ // bufOff += 8;
+ ProcessBlock(buf, 0);
}
- byte[][] temp = new byte[STATE_BYTE_SIZE_1024][];
- for (int i = 0; i < state_.Length; i++)
{
- temp[i] = new byte[ROWS];
- Array.Copy(state_[i], temp[i], ROWS);
- }
+ Array.Copy(state, 0, tempState1, 0, columns);
- P(temp);
+ P(tempState1);
- for (int i = 0; i < ROWS; ++i)
- {
- for (int j = 0; j < columns; ++j)
+ for (int col = 0; col < columns; ++col)
{
- state_[j][i] ^= temp[j][i];
+ state[col] ^= tempState1[col];
}
}
- byte[] stateLine = new byte[ROWS * columns];
- int stateLineIndex = 0;
- for (int j = 0; j < columns; ++j)
+ int neededColumns = hashSize / 8;
+ for (int col = columns - neededColumns; col < columns; ++col)
{
- for (int i = 0; i < ROWS; ++i)
- {
- stateLine[stateLineIndex] = state_[j][i];
- stateLineIndex++;
- }
+ Pack.UInt64_To_LE(state[col], output, outOff);
+ outOff += 8;
}
- Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize);
-
Reset();
return hashSize;
@@ -237,183 +208,313 @@ namespace Org.BouncyCastle.Crypto.Digests
public virtual void Reset()
{
- for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++)
- {
- state_[bufferIndex] = new byte[columns];
- }
+ Array.Clear(state, 0, state.Length);
+ state[0] = (ulong)blockSize;
- state_[0][0] = (byte)state_.Length;
-
- inputLength = 0;
+ inputBlocks = 0;
bufOff = 0;
-
- Arrays.Fill(buf, (byte)0);
-
- if (padded_ != null)
- {
- Arrays.Fill(padded_, (byte)0);
- }
}
- public virtual int GetDigestSize()
+ protected virtual void ProcessBlock(byte[] input, int inOff)
{
- return hashSize;
- }
+ int pos = inOff;
+ for (int col = 0; col < columns; ++col)
+ {
+ ulong word = Pack.LE_To_UInt64(input, pos);
+ pos += 8;
- public virtual int GetByteLength()
- {
- return blockSize;
- }
+ tempState1[col] = state[col] ^ word;
+ tempState2[col] = word;
+ }
- public virtual void Update(byte input)
- {
- buf[bufOff++] = input;
- if (bufOff == blockSize)
+ P(tempState1);
+ Q(tempState2);
+
+ for (int col = 0; col < columns; ++col)
{
- ProcessBlock(buf, 0);
- bufOff = 0;
+ state[col] ^= tempState1[col] ^ tempState2[col];
}
- inputLength++;
}
- private void SubBytes(byte[][] state)
+ private void P(ulong[] s)
{
- int i, j;
- for (i = 0; i < ROWS; ++i)
+ for (int round = 0; round < rounds; ++round)
{
- for (j = 0; j < columns; ++j)
+ ulong rc = (ulong)round;
+
+ /* AddRoundConstants */
+ for (int col = 0; col < columns; ++col)
{
- state[j][i] = sBoxes[i % 4][state[j][i]];
+ s[col] ^= rc;
+ rc += 0x10L;
}
+
+ ShiftRows(s);
+ SubBytes(s);
+ MixColumns(s);
}
}
- private void ShiftBytes(byte[][] state)
+ private void Q(ulong[] s)
{
- int i, j;
- byte[] temp = new byte[NB_1024];
- int shift = -1;
- for (i = 0; i < ROWS; ++i)
+ for (int round = 0; round < rounds; ++round)
{
- if ((i == ROWS - 1) && (columns == NB_1024))
- {
- shift = 11;
- }
- else
- {
- ++shift;
- }
- for (j = 0; j < columns; ++j)
- {
- temp[(j + shift) % columns] = state[j][i];
- }
- for (j = 0; j < columns; ++j)
+ /* AddRoundConstantsQ */
+ ulong rc = ((ulong)(((columns - 1) << 4) ^ round) << 56) | 0x00F0F0F0F0F0F0F3UL;
+
+ for (int col = 0; col < columns; ++col)
{
- state[j][i] = temp[j];
+ s[col] += rc;
+ rc -= 0x1000000000000000L;
}
+
+ ShiftRows(s);
+ SubBytes(s);
+ MixColumns(s);
}
}
- /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */
- private static ulong MultiplyGFx4(ulong u, ulong v)
+ private static ulong MixColumn(ulong c)
{
- ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL);
-
- for (int i = 1; i < 8; ++i)
- {
- u <<= 1;
- v >>= 1;
- r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL);
- }
-
- // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */
-
- ulong hi = r & 0xFF00FF00FF00FF00UL;
- r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8);
- hi = r & 0x0F000F000F000F00UL;
- r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8);
- return r;
+ //// Calculate column multiplied by powers of 'x'
+ //ulong x0 = c;
+ //ulong x1 = ((x0 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x0 & 0x8080808080808080UL) >> 7) * 0x1DUL);
+ //ulong x2 = ((x1 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x1 & 0x8080808080808080UL) >> 7) * 0x1DUL);
+ //ulong x3 = ((x2 & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((x2 & 0x8080808080808080UL) >> 7) * 0x1DUL);
+
+ //// Calculate products with circulant matrix from (0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04)
+ //ulong m0 = x0;
+ //ulong m1 = x0;
+ //ulong m2 = x0 ^ x2;
+ //ulong m3 = x0;
+ //ulong m4 = x3;
+ //ulong m5 = x1 ^ x2;
+ //ulong m6 = x0 ^ x1 ^ x2;
+ //ulong m7 = x2;
+
+ //// Assemble the rotated products
+ //return m0
+ // ^ Rotate(8, m1)
+ // ^ Rotate(16, m2)
+ // ^ Rotate(24, m3)
+ // ^ Rotate(32, m4)
+ // ^ Rotate(40, m5)
+ // ^ Rotate(48, m6)
+ // ^ Rotate(56, m7);
+
+ // Multiply elements by 'x'
+ ulong x1 = ((c & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((c & 0x8080808080808080UL) >> 7) * 0x1DUL);
+ ulong u, v;
+
+ u = Rotate(8, c) ^ c;
+ u ^= Rotate(16, u);
+ u ^= Rotate(48, c);
+
+ v = u ^ c ^ x1;
+
+ // Multiply elements by 'x^2'
+ v = ((v & 0x3F3F3F3F3F3F3F3FUL) << 2) ^ (((v & 0x8080808080808080UL) >> 6) * 0x1DUL) ^ (((v & 0x4040404040404040UL) >> 6) * 0x1DUL);
+
+ return u ^ Rotate(32, v) ^ Rotate(40, x1) ^ Rotate(48, x1);
}
- private void MixColumns(byte[][] state)
+ private void MixColumns(ulong[] s)
{
for (int col = 0; col < columns; ++col)
{
- ulong colVal = Pack.LE_To_UInt64(state[col]);
- ulong colEven = colVal & 0x00FF00FF00FF00FFUL;
- ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL;
-
- //ulong rowMatrix = (mdsMatrix >> 8) | (mdsMatrix << 56);
- ulong rowMatrix = mdsMatrix;
-
- ulong result = 0;
- for (int row = 7; row >= 0; --row)
- {
- ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL);
-
- rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56);
-
- product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL);
-
- product ^= (product >> 32);
- product ^= (product >> 16);
-
- result <<= 8;
- result |= (product & 0xFFUL);
- }
-
- Pack.UInt64_To_LE(result, state[col]);
+ s[col] = MixColumn(s[col]);
}
}
- private void AddRoundConstantP(byte[][] state, int round)
+ private static ulong Rotate(int n, ulong x)
{
- int i;
- for (i = 0; i < columns; ++i)
- {
- state[i][0] ^= (byte)((i * 0x10) ^ round);
- }
+ return (x >> n) | (x << -n);
}
- private void AddRoundConstantQ(byte[][] state, int round)
+ private void ShiftRows(ulong[] s)
{
- int j;
- UInt64[] s = new UInt64[columns];
-
- for (j = 0; j < columns; j++)
+ switch (columns)
{
- s[j] = Pack.LE_To_UInt64(state[j]);
-
- s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8)));
-
- state[j] = Pack.UInt64_To_LE(s[j]);
+ case NB_512:
+ {
+ ulong c0 = s[0], c1 = s[1], c2 = s[2], c3 = s[3];
+ ulong c4 = s[4], c5 = s[5], c6 = s[6], c7 = s[7];
+ ulong d;
+
+ d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d;
+ d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d;
+ d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d;
+ d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d;
+
+ d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d;
+ d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d;
+ d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d;
+ d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d;
+
+ d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d;
+ d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d;
+ d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d;
+ d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d;
+
+ s[0] = c0; s[1] = c1; s[2] = c2; s[3] = c3;
+ s[4] = c4; s[5] = c5; s[6] = c6; s[7] = c7;
+ break;
}
- }
-
- private void P(byte[][] state)
- {
- int i;
- for (i = 0; i < rounds; ++i)
+ case NB_1024:
{
- AddRoundConstantP(state, i);
- SubBytes(state);
- ShiftBytes(state);
- MixColumns(state);
+ ulong c00 = s[0], c01 = s[1], c02 = s[2], c03 = s[3];
+ ulong c04 = s[4], c05 = s[5], c06 = s[6], c07 = s[7];
+ ulong c08 = s[8], c09 = s[9], c10 = s[10], c11 = s[11];
+ ulong c12 = s[12], c13 = s[13], c14 = s[14], c15 = s[15];
+ ulong d;
+
+ // NOTE: Row 7 is shifted by 11
+
+ d = (c00 ^ c08) & 0xFF00000000000000UL; c00 ^= d; c08 ^= d;
+ d = (c01 ^ c09) & 0xFF00000000000000UL; c01 ^= d; c09 ^= d;
+ d = (c02 ^ c10) & 0xFFFF000000000000UL; c02 ^= d; c10 ^= d;
+ d = (c03 ^ c11) & 0xFFFFFF0000000000UL; c03 ^= d; c11 ^= d;
+ d = (c04 ^ c12) & 0xFFFFFFFF00000000UL; c04 ^= d; c12 ^= d;
+ d = (c05 ^ c13) & 0x00FFFFFFFF000000UL; c05 ^= d; c13 ^= d;
+ d = (c06 ^ c14) & 0x00FFFFFFFFFF0000UL; c06 ^= d; c14 ^= d;
+ d = (c07 ^ c15) & 0x00FFFFFFFFFFFF00UL; c07 ^= d; c15 ^= d;
+
+ d = (c00 ^ c04) & 0x00FFFFFF00000000UL; c00 ^= d; c04 ^= d;
+ d = (c01 ^ c05) & 0xFFFFFFFFFF000000UL; c01 ^= d; c05 ^= d;
+ d = (c02 ^ c06) & 0xFF00FFFFFFFF0000UL; c02 ^= d; c06 ^= d;
+ d = (c03 ^ c07) & 0xFF0000FFFFFFFF00UL; c03 ^= d; c07 ^= d;
+ d = (c08 ^ c12) & 0x00FFFFFF00000000UL; c08 ^= d; c12 ^= d;
+ d = (c09 ^ c13) & 0xFFFFFFFFFF000000UL; c09 ^= d; c13 ^= d;
+ d = (c10 ^ c14) & 0xFF00FFFFFFFF0000UL; c10 ^= d; c14 ^= d;
+ d = (c11 ^ c15) & 0xFF0000FFFFFFFF00UL; c11 ^= d; c15 ^= d;
+
+ d = (c00 ^ c02) & 0xFFFF0000FFFF0000UL; c00 ^= d; c02 ^= d;
+ d = (c01 ^ c03) & 0x00FFFF0000FFFF00UL; c01 ^= d; c03 ^= d;
+ d = (c04 ^ c06) & 0xFFFF0000FFFF0000UL; c04 ^= d; c06 ^= d;
+ d = (c05 ^ c07) & 0x00FFFF0000FFFF00UL; c05 ^= d; c07 ^= d;
+ d = (c08 ^ c10) & 0xFFFF0000FFFF0000UL; c08 ^= d; c10 ^= d;
+ d = (c09 ^ c11) & 0x00FFFF0000FFFF00UL; c09 ^= d; c11 ^= d;
+ d = (c12 ^ c14) & 0xFFFF0000FFFF0000UL; c12 ^= d; c14 ^= d;
+ d = (c13 ^ c15) & 0x00FFFF0000FFFF00UL; c13 ^= d; c15 ^= d;
+
+ d = (c00 ^ c01) & 0xFF00FF00FF00FF00UL; c00 ^= d; c01 ^= d;
+ d = (c02 ^ c03) & 0xFF00FF00FF00FF00UL; c02 ^= d; c03 ^= d;
+ d = (c04 ^ c05) & 0xFF00FF00FF00FF00UL; c04 ^= d; c05 ^= d;
+ d = (c06 ^ c07) & 0xFF00FF00FF00FF00UL; c06 ^= d; c07 ^= d;
+ d = (c08 ^ c09) & 0xFF00FF00FF00FF00UL; c08 ^= d; c09 ^= d;
+ d = (c10 ^ c11) & 0xFF00FF00FF00FF00UL; c10 ^= d; c11 ^= d;
+ d = (c12 ^ c13) & 0xFF00FF00FF00FF00UL; c12 ^= d; c13 ^= d;
+ d = (c14 ^ c15) & 0xFF00FF00FF00FF00UL; c14 ^= d; c15 ^= d;
+
+ s[0] = c00; s[1] = c01; s[2] = c02; s[3] = c03;
+ s[4] = c04; s[5] = c05; s[6] = c06; s[7] = c07;
+ s[8] = c08; s[9] = c09; s[10] = c10; s[11] = c11;
+ s[12] = c12; s[13] = c13; s[14] = c14; s[15] = c15;
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported state size: only 512/1024 are allowed");
+ }
}
}
- private void Q(byte[][] state)
+ private void SubBytes(ulong[] s)
{
- int i;
- for (i = 0; i < rounds; ++i)
+ for (int i = 0; i < columns; ++i)
{
- AddRoundConstantQ(state, i);
- SubBytes(state);
- ShiftBytes(state);
- MixColumns(state);
+ ulong u = s[i];
+ uint lo = (uint)u, hi = (uint)(u >> 32);
+ byte t0 = S0[lo & 0xFF];
+ byte t1 = S1[(lo >> 8) & 0xFF];
+ byte t2 = S2[(lo >> 16) & 0xFF];
+ byte t3 = S3[lo >> 24];
+ lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi & 0xFF];
+ byte t5 = S1[(hi >> 8) & 0xFF];
+ byte t6 = S2[(hi >> 16) & 0xFF];
+ byte t7 = S3[hi >> 24];
+ hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ s[i] = (ulong)lo | ((ulong)hi << 32);
}
}
+ private static readonly byte[] S0 = new byte[] {
+ 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
+ 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
+ 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
+ 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
+ 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
+ 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
+ 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
+ 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
+ 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
+ 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
+ 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
+ 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
+ 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
+ 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
+ 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
+ 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
+ };
+
+ private static readonly byte[] S1 = new byte[] {
+ 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
+ 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
+ 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
+ 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
+ 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
+ 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
+ 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
+ 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
+ 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
+ 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
+ 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
+ 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
+ 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
+ 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
+ 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
+ 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
+ };
+
+ private static readonly byte[] S2 = new byte[] {
+ 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
+ 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
+ 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
+ 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
+ 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
+ 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
+ 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
+ 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
+ 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
+ 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
+ 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
+ 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
+ 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
+ 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
+ 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
+ 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
+ };
+
+ private static readonly byte[] S3 = new byte[] {
+ 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
+ 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
+ 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
+ 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
+ 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
+ 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
+ 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
+ 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
+ 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
+ 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
+ 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
+ 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
+ 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
+ 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
+ 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
+ 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
+ };
+
public virtual IMemoable Copy()
{
return new Dstu7564Digest(this);
@@ -425,87 +526,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
- //private const ulong mdsMatrix = 0x0407060801050101UL;
- private const ulong mdsMatrix = 0x0104070608010501UL;
-
- private static readonly byte[][] sBoxes = new byte[][]
- {
- new byte[] {
- 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
- 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
- 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
- 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
- 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
- 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
- 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
- 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
- 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
- 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
- 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
- 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
- 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
- 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
- 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
- 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
- },
-
- new byte[] {
- 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
- 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
- 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
- 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
- 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
- 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
- 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
- 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
- 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
- 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
- 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
- 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
- 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
- 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
- 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
- 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
- },
-
- new byte[]{
- 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
- 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
- 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
- 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
- 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
- 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
- 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
- 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
- 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
- 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
- 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
- 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
- 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
- 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
- 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
- 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
- },
-
- new byte[]{
- 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
- 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
- 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
- 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
- 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
- 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
- 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
- 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
- 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
- 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
- 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
- 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
- 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
- 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
- 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
- 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
- }
- };
}
}
diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs
index 534a23bbf..4242d3a7a 100644
--- a/crypto/src/crypto/engines/Dstu7624Engine.cs
+++ b/crypto/src/crypto/engines/Dstu7624Engine.cs
@@ -13,9 +13,6 @@ namespace Org.BouncyCastle.Crypto.Engines
public class Dstu7624Engine
: IBlockCipher
{
- private static readonly int BITS_IN_WORD = 64;
- private static readonly int BITS_IN_BYTE = 8;
-
private ulong[] internalState;
private ulong[] workingKey;
private ulong[][] roundKeys;
@@ -27,126 +24,91 @@ namespace Org.BouncyCastle.Crypto.Engines
private int wordsInKey;
/* Number of encryption rounds depending on key length */
- private static int ROUNDS_128 = 10;
- private static int ROUNDS_256 = 14;
- private static int ROUNDS_512 = 18;
+ private const int ROUNDS_128 = 10;
+ private const int ROUNDS_256 = 14;
+ private const int ROUNDS_512 = 18;
- private int blockSizeBits;
private int roundsAmount;
private bool forEncryption;
- private byte[] internalStateBytes;
- private byte[] tempInternalStateBytes;
-
public Dstu7624Engine(int blockSizeBits)
{
/* DSTU7624 supports 128 | 256 | 512 key/block sizes */
if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512)
{
- throw new ArgumentException("Unsupported block length: only 128/256/512 are allowed");
+ throw new ArgumentException("unsupported block length: only 128/256/512 are allowed");
}
- this.blockSizeBits = blockSizeBits;
- wordsInBlock = blockSizeBits / BITS_IN_WORD;
+ wordsInBlock = blockSizeBits / 64;
internalState = new ulong[wordsInBlock];
-
- internalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
- tempInternalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
}
#region INITIALIZATION
+
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
- if (parameters is KeyParameter)
- {
- this.forEncryption = forEncryption;
-
- byte[] keyBytes = ((KeyParameter)parameters).GetKey();
- int keyBitLength = keyBytes.Length * BITS_IN_BYTE;
- int blockBitLength = wordsInBlock * BITS_IN_WORD;
-
- if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512)
- {
- throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
- }
-
- /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */
- if (blockBitLength == 128)
- {
- if (keyBitLength == 512)
- {
- throw new ArgumentException("Unsupported key length");
- }
- }
-
- if (blockBitLength == 256)
- {
- if (keyBitLength == 128)
- {
- throw new ArgumentException("Unsupported key length");
- }
- }
-
- if (blockBitLength == 512)
- {
- if (keyBitLength != 512)
- {
- throw new ArgumentException("Unsupported key length");
- }
- }
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameter passed to Dstu7624Engine Init");
- switch (keyBitLength)
- {
- case 128:
- roundsAmount = ROUNDS_128;
- break;
- case 256:
- roundsAmount = ROUNDS_256;
- break;
- case 512:
- roundsAmount = ROUNDS_512;
- break;
- }
-
- wordsInKey = keyBitLength / BITS_IN_WORD;
-
- /* +1 round key as defined in standard */
- roundKeys = new ulong[roundsAmount + 1][];
- for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++)
- {
- roundKeys[roundKeyIndex] = new ulong[wordsInBlock];
- }
+ this.forEncryption = forEncryption;
- workingKey = new ulong[wordsInKey];
+ byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+ int keyBitLength = keyBytes.Length << 3;
+ int blockBitLength = wordsInBlock << 6;
- if (keyBytes.Length != wordsInKey * BITS_IN_WORD / BITS_IN_BYTE)
- {
- throw new ArgumentException("Invalid key parameter passed to DSTU7624Engine init");
- }
+ if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512)
+ {
+ throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
+ }
- /* Unpack encryption key bytes to words */
- Pack.LE_To_UInt64(keyBytes, 0, workingKey);
+ /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */
+ if (keyBitLength != blockBitLength && keyBitLength != (2 * blockBitLength))
+ {
+ throw new ArgumentException("Unsupported key length");
+ }
- ulong[] kt = new ulong[wordsInBlock];
+ switch (keyBitLength)
+ {
+ case 128:
+ roundsAmount = ROUNDS_128;
+ break;
+ case 256:
+ roundsAmount = ROUNDS_256;
+ break;
+ case 512:
+ roundsAmount = ROUNDS_512;
+ break;
+ }
- KeyExpandKT(workingKey, kt);
+ wordsInKey = keyBitLength / 64;
- KeyExpandEven(workingKey, kt);
+ /* +1 round key as defined in standard */
+ roundKeys = new ulong[roundsAmount + 1][];
+ for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++)
+ {
+ roundKeys[roundKeyIndex] = new ulong[wordsInBlock];
+ }
- KeyExpandOdd();
+ workingKey = new ulong[wordsInKey];
- }
- else if (parameters != null)
+ if (keyBytes.Length != wordsInKey * 8)
{
- throw new ArgumentException("invalid parameter passed to Dstu7624 init - "
- + Platform.GetTypeName(parameters));
+ throw new ArgumentException("Invalid key parameter passed to Dstu7624Engine Init");
}
- this.forEncryption = forEncryption;
+ /* Unpack encryption key bytes to words */
+ Pack.LE_To_UInt64(keyBytes, 0, workingKey);
+
+ ulong[] tempKeys = new ulong[wordsInBlock];
+
+ /* KSA in DSTU7624 is strengthened to mitigate known weaknesses in AES KSA (eprint.iacr.org/2012/260.pdf) */
+ WorkingKeyExpandKT(workingKey, tempKeys);
+ WorkingKeyExpandEven(workingKey, tempKeys);
+ WorkingKeyExpandOdd();
}
- private void KeyExpandKT(ulong[] key, ulong[] kt)
+ private void WorkingKeyExpandKT(ulong[] workingKey, ulong[] tempKeys)
{
ulong[] k0 = new ulong[wordsInBlock];
ulong[] k1 = new ulong[wordsInBlock];
@@ -156,96 +118,114 @@ namespace Org.BouncyCastle.Crypto.Engines
if (wordsInBlock == wordsInKey)
{
- Array.Copy(key, k0, k0.Length);
- Array.Copy(key, k1, k1.Length);
+ Array.Copy(workingKey, 0, k0, 0, k0.Length);
+ Array.Copy(workingKey, 0, k1, 0, k1.Length);
}
else
{
- Array.Copy(key, 0, k0, 0, wordsInBlock);
- Array.Copy(key, wordsInBlock, k1, 0, wordsInBlock);
+ Array.Copy(workingKey, 0, k0, 0, wordsInBlock);
+ Array.Copy(workingKey, wordsInBlock, k1, 0, wordsInBlock);
}
- AddRoundKeyExpand(k0);
+
+ for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
+ {
+ internalState[wordIndex] += k0[wordIndex];
+ }
EncryptionRound();
- XorRoundKeyExpand(k1);
+ for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
+ {
+ internalState[wordIndex] ^= k1[wordIndex];
+ }
EncryptionRound();
- AddRoundKeyExpand(k0);
+ for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
+ {
+ internalState[wordIndex] += k0[wordIndex];
+ }
EncryptionRound();
- Array.Copy(internalState, kt, wordsInBlock);
+ Array.Copy(internalState, 0, tempKeys, 0, wordsInBlock);
}
- private void KeyExpandEven(ulong[] key, ulong[] kt)
+ private void WorkingKeyExpandEven(ulong[] workingKey, ulong[] tempKey)
{
- ulong[] initial_data = new ulong[wordsInKey];
-
- ulong[] kt_round = new ulong[wordsInBlock];
-
- ulong[] tmv = new ulong[wordsInBlock];
+ ulong[] initialData = new ulong[wordsInKey];
+ ulong[] tempRoundKey = new ulong[wordsInBlock];
int round = 0;
- Array.Copy(key, initial_data, wordsInKey);
+ Array.Copy(workingKey, 0, initialData, 0, wordsInKey);
- for (int i = 0; i < wordsInBlock; i++)
- {
- tmv[i] = 0x0001000100010001;
- }
+ ulong tmv = 0x0001000100010001UL;
while (true)
{
- Array.Copy(kt, internalState, wordsInBlock);
-
- AddRoundKeyExpand(tmv);
-
- Array.Copy(internalState, kt_round, wordsInBlock);
- Array.Copy(initial_data, internalState, wordsInBlock);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv;
+ }
- AddRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] = initialData[wordIndex] + tempRoundKey[wordIndex];
+ }
EncryptionRound();
- XorRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] ^= tempRoundKey[wordIndex];
+ }
EncryptionRound();
- AddRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] += tempRoundKey[wordIndex];
+ }
- Array.Copy(internalState, roundKeys[round], wordsInBlock);
+ Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock);
if (roundsAmount == round)
{
break;
}
+
if (wordsInKey != wordsInBlock)
{
round += 2;
+ tmv <<= 1;
- ShiftLeft(tmv);
-
- Array.Copy(kt, internalState, wordsInBlock);
-
- AddRoundKeyExpand(tmv);
-
- Array.Copy(internalState, kt_round, wordsInBlock);
- Array.Copy(initial_data, wordsInBlock, internalState, 0, wordsInBlock);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv;
+ }
- AddRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] = initialData[wordsInBlock + wordIndex] + tempRoundKey[wordIndex];
+ }
EncryptionRound();
- XorRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] ^= tempRoundKey[wordIndex];
+ }
EncryptionRound();
- AddRoundKeyExpand(kt_round);
+ for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
+ {
+ internalState[wordIndex] += tempRoundKey[wordIndex];
+ }
- Array.Copy(internalState, roundKeys[round], wordsInBlock);
+ Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock);
if (roundsAmount == round)
{
@@ -254,89 +234,99 @@ namespace Org.BouncyCastle.Crypto.Engines
}
round += 2;
- ShiftLeft(tmv);
+ tmv <<= 1;
- //Rotate initial data array on 1 element left
- ulong temp = initial_data[0];
- Array.Copy(initial_data, 1, initial_data, 0, initial_data.Length - 1);
- initial_data[initial_data.Length - 1] = temp;
+ ulong temp = initialData[0];
+ for (int i = 1; i < initialData.Length; ++i)
+ {
+ initialData[i - 1] = initialData[i];
+ }
+ initialData[initialData.Length - 1] = temp;
}
}
- private void KeyExpandOdd()
+
+ private void WorkingKeyExpandOdd()
{
- for (int i = 1; i < roundsAmount; i += 2)
+ for (int roundIndex = 1; roundIndex < roundsAmount; roundIndex += 2)
{
- Array.Copy(roundKeys[i - 1], roundKeys[i], wordsInBlock);
- RotateLeft(roundKeys[i]);
+ RotateLeft(roundKeys[roundIndex - 1], roundKeys[roundIndex]);
}
}
- #endregion
+ #endregion
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
- throw new InvalidOperationException("Dstu7624 engine not initialised");
+ throw new InvalidOperationException("Dstu7624Engine not initialised");
Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short");
Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short");
if (forEncryption)
{
- Encrypt(input, inOff, output, outOff);
- }
- else
- {
- Decrypt(input, inOff, output, outOff);
- }
-
- return GetBlockSize();
- }
-
- private void Encrypt(byte[] plain, int inOff, byte[] cipherText, int outOff)
- {
- Pack.LE_To_UInt64(plain, inOff, internalState);
+ /* Encrypt */
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ EncryptBlock_128(input, inOff, output, outOff);
+ break;
+ }
+ default:
+ {
+ Pack.LE_To_UInt64(input, inOff, internalState);
+ AddRoundKey(0);
+ for (int round = 0;;)
+ {
+ EncryptionRound();
- int round = 0;
- AddRoundKey(round);
+ if (++round == roundsAmount)
+ {
+ break;
+ }
- while (++round < roundsAmount)
- {
- EncryptionRound();
- XorRoundKey(round);
+ XorRoundKey(round);
+ }
+ AddRoundKey(roundsAmount);
+ Pack.UInt64_To_LE(internalState, output, outOff);
+ break;
+ }
+ }
}
-
- EncryptionRound();
- AddRoundKey(round);
-
- Pack.UInt64_To_LE(internalState, cipherText, outOff);
- }
-
- private void Decrypt(byte[] cipherText, int inOff, byte[] decryptedText, int outOff)
- {
- Pack.LE_To_UInt64(cipherText, inOff, internalState);
-
- int round = roundsAmount;
- SubRoundKey(round);
-
- while (--round > 0)
+ else
{
- DecryptionRound();
- XorRoundKey(round);
+ /* Decrypt */
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ DecryptBlock_128(input, inOff, output, outOff);
+ break;
+ }
+ default:
+ {
+ Pack.LE_To_UInt64(input, inOff, internalState);
+ SubRoundKey(roundsAmount);
+ for (int round = roundsAmount;;)
+ {
+ DecryptionRound();
+
+ if (--round == 0)
+ {
+ break;
+ }
+
+ XorRoundKey(round);
+ }
+ SubRoundKey(0);
+ Pack.UInt64_To_LE(internalState, output, outOff);
+ break;
+ }
+ }
}
- DecryptionRound();
- SubRoundKey(round);
-
- Pack.UInt64_To_LE(internalState, decryptedText, outOff);
- }
-
- private void AddRoundKeyExpand(ulong[] value)
- {
- for (int i = 0; i < wordsInBlock; i++)
- {
- internalState[i] += value[i];
- }
+ return GetBlockSize();
}
private void EncryptionRound()
@@ -348,393 +338,737 @@ namespace Org.BouncyCastle.Crypto.Engines
private void DecryptionRound()
{
- InvMixColumns();
+ MixColumnsInv();
InvShiftRows();
InvSubBytes();
}
- private void RotateLeft(ulong[] state_value)
+ private void DecryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
{
- int rotateBytesLength = 2 * state_value.Length + 3;
- int bytesLength = state_value.Length * (BITS_IN_WORD / BITS_IN_BYTE);
+ ulong c0 = Pack.LE_To_UInt64(input, inOff);
+ ulong c1 = Pack.LE_To_UInt64(input, inOff + 8);
- byte[] bytes = Pack.UInt64_To_LE(state_value);
- byte[] buffer = new byte[rotateBytesLength];
+ ulong[] roundKey = roundKeys[roundsAmount];
+ c0 -= roundKey[0];
+ c1 -= roundKey[1];
+
+ for (int round = roundsAmount;;)
+ {
+ c0 = MixColumnInv(c0);
+ c1 = MixColumnInv(c1);
+
+ uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
+ uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
+
+ {
+ byte t0 = T0[lo0 & 0xFF];
+ byte t1 = T1[(lo0 >> 8) & 0xFF];
+ byte t2 = T2[(lo0 >> 16) & 0xFF];
+ byte t3 = T3[lo0 >> 24];
+ lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = T0[hi1 & 0xFF];
+ byte t5 = T1[(hi1 >> 8) & 0xFF];
+ byte t6 = T2[(hi1 >> 16) & 0xFF];
+ byte t7 = T3[hi1 >> 24];
+ hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c0 = (ulong)lo0 | ((ulong)hi1 << 32);
+ }
+
+ {
+ byte t0 = T0[lo1 & 0xFF];
+ byte t1 = T1[(lo1 >> 8) & 0xFF];
+ byte t2 = T2[(lo1 >> 16) & 0xFF];
+ byte t3 = T3[lo1 >> 24];
+ lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = T0[hi0 & 0xFF];
+ byte t5 = T1[(hi0 >> 8) & 0xFF];
+ byte t6 = T2[(hi0 >> 16) & 0xFF];
+ byte t7 = T3[hi0 >> 24];
+ hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c1 = (ulong)lo1 | ((ulong)hi0 << 32);
+ }
- Array.Copy(bytes, buffer, rotateBytesLength);
+ if (--round == 0)
+ {
+ break;
+ }
- Buffer.BlockCopy(bytes, rotateBytesLength, bytes, 0, bytesLength - rotateBytesLength);
+ roundKey = roundKeys[round];
+ c0 ^= roundKey[0];
+ c1 ^= roundKey[1];
+ }
- Array.Copy(buffer, 0, bytes, bytesLength - rotateBytesLength, rotateBytesLength);
+ roundKey = roundKeys[0];
+ c0 -= roundKey[0];
+ c1 -= roundKey[1];
- Pack.LE_To_UInt64(bytes, 0, state_value);
+ Pack.UInt64_To_LE(c0, output, outOff);
+ Pack.UInt64_To_LE(c1, output, outOff + 8);
}
- private void ShiftLeft(ulong[] state_value)
+ private void EncryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
{
- for (int i = 0; i < state_value.Length; i++)
+ ulong c0 = Pack.LE_To_UInt64(input, inOff);
+ ulong c1 = Pack.LE_To_UInt64(input, inOff + 8);
+
+ ulong[] roundKey = roundKeys[0];
+ c0 += roundKey[0];
+ c1 += roundKey[1];
+
+ for (int round = 0;;)
{
- state_value[i] <<= 1;
+ uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
+ uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
+
+ {
+ byte t0 = S0[lo0 & 0xFF];
+ byte t1 = S1[(lo0 >> 8) & 0xFF];
+ byte t2 = S2[(lo0 >> 16) & 0xFF];
+ byte t3 = S3[lo0 >> 24];
+ lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi1 & 0xFF];
+ byte t5 = S1[(hi1 >> 8) & 0xFF];
+ byte t6 = S2[(hi1 >> 16) & 0xFF];
+ byte t7 = S3[hi1 >> 24];
+ hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c0 = (ulong)lo0 | ((ulong)hi1 << 32);
+ }
+
+ {
+ byte t0 = S0[lo1 & 0xFF];
+ byte t1 = S1[(lo1 >> 8) & 0xFF];
+ byte t2 = S2[(lo1 >> 16) & 0xFF];
+ byte t3 = S3[lo1 >> 24];
+ lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi0 & 0xFF];
+ byte t5 = S1[(hi0 >> 8) & 0xFF];
+ byte t6 = S2[(hi0 >> 16) & 0xFF];
+ byte t7 = S3[hi0 >> 24];
+ hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ c1 = (ulong)lo1 | ((ulong)hi0 << 32);
+ }
+
+ c0 = MixColumn(c0);
+ c1 = MixColumn(c1);
+
+ if (++round == roundsAmount)
+ {
+ break;
+ }
+
+ roundKey = roundKeys[round];
+ c0 ^= roundKey[0];
+ c1 ^= roundKey[1];
}
- Array.Reverse(state_value);
+
+ roundKey = roundKeys[roundsAmount];
+ c0 += roundKey[0];
+ c1 += roundKey[1];
+
+ Pack.UInt64_To_LE(c0, output, outOff);
+ Pack.UInt64_To_LE(c1, output, outOff + 8);
}
- private void XorRoundKeyExpand(ulong[] value)
+ private void SubBytes()
{
for (int i = 0; i < wordsInBlock; i++)
{
- internalState[i] ^= value[i];
+ ulong u = internalState[i];
+ uint lo = (uint)u, hi = (uint)(u >> 32);
+ byte t0 = S0[lo & 0xFF];
+ byte t1 = S1[(lo >> 8) & 0xFF];
+ byte t2 = S2[(lo >> 16) & 0xFF];
+ byte t3 = S3[lo >> 24];
+ lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = S0[hi & 0xFF];
+ byte t5 = S1[(hi >> 8) & 0xFF];
+ byte t6 = S2[(hi >> 16) & 0xFF];
+ byte t7 = S3[hi >> 24];
+ hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ internalState[i] = (ulong)lo | ((ulong)hi << 32);
}
}
- private void XorRoundKey(int round)
+ private void InvSubBytes()
{
- ulong[] roundKey = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++)
{
- internalState[i] ^= roundKey[i];
+ ulong u = internalState[i];
+ uint lo = (uint)u, hi = (uint)(u >> 32);
+ byte t0 = T0[lo & 0xFF];
+ byte t1 = T1[(lo >> 8) & 0xFF];
+ byte t2 = T2[(lo >> 16) & 0xFF];
+ byte t3 = T3[lo >> 24];
+ lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
+ byte t4 = T0[hi & 0xFF];
+ byte t5 = T1[(hi >> 8) & 0xFF];
+ byte t6 = T2[(hi >> 16) & 0xFF];
+ byte t7 = T3[hi >> 24];
+ hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
+ internalState[i] = (ulong)lo | ((ulong)hi << 32);
}
}
private void ShiftRows()
{
- int row, col;
- int shift = -1;
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ ulong c0 = internalState[0], c1 = internalState[1];
+ ulong d;
- byte[] stateBytes = Pack.UInt64_To_LE(internalState);
- byte[] nstate = new byte[wordsInBlock * 8];
+ d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d;
- for (row = 0; row < 8; row++)
+ internalState[0] = c0;
+ internalState[1] = c1;
+ break;
+ }
+ case 4:
{
- if (row % (8 / wordsInBlock) == 0)
- {
- shift += 1;
- }
+ ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
+ ulong d;
- for (col = 0; col < wordsInBlock; col++)
- {
- nstate[row + ((col + shift) % wordsInBlock) * 8] = stateBytes[row + col * 8];
- }
- }
+ d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d;
+ d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d;
- Pack.LE_To_UInt64(nstate, 0, internalState);
+ d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d;
+ d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d;
+
+ internalState[0] = c0;
+ internalState[1] = c1;
+ internalState[2] = c2;
+ internalState[3] = c3;
+ break;
+ }
+ case 8:
+ {
+ ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
+ ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7];
+ ulong d;
+
+ d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d;
+ d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d;
+ d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d;
+ d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d;
+
+ d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d;
+ d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d;
+ d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d;
+ d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d;
+
+ d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d;
+ d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d;
+ d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d;
+ d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d;
+
+ internalState[0] = c0;
+ internalState[1] = c1;
+ internalState[2] = c2;
+ internalState[3] = c3;
+ internalState[4] = c4;
+ internalState[5] = c5;
+ internalState[6] = c6;
+ internalState[7] = c7;
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
+ }
+ }
}
private void InvShiftRows()
{
- int row, col;
- int shift = -1;
+ switch (wordsInBlock)
+ {
+ case 2:
+ {
+ ulong c0 = internalState[0], c1 = internalState[1];
+ ulong d;
- byte[] stateBytes = Pack.UInt64_To_LE(internalState);
- byte[] nstate = new byte[wordsInBlock * 8];
+ d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d;
- for (row = 0; row < 8; row++)
+ internalState[0] = c0;
+ internalState[1] = c1;
+ break;
+ }
+ case 4:
{
- if (row % (8 / wordsInBlock) == 0)
- {
- shift += 1;
- }
+ ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
+ ulong d;
- for (col = 0; col < wordsInBlock; col++)
- {
- nstate[row + col * 8] = stateBytes[row + ((col + shift) % wordsInBlock) * 8];
- }
- }
+ d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d;
+ d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d;
+
+ d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d;
+ d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d;
- Pack.LE_To_UInt64(nstate, 0, internalState);
+ internalState[0] = c0;
+ internalState[1] = c1;
+ internalState[2] = c2;
+ internalState[3] = c3;
+ break;
+ }
+ case 8:
+ {
+ ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
+ ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7];
+ ulong d;
+
+ d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d;
+ d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d;
+ d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d;
+ d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d;
+
+ d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d;
+ d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d;
+ d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d;
+ d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d;
+
+ d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d;
+ d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d;
+ d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d;
+ d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d;
+
+ internalState[0] = c0;
+ internalState[1] = c1;
+ internalState[2] = c2;
+ internalState[3] = c3;
+ internalState[4] = c4;
+ internalState[5] = c5;
+ internalState[6] = c6;
+ internalState[7] = c7;
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
+ }
+ }
}
private void AddRoundKey(int round)
{
+ ulong[] roundKey = roundKeys[round];
for (int i = 0; i < wordsInBlock; ++i)
{
- internalState[i] += roundKeys[round][i];
+ internalState[i] += roundKey[i];
}
}
private void SubRoundKey(int round)
{
+ ulong[] roundKey = roundKeys[round];
for (int i = 0; i < wordsInBlock; ++i)
{
- internalState[i] -= roundKeys[round][i];
+ internalState[i] -= roundKey[i];
}
}
- private void MixColumns()
+ private void XorRoundKey(int round)
{
- MatrixMultiply(mdsMatrix);
+ ulong[] roundKey = roundKeys[round];
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] ^= roundKey[i];
+ }
}
- private void InvMixColumns()
+ private static ulong MixColumn(ulong c)
{
- MatrixMultiply(mdsInvMatrix);
+ //// Calculate column multiplied by powers of 'x'
+ //ulong x0 = c;
+ //ulong x1 = MulX(x0);
+ //ulong x2 = MulX(x1);
+ //ulong x3 = MulX(x2);
+
+ //// Calculate products with circulant matrix from (0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04)
+ //ulong m0 = x0;
+ //ulong m1 = x0;
+ //ulong m2 = x0 ^ x2;
+ //ulong m3 = x0;
+ //ulong m4 = x3;
+ //ulong m5 = x1 ^ x2;
+ //ulong m6 = x0 ^ x1 ^ x2;
+ //ulong m7 = x2;
+
+ //// Assemble the rotated products
+ //return m0
+ // ^ Rotate(8, m1)
+ // ^ Rotate(16, m2)
+ // ^ Rotate(24, m3)
+ // ^ Rotate(32, m4)
+ // ^ Rotate(40, m5)
+ // ^ Rotate(48, m6)
+ // ^ Rotate(56, m7);
+
+ ulong x1 = MulX(c);
+ ulong u, v;
+
+ u = Rotate(8, c) ^ c;
+ u ^= Rotate(16, u);
+ u ^= Rotate(48, c);
+
+ v = MulX2(u ^ c ^ x1);
+
+ return u ^ Rotate(32, v) ^ Rotate(40, x1) ^ Rotate(48, x1);
}
- private void MatrixMultiply(ulong matrix)
+ private void MixColumns()
{
for (int col = 0; col < wordsInBlock; ++col)
{
- ulong colVal = internalState[col];
- ulong colEven = colVal & 0x00FF00FF00FF00FFUL;
- ulong colOdd = (colVal >> 8) & 0x00FF00FF00FF00FFUL;
-
- //ulong rowMatrix = (matrix >> 8) | (matrix << 56);
- ulong rowMatrix = matrix;
-
- ulong result = 0;
- for (int row = 7; row >= 0; --row)
- {
- ulong product = MultiplyGFx4(colEven, rowMatrix & 0x00FF00FF00FF00FFUL);
-
- rowMatrix = (rowMatrix >> 8) | (rowMatrix << 56);
-
- product ^= MultiplyGFx4(colOdd, rowMatrix & 0x00FF00FF00FF00FFUL);
-
- product ^= (product >> 32);
- product ^= (product >> 16);
-
- result <<= 8;
- result |= (product & 0xFFUL);
- }
-
- internalState[col] = result;
+ internalState[col] = MixColumn(internalState[col]);
}
}
- /* Pair-wise GF multiplication of 4 byte-pairs (at bits 0, 16, 32, 48 within x, y) */
- private static ulong MultiplyGFx4(ulong u, ulong v)
+ private static ulong MixColumnInv(ulong c)
{
- ulong r = u & ((v & 0x0001000100010001UL) * 0xFFFFUL);
+/*
+ // Calculate column multiplied by powers of 'x'
+ ulong x0 = c;
+ ulong x1 = MulX(x0);
+ ulong x2 = MulX(x1);
+ ulong x3 = MulX(x2);
+ ulong x4 = MulX(x3);
+ ulong x5 = MulX(x4);
+ ulong x6 = MulX(x5);
+ ulong x7 = MulX(x6);
+
+ // Calculate products with circulant matrix from (0xAD,0x95,0x76,0xA8,0x2F,0x49,0xD7,0xCA)
+ //long m0 = x0 ^ x2 ^ x3 ^ x5 ^ x7;
+ //long m1 = x0 ^ x2 ^ x4 ^ x7;
+ //long m2 = x1 ^ x2 ^ x4 ^ x5 ^ x6;
+ //long m3 = x3 ^ x5 ^ x7;
+ //long m4 = x0 ^ x1 ^ x2 ^ x3 ^ x5;
+ //long m5 = x0 ^ x3 ^ x6;
+ //long m6 = x0 ^ x1 ^ x2 ^ x4 ^ x6 ^ x7;
+ //long m7 = x1 ^ x3 ^ x6 ^ x7;
+
+ ulong m5 = x0 ^ x3 ^ x6;
+ x0 ^= x2;
+ ulong m3 = x3 ^ x5 ^ x7;
+ ulong m0 = m3 ^ x0;
+ ulong m6 = x0 ^ x4;
+ ulong m1 = m6 ^ x7;
+ x5 ^= x1;
+ x7 ^= x1 ^ x6;
+ ulong m2 = x2 ^ x4 ^ x5 ^ x6;
+ ulong m4 = x0 ^ x3 ^ x5;
+ m6 ^= x7;
+ ulong m7 = x3 ^ x7;
+
+ // Assemble the rotated products
+ return m0
+ ^ Rotate(8, m1)
+ ^ Rotate(16, m2)
+ ^ Rotate(24, m3)
+ ^ Rotate(32, m4)
+ ^ Rotate(40, m5)
+ ^ Rotate(48, m6)
+ ^ Rotate(56, m7);
+*/
+
+ ulong u0 = c;
+ u0 ^= Rotate( 8, u0);
+ u0 ^= Rotate(32, u0);
+ u0 ^= Rotate(48, c);
+
+ ulong t = u0 ^ c;
+
+ ulong c48 = Rotate(48, c);
+ ulong c56 = Rotate(56, c);
+
+ ulong u7 = t ^ c56;
+ ulong u6 = Rotate(56, t);
+ u6 ^= MulX(u7);
+ ulong u5 = Rotate(16, t) ^ c;
+ u5 ^= Rotate(40, MulX(u6) ^ c);
+ ulong u4 = t ^ c48;
+ u4 ^= MulX(u5);
+ ulong u3 = Rotate(16, u0);
+ u3 ^= MulX(u4);
+ ulong u2 = t ^ Rotate(24, c) ^ c48 ^ c56;
+ u2 ^= MulX(u3);
+ ulong u1 = Rotate(32, t) ^ c ^ c56;
+ u1 ^= MulX(u2);
+ u0 ^= MulX(Rotate(40, u1));
+
+ return u0;
+ }
- for (int i = 1; i < 8; ++i)
+ private void MixColumnsInv()
+ {
+ for (int col = 0; col < wordsInBlock; ++col)
{
- u <<= 1;
- v >>= 1;
- r ^= u & ((v & 0x0001000100010001L) * 0xFFFFL);
+ internalState[col] = MixColumnInv(internalState[col]);
}
+ }
- // REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */
+ private static ulong MulX(ulong n)
+ {
+ return ((n & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((n & 0x8080808080808080UL) >> 7) * 0x1DUL);
+ }
- ulong hi = r & 0xFF00FF00FF00FF00UL;
- r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8);
- hi = r & 0x0F000F000F000F00UL;
- r ^= hi ^ (hi >> 4) ^ (hi >> 5) ^ (hi >> 6) ^ (hi >> 8);
- return r;
+ private static ulong MulX2(ulong n)
+ {
+ return ((n & 0x3F3F3F3F3F3F3F3FUL) << 2) ^ (((n & 0x8080808080808080UL) >> 6) * 0x1DUL) ^ (((n & 0x4040404040404040UL) >> 6) * 0x1DUL);
}
- private void SubBytes()
+ //private static ulong MulX4(ulong n)
+ //{
+ // ulong u = n & 0xF0F0F0F0F0F0F0F0UL;
+ // return ((n & 0x0F0F0F0F0F0F0F0FUL) << 4) ^ u ^ (u >> 1) ^ (u >> 2) ^ (u >> 4);
+ //}
+
+ /*
+ * Pair-wise modular multiplication of 8 byte-pairs.
+ *
+ * REDUCTION_POLYNOMIAL is x^8 + x^4 + x^3 + x^2 + 1
+ */
+ //private static ulong MultiplyGFx8(ulong u, ulong v, int vMaxDegree)
+ //{
+ // ulong r = u & ((v & 0x0101010101010101UL) * 0xFFUL);
+ // for (int i = 1; i <= vMaxDegree; ++i)
+ // {
+ // u = ((u & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((u >> 7) & 0x0101010101010101UL) * 0x1DUL);
+ // v >>= 1;
+
+ // r ^= u & ((v & 0x0101010101010101UL) * 0xFFUL);
+ // }
+
+ // return r;
+ //}
+
+ //private static ulong MultiplyMds(ulong u)
+ //{
+ // ulong r = 0, s = 0, t = (u >> 8);
+ // r ^= u & 0x0000001F00000000UL; r <<= 1;
+ // s ^= t & 0x00000000E0000000UL; s <<= 1;
+ // r ^= u & 0x3F3F3F00003F0000UL; r <<= 1;
+ // s ^= t & 0x00C0C0C00000C000UL; s <<= 1;
+ // r ^= u & 0x007F7F0000000000UL; r <<= 1;
+ // s ^= t & 0x0000808000000000UL; s <<= 1;
+ // r ^= u & 0x00FF0000FFFFFFFFUL;
+ // r ^= s ^ (s << 2) ^ (s << 3) ^ (s << 4);
+ // return r;
+ //}
+
+ private static ulong Rotate(int n, ulong x)
{
- for (int i = 0; i < wordsInBlock; i++)
- {
- internalState[i] = sboxesForEncryption[0][internalState[i] & 0x00000000000000FF] |
- ((ulong)sboxesForEncryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
- ((ulong)sboxesForEncryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
- ((ulong)sboxesForEncryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
- ((ulong)sboxesForEncryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
- ((ulong)sboxesForEncryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
- ((ulong)sboxesForEncryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
- ((ulong)sboxesForEncryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
- }
+ return (x >> n) | (x << -n);
}
- private void InvSubBytes()
+ private void RotateLeft(ulong[] x, ulong[] z)
{
- for (int i = 0; i < wordsInBlock; i++)
+ switch (wordsInBlock)
{
- internalState[i] = sboxesForDecryption[0][internalState[i] & 0x00000000000000FF] |
- ((ulong)sboxesForDecryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
- ((ulong)sboxesForDecryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
- ((ulong)sboxesForDecryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
- ((ulong)sboxesForDecryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
- ((ulong)sboxesForDecryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
- ((ulong)sboxesForDecryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
- ((ulong)sboxesForDecryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
+ case 2:
+ {
+ ulong x0 = x[0], x1 = x[1];
+ z[0] = (x0 >> 56) | (x1 << 8);
+ z[1] = (x1 >> 56) | (x0 << 8);
+ break;
+ }
+ case 4:
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = (x1 >> 24) | (x2 << 40);
+ z[1] = (x2 >> 24) | (x3 << 40);
+ z[2] = (x3 >> 24) | (x0 << 40);
+ z[3] = (x0 >> 24) | (x1 << 40);
+ break;
+ }
+ case 8:
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ ulong x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7];
+ z[0] = (x2 >> 24) | (x3 << 40);
+ z[1] = (x3 >> 24) | (x4 << 40);
+ z[2] = (x4 >> 24) | (x5 << 40);
+ z[3] = (x5 >> 24) | (x6 << 40);
+ z[4] = (x6 >> 24) | (x7 << 40);
+ z[5] = (x7 >> 24) | (x0 << 40);
+ z[6] = (x0 >> 24) | (x1 << 40);
+ z[7] = (x1 >> 24) | (x2 << 40);
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
+ }
}
}
#region TABLES AND S-BOXES
- //private const ulong mdsMatrix = 0x0407060801050101UL;
- //private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL;
- private const ulong mdsMatrix = 0x0104070608010501UL;
- private const ulong mdsInvMatrix = 0xADCAD7492FA87695UL;
+ private const ulong mdsMatrix = 0x0407060801050101UL;
+ private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL;
+
+ private static readonly byte[] S0 = new byte[]{
+ 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
+ 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
+ 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
+ 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
+ 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
+ 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
+ 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
+ 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
+ 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
+ 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
+ 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
+ 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
+ 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
+ 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
+ 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
+ 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
+ };
- private byte[][] sboxesForEncryption =
- {
- new byte[]
- {
- 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
- 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
- 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
- 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
- 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
- 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
- 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
- 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
- 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
- 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
- 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
- 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
- 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
- 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
- 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
- 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
- },
-
- new byte[]
- {
- 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
- 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
- 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
- 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
- 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
- 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
- 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
- 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
- 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
- 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
- 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
- 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
- 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
- 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
- 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
- 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
- },
-
- new byte[]
- {
- 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
- 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
- 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
- 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
- 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
- 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
- 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
- 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
- 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
- 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
- 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
- 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
- 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
- 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
- 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
- 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
- },
-
- new byte[]
- {
- 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
- 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
- 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
- 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
- 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
- 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
- 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
- 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
- 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
- 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
- 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
- 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
- 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
- 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
- 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
- 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
- }
+ private static readonly byte[] S1 = new byte[]{
+ 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
+ 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
+ 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
+ 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
+ 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
+ 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
+ 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
+ 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
+ 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
+ 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
+ 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
+ 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
+ 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
+ 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
+ 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
+ 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
};
- private byte[][] sboxesForDecryption =
- {
- new byte[]
- {
- 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b,
- 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28,
- 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0,
- 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c,
- 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23,
- 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02,
- 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c,
- 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7,
- 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c,
- 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d,
- 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17,
- 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29,
- 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec,
- 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09,
- 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1,
- 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f
- },
-
- new byte[]
- {
- 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29,
- 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc,
- 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2,
- 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76,
- 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8,
- 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f,
- 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c,
- 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9,
- 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99,
- 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38,
- 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7,
- 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87,
- 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b,
- 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c,
- 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4,
- 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa
- },
-
- new byte[]
- {
- 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95,
- 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3,
- 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a,
- 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85,
- 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52,
- 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5,
- 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb,
- 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7,
- 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62,
- 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c,
- 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d,
- 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3,
- 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91,
- 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a,
- 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49,
- 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1
- },
-
- new byte[]
- {
- 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3,
- 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f,
- 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21,
- 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba,
- 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49,
- 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66,
- 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4,
- 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8,
- 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85,
- 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91,
- 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb,
- 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d,
- 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d,
- 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f,
- 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf,
- 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
- }
+ private static readonly byte[] S2 = new byte[]{
+ 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
+ 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
+ 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
+ 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
+ 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
+ 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
+ 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
+ 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
+ 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
+ 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
+ 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
+ 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
+ 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
+ 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
+ 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
+ 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
+ };
+
+ private static readonly byte[] S3 = new byte[]{
+ 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
+ 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
+ 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
+ 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
+ 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
+ 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
+ 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
+ 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
+ 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
+ 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
+ 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
+ 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
+ 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
+ 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
+ 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
+ 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
+ };
+
+ private static readonly byte[] T0 = new byte[]{
+ 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b,
+ 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28,
+ 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0,
+ 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c,
+ 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23,
+ 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02,
+ 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c,
+ 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7,
+ 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c,
+ 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d,
+ 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17,
+ 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29,
+ 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec,
+ 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09,
+ 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1,
+ 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f
+ };
+
+ private static readonly byte[] T1 = new byte[]{
+ 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29,
+ 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc,
+ 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2,
+ 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76,
+ 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8,
+ 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f,
+ 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c,
+ 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9,
+ 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99,
+ 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38,
+ 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7,
+ 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87,
+ 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b,
+ 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c,
+ 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4,
+ 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa
+ };
+
+ private static readonly byte[] T2 = new byte[]{
+ 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95,
+ 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3,
+ 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a,
+ 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85,
+ 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52,
+ 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5,
+ 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb,
+ 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7,
+ 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62,
+ 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c,
+ 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d,
+ 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3,
+ 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91,
+ 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a,
+ 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49,
+ 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1
+ };
+
+ private static readonly byte[] T3 = new byte[]{
+ 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3,
+ 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f,
+ 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21,
+ 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba,
+ 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49,
+ 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66,
+ 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4,
+ 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8,
+ 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85,
+ 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91,
+ 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb,
+ 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d,
+ 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d,
+ 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f,
+ 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf,
+ 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
};
#endregion
public virtual string AlgorithmName
{
- get { return "Dstu7624"; }
+ get { return "DSTU7624"; }
}
public virtual int GetBlockSize()
{
- return blockSizeBits / BITS_IN_BYTE;
+ return wordsInBlock << 3;
}
public virtual bool IsPartialBlockOkay
@@ -744,6 +1078,7 @@ namespace Org.BouncyCastle.Crypto.Engines
public virtual void Reset()
{
+ Array.Clear(internalState, 0, internalState.Length);
}
}
}
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
index efa74d735..64a36df63 100644
--- a/crypto/src/crypto/generators/SCrypt.cs
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -8,12 +8,46 @@ using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Generators
{
- public class SCrypt
+ /// <summary>Implementation of the scrypt a password-based key derivation function.</summary>
+ /// <remarks>
+ /// Scrypt was created by Colin Percival and is specified in
+ /// <a href="http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01">draft-josefsson-scrypt-kd</a>.
+ /// </remarks>
+ public class SCrypt
{
- // TODO Validate arguments
- public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ /// <summary>Generate a key using the scrypt key derivation function.</summary>
+ /// <param name="P">the bytes of the pass phrase.</param>
+ /// <param name="S">the salt to use for this invocation.</param>
+ /// <param name="N">CPU/Memory cost parameter. Must be larger than 1, a power of 2 and less than
+ /// <code>2^(128 * r / 8)</code>.</param>
+ /// <param name="r">the block size, must be >= 1.</param>
+ /// <param name="p">Parallelization parameter. Must be a positive integer less than or equal to
+ /// <code>Int32.MaxValue / (128 * r * 8)</code>.</param>
+ /// <param name="dkLen">the length of the key to generate.</param>
+ /// <returns>the generated key.</returns>
+ public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
{
- return MFcrypt(P, S, N, r, p, dkLen);
+ if (P == null)
+ throw new ArgumentNullException("Passphrase P must be provided.");
+ if (S == null)
+ throw new ArgumentNullException("Salt S must be provided.");
+ if (N <= 1)
+ throw new ArgumentException("Cost parameter N must be > 1.");
+ // Only value of r that cost (as an int) could be exceeded for is 1
+ if (r == 1 && N >= 65536)
+ throw new ArgumentException("Cost parameter N must be > 1 and < 65536.");
+ if (r < 1)
+ throw new ArgumentException("Block size r must be >= 1.");
+ int maxParallel = Int32.MaxValue / (128 * r * 8);
+ if (p < 1 || p > maxParallel)
+ {
+ throw new ArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
+ + " (based on block size r of " + r + ")");
+ }
+ if (dkLen < 1)
+ throw new ArgumentException("Generated key length dkLen must be >= 1.");
+
+ return MFcrypt(P, S, N, r, p, dkLen);
}
private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index 7ddf6c8e4..c6adbdd95 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -3,10 +3,14 @@ using System.Collections;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.GM;
+using Org.BouncyCastle.Asn1.Misc;
using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Rosstandart;
using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.UA;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto;
@@ -20,7 +24,11 @@ namespace Org.BouncyCastle.Security
public sealed class DigestUtilities
{
private enum DigestAlgorithm {
+ BLAKE2B_160, BLAKE2B_256, BLAKE2B_384, BLAKE2B_512,
+ BLAKE2S_128, BLAKE2S_160, BLAKE2S_224, BLAKE2S_256,
+ DSTU7564_256, DSTU7564_384, DSTU7564_512,
GOST3411,
+ GOST3411_2012_256, GOST3411_2012_512,
KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512,
MD2, MD4, MD5,
RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
@@ -28,6 +36,7 @@ namespace Org.BouncyCastle.Security
SHA_512_224, SHA_512_256,
SHA3_224, SHA3_256, SHA3_384, SHA3_512,
SHAKE128, SHAKE256,
+ SM3,
TIGER,
WHIRLPOOL,
};
@@ -81,6 +90,24 @@ namespace Org.BouncyCastle.Security
algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128";
algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256";
+ algorithms[GMObjectIdentifiers.sm3.Id] = "SM3";
+
+ algorithms[MiscObjectIdentifiers.id_blake2b160.Id] = "BLAKE2B-160";
+ algorithms[MiscObjectIdentifiers.id_blake2b256.Id] = "BLAKE2B-256";
+ algorithms[MiscObjectIdentifiers.id_blake2b384.Id] = "BLAKE2B-384";
+ algorithms[MiscObjectIdentifiers.id_blake2b512.Id] = "BLAKE2B-512";
+ algorithms[MiscObjectIdentifiers.id_blake2s128.Id] = "BLAKE2S-128";
+ algorithms[MiscObjectIdentifiers.id_blake2s160.Id] = "BLAKE2S-160";
+ algorithms[MiscObjectIdentifiers.id_blake2s224.Id] = "BLAKE2S-224";
+ algorithms[MiscObjectIdentifiers.id_blake2s256.Id] = "BLAKE2S-256";
+
+ algorithms[RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id] = "GOST3411-2012-256";
+ algorithms[RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id] = "GOST3411-2012-512";
+
+ algorithms[UAObjectIdentifiers.dstu7564digest_256.Id] = "DSTU7564-256";
+ algorithms[UAObjectIdentifiers.dstu7564digest_384.Id] = "DSTU7564-384";
+ algorithms[UAObjectIdentifiers.dstu7564digest_512.Id] = "DSTU7564-512";
+
oids["MD2"] = PkcsObjectIdentifiers.MD2;
oids["MD4"] = PkcsObjectIdentifiers.MD4;
oids["MD5"] = PkcsObjectIdentifiers.MD5;
@@ -101,6 +128,20 @@ namespace Org.BouncyCastle.Security
oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
+ oids["SM3"] = GMObjectIdentifiers.sm3;
+ oids["BLAKE2B-160"] = MiscObjectIdentifiers.id_blake2b160;
+ oids["BLAKE2B-256"] = MiscObjectIdentifiers.id_blake2b256;
+ oids["BLAKE2B-384"] = MiscObjectIdentifiers.id_blake2b384;
+ oids["BLAKE2B-512"] = MiscObjectIdentifiers.id_blake2b512;
+ oids["BLAKE2S-128"] = MiscObjectIdentifiers.id_blake2s128;
+ oids["BLAKE2S-160"] = MiscObjectIdentifiers.id_blake2s160;
+ oids["BLAKE2S-224"] = MiscObjectIdentifiers.id_blake2s224;
+ oids["BLAKE2S-256"] = MiscObjectIdentifiers.id_blake2s256;
+ oids["GOST3411-2012-256"] = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256;
+ oids["GOST3411-2012-512"] = RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512;
+ oids["DSTU7564-256"] = UAObjectIdentifiers.dstu7564digest_256;
+ oids["DSTU7564-384"] = UAObjectIdentifiers.dstu7564digest_384;
+ oids["DSTU7564-512"] = UAObjectIdentifiers.dstu7564digest_512;
}
/// <summary>
@@ -153,34 +194,48 @@ namespace Org.BouncyCastle.Security
switch (digestAlgorithm)
{
- case DigestAlgorithm.GOST3411: return new Gost3411Digest();
- case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224);
- case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256);
- case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288);
- case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384);
- case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512);
- case DigestAlgorithm.MD2: return new MD2Digest();
- case DigestAlgorithm.MD4: return new MD4Digest();
- case DigestAlgorithm.MD5: return new MD5Digest();
- case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest();
- case DigestAlgorithm.RIPEMD160: return new RipeMD160Digest();
- case DigestAlgorithm.RIPEMD256: return new RipeMD256Digest();
- case DigestAlgorithm.RIPEMD320: return new RipeMD320Digest();
- case DigestAlgorithm.SHA_1: return new Sha1Digest();
- case DigestAlgorithm.SHA_224: return new Sha224Digest();
- case DigestAlgorithm.SHA_256: return new Sha256Digest();
- case DigestAlgorithm.SHA_384: return new Sha384Digest();
- case DigestAlgorithm.SHA_512: return new Sha512Digest();
- case DigestAlgorithm.SHA_512_224: return new Sha512tDigest(224);
- case DigestAlgorithm.SHA_512_256: return new Sha512tDigest(256);
- case DigestAlgorithm.SHA3_224: return new Sha3Digest(224);
- case DigestAlgorithm.SHA3_256: return new Sha3Digest(256);
- case DigestAlgorithm.SHA3_384: return new Sha3Digest(384);
- case DigestAlgorithm.SHA3_512: return new Sha3Digest(512);
- case DigestAlgorithm.SHAKE128: return new ShakeDigest(128);
- case DigestAlgorithm.SHAKE256: return new ShakeDigest(256);
- case DigestAlgorithm.TIGER: return new TigerDigest();
- case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest();
+ case DigestAlgorithm.BLAKE2B_160: return new Blake2bDigest(160);
+ case DigestAlgorithm.BLAKE2B_256: return new Blake2bDigest(256);
+ case DigestAlgorithm.BLAKE2B_384: return new Blake2bDigest(384);
+ case DigestAlgorithm.BLAKE2B_512: return new Blake2bDigest(512);
+ case DigestAlgorithm.BLAKE2S_128: return new Blake2sDigest(128);
+ case DigestAlgorithm.BLAKE2S_160: return new Blake2sDigest(160);
+ case DigestAlgorithm.BLAKE2S_224: return new Blake2sDigest(224);
+ case DigestAlgorithm.BLAKE2S_256: return new Blake2sDigest(256);
+ case DigestAlgorithm.DSTU7564_256: return new Dstu7564Digest(256);
+ case DigestAlgorithm.DSTU7564_384: return new Dstu7564Digest(384);
+ case DigestAlgorithm.DSTU7564_512: return new Dstu7564Digest(512);
+ case DigestAlgorithm.GOST3411: return new Gost3411Digest();
+ case DigestAlgorithm.GOST3411_2012_256: return new GOST3411_2012_256Digest();
+ case DigestAlgorithm.GOST3411_2012_512: return new GOST3411_2012_512Digest();
+ case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224);
+ case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256);
+ case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288);
+ case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384);
+ case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512);
+ case DigestAlgorithm.MD2: return new MD2Digest();
+ case DigestAlgorithm.MD4: return new MD4Digest();
+ case DigestAlgorithm.MD5: return new MD5Digest();
+ case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest();
+ case DigestAlgorithm.RIPEMD160: return new RipeMD160Digest();
+ case DigestAlgorithm.RIPEMD256: return new RipeMD256Digest();
+ case DigestAlgorithm.RIPEMD320: return new RipeMD320Digest();
+ case DigestAlgorithm.SHA_1: return new Sha1Digest();
+ case DigestAlgorithm.SHA_224: return new Sha224Digest();
+ case DigestAlgorithm.SHA_256: return new Sha256Digest();
+ case DigestAlgorithm.SHA_384: return new Sha384Digest();
+ case DigestAlgorithm.SHA_512: return new Sha512Digest();
+ case DigestAlgorithm.SHA_512_224: return new Sha512tDigest(224);
+ case DigestAlgorithm.SHA_512_256: return new Sha512tDigest(256);
+ case DigestAlgorithm.SHA3_224: return new Sha3Digest(224);
+ case DigestAlgorithm.SHA3_256: return new Sha3Digest(256);
+ case DigestAlgorithm.SHA3_384: return new Sha3Digest(384);
+ case DigestAlgorithm.SHA3_512: return new Sha3Digest(512);
+ case DigestAlgorithm.SHAKE128: return new ShakeDigest(128);
+ case DigestAlgorithm.SHAKE256: return new ShakeDigest(256);
+ case DigestAlgorithm.SM3: return new SM3Digest();
+ case DigestAlgorithm.TIGER: return new TigerDigest();
+ case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest();
}
}
catch (ArgumentException)
|