summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2017-06-25 18:08:58 +1000
committerDavid Hook <dgh@bouncycastle.org>2017-06-25 18:08:58 +1000
commit7b7e632102dc6e27f6183d86fd423e2be9e58696 (patch)
treea8b949a3e39f4121b86344d0ea861a979cb315e9 /crypto/src
parentUse slightly improved addition chain for sm2p256v1 field sqrt (diff)
downloadBouncyCastle.NET-ed25519-7b7e632102dc6e27f6183d86fd423e2be9e58696.tar.xz
Initial cut of DSTU7564 digest and HMAC.
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/digests/DSTU7564Digest.cs550
-rw-r--r--crypto/src/crypto/macs/DSTU7564Mac.cs156
2 files changed, 706 insertions, 0 deletions
diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs
new file mode 100644
index 000000000..9a785a5c9
--- /dev/null
+++ b/crypto/src/crypto/digests/DSTU7564Digest.cs
@@ -0,0 +1,550 @@
+using System;
+
+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;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+     /**
+	* implementation of Ukrainian DSTU 7564 hash function
+	*/
+     public class Dstu7564Digest : IDigest, IMemoable
+     {
+          private const int ROWS = 8;
+          private const int REDUCTION_POLYNOMIAL = 0x011d;
+          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 int bufOff;
+        private byte[] buf;
+
+        public Dstu7564Digest(Dstu7564Digest digest)
+        {
+            copyIn(digest);
+        }
+
+        private void copyIn(Dstu7564Digest digest)
+        {
+            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++)
+            {
+                this.state_[i] = Arrays.Clone(digest.state_[i]);
+            }
+
+            this.inputLength = digest.inputLength;
+            this.bufOff = digest.bufOff;
+            this.buf = Arrays.Clone(digest.buf);
+        }
+
+        public Dstu7564Digest(int hashSizeBits)
+          {
+               if (hashSizeBits == 256 || hashSizeBits == 384 || hashSizeBits == 512)
+               {
+                    this.hashSize = hashSizeBits / 8;
+               }
+               else
+               {
+                    throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size");
+               }
+
+               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][];
+
+               }
+
+               //Console.WriteLine("length: " + state_.Length);
+
+               for (int i = 0; i < state_.Length; i++)
+               {
+                    this.state_[i] = new byte[columns];
+               }
+
+               this.state_[0][0] = (byte)state_.Length;
+               
+               this.hashSize = hashSizeBits / 8;
+
+               this.padded_ = null;
+               this.buf = new byte[blockSize];
+        }
+
+          public string AlgorithmName
+          {
+               get { return "DSTU7564"; }
+          }
+
+
+          public virtual void BlockUpdate(byte[] input, int inOff, int length)
+          {
+            while (bufOff != 0 && length > 0)
+            {
+                Update(input[inOff++]);
+                length--;
+            }
+
+            if (length > 0)
+            {
+                while (length > blockSize)
+                {
+                    ProcessBlock(input, inOff);
+                    inOff += blockSize;
+                    inputLength += (ulong)blockSize;
+                    length -= blockSize;
+                }
+
+                while (length > 0)
+                {
+                    Update(input[inOff++]);
+                    length--;
+                }
+            }
+        }
+
+          protected byte[] Pad(byte[] input, int inOff, int length)
+          {
+            //Console.WriteLine(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 void ProcessBlock(byte[] input, int inOff)
+          {
+               byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][];
+               byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][];
+
+               for (int i = 0; i < state_.Length; i++)
+               {
+                    temp1[i] = new byte[ROWS];
+                    temp2[i] = new byte[ROWS];
+               }
+               
+               for (int i = 0; i < ROWS; ++i)
+               {
+                    for (int j = 0; j < columns; ++j)
+                    {
+                         //Console.WriteLine("row = {0}, column = {1}", i, j);
+
+                         temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]);
+                         temp2[j][i] = input[j * ROWS + i + inOff];
+
+                    }
+                    
+               }
+
+               P(temp1);
+
+               Q(temp2);
+
+               for (int i = 0; i < ROWS; ++i)
+               {
+                    for (int j = 0; j < columns; ++j)
+                    {
+                         state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]);
+
+                    }
+ 
+               }
+          }
+
+          public int DoFinal(byte[] output, int outOff)
+          {
+            padded_ = Pad(buf, 0, bufOff);
+
+            ProcessBlock(padded_, 0);
+
+ 
+               //Console.WriteLine(stateLine.Length);
+
+               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);
+               }
+
+            P(temp);
+
+            for (int i = 0; i < ROWS; ++i)
+            {
+                 for (int j = 0; j < columns; ++j)
+                 {
+                      state_[j][i] ^= temp[j][i];
+                      //Console.Write("{0:x} ", state_[j][i]);
+                 }
+                 //Console.WriteLine();
+            }
+
+            byte[] stateLine = new byte[ROWS * columns];
+            int stateLineIndex = 0;
+               for (int j = 0; j < columns; ++j)
+               {
+                    for (int i = 0; i < ROWS; ++i)
+                    {
+                    
+                         stateLine[stateLineIndex] = state_[j][i];
+                         stateLineIndex++;
+
+                         //Console.WriteLine("index = {0}, row = {1}, column = {2}", stateLineIndex, i, j);
+
+                    }
+               }
+               
+               //Console.WriteLine("final: " + Hex.ToHexString(stateLine));
+               //Console.WriteLine(stateLine.Length);
+               
+               Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize);
+
+                Reset();
+
+               return hashSize;
+          }
+
+          public void Reset()
+          {
+            for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++)
+            {
+                state_[bufferIndex] = new byte[columns];
+            }
+
+            state_[0][0] = (byte)state_.Length;
+
+            inputLength = 0;
+            bufOff = 0;
+
+            Arrays.Fill(buf, (byte)0);
+            Arrays.Fill(padded_, (byte)0);
+        }
+
+          public int GetDigestSize()
+          {
+               return hashSize;
+          }
+
+          public int GetByteLength()
+          {
+               return blockSize;
+          }
+
+          public void Update(byte input)
+          {
+            buf[bufOff++] = input;
+            if (bufOff == blockSize)
+            {
+                ProcessBlock(buf, 0);
+                bufOff = 0;
+            }
+            inputLength++;
+          }
+
+        void SubBytes(byte[][] state)
+          {
+               int i, j;
+               for (i = 0; i < ROWS; ++i)
+               {
+                    for (j = 0; j < columns; ++j)
+                    {
+                         state[j][i] = sBoxes[i % 4][state[j][i]];
+                    }
+               }
+          }
+
+          void ShiftBytes(byte[][] state)
+          {
+               int i, j;
+               byte[] temp = new byte[NB_1024];
+               int shift = -1;
+               for (i = 0; i < ROWS; ++i)
+               {
+                    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)
+                    {
+                         state[j][i] = temp[j];
+                    }
+               }
+          }
+
+          byte MultiplyGF(byte x, byte y)
+          {
+               int i;
+               byte r = 0;
+               byte hbit = 0;
+               for (i = 0; i < BITS_IN_BYTE; ++i)
+               {
+                    if ((y & 0x1) == 1)
+                    {
+                         r ^= x;
+                    }
+
+                    hbit = (byte)(x & 0x80);
+
+                    x <<= 1;
+
+                    if (hbit == 0x80)
+                    {
+                         x = (byte)((int)x ^ REDUCTION_POLYNOMIAL);
+                    }
+
+                    y >>= 1;
+               }
+               return r;
+          }
+
+          private void MixColumns(byte[][] state)
+          {
+               int i, row, col, b;
+               byte product;
+               byte[] result = new byte[ROWS];
+
+               for (col = 0; col < columns; ++col)
+               {
+                    Array.Clear(result, 0, ROWS);
+                    for (row = ROWS - 1; row >= 0; --row)
+                    {
+                         product = 0;
+                         for (b = ROWS - 1; b >= 0; --b)
+                         {
+                              product ^= MultiplyGF(state[col][b], mds_matrix[row][b]);
+                         }
+                         result[row] = product;
+                    }
+                    for (i = 0; i < ROWS; ++i)
+                    {
+                         state[col][i] = result[i];
+                    }
+               }
+          }
+
+          void AddRoundConstantP(byte[][] state, int round)
+          {
+               int i;
+               for (i = 0; i < columns; ++i)
+               {
+                    state[i][0] ^= (byte)((i * 0x10) ^ round);
+               }
+          }
+
+          void AddRoundConstantQ(byte[][] state, int round)
+          {
+               int j;
+               UInt64[] s = new UInt64[columns];
+
+               for (j = 0; j < columns; j++)
+               {
+                    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]);
+               }
+          }
+
+          void P(byte[][] state)
+          {
+               int i;
+               for (i = 0; i < rounds; ++i)
+               {
+                    AddRoundConstantP(state, i);
+                    SubBytes(state);
+                    ShiftBytes(state);
+                    MixColumns(state);
+               }
+          }
+
+          void Q(byte[][] state)
+          {
+               int i;
+               for (i = 0; i < rounds; ++i)
+               {
+                    AddRoundConstantQ(state, i);
+                    SubBytes(state);
+                    ShiftBytes(state);
+                    MixColumns(state);
+               }
+          }
+
+        public IMemoable Copy()
+        {
+            return new Dstu7564Digest(this);
+        }
+
+        public void Reset(IMemoable other)
+        {
+            Dstu7564Digest d = (Dstu7564Digest)other;
+
+            copyIn(d);
+        }
+
+        private readonly byte[][] mds_matrix = new byte[][]
+          { 
+               new byte[] {0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04},
+	          new byte[] {0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07},
+	          new byte[] {0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06},
+	          new byte[] {0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08},
+	          new byte[] {0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01},
+	          new byte[] {0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05},
+	          new byte[] {0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01},
+               new byte[] {0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01}
+          };
+
+
+
+
+          private 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/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
new file mode 100644
index 000000000..a5f984270
--- /dev/null
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+     /// <summary>
+     /// Implementation of DSTU7564 mac mode
+     /// </summary>
+     public class DSTU7564Mac : IMac
+     {
+          private Dstu7564Digest engine;
+          private int macSize;
+
+        private ulong inputLength;
+
+        byte[] paddedKey;
+          byte[] invertedKey;
+          byte[] paddedInput;
+
+        public string AlgorithmName
+        {
+            get
+            {
+                return "DSTU7564Mac";
+            }
+        }
+
+        public DSTU7564Mac(int macSizeBits)
+          {
+            engine = new Dstu7564Digest(macSizeBits);
+            macSize = macSizeBits / 8;
+          }
+
+          public void Init(ICipherParameters parameters)
+          {
+            if (parameters is KeyParameter)
+        {
+                byte[] key = ((KeyParameter)parameters).GetKey();
+
+                invertedKey = new byte[key.Length];
+
+                paddedKey = PadKey(key);
+
+                for (int byteIndex = 0; byteIndex < invertedKey.Length; byteIndex++)
+                {
+                    invertedKey[byteIndex] = (byte)(key[byteIndex] ^ (byte)0xFF);
+                }
+            }
+        else
+        {
+                throw new ArgumentException("Bad parameter passed");
+            }
+
+            engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+        }
+
+          public int GetMacSize()
+          {
+               return macSize;
+          }
+
+          public void BlockUpdate(byte[] input, int inOff, int len)
+          {
+            if (input.Length - inOff < len)
+            {
+                throw new DataLengthException("Input buffer too short");
+            }
+
+            if (paddedKey == null)
+            {
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            }
+
+            engine.BlockUpdate(input, inOff, len);
+            inputLength += (ulong)len;
+
+          }
+
+        public void Update(byte input)
+        {
+            engine.Update(input);
+            inputLength++;
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (output.Length - outOff < macSize)
+            {
+                throw new DataLengthException("Output buffer too short");
+            }
+            if (paddedKey == null)
+            {
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            }
+
+            Pad();
+
+            engine.BlockUpdate(invertedKey, 0, invertedKey.Length);
+
+            inputLength = 0;
+
+            return engine.DoFinal(output, outOff);
+        }
+
+        public void Reset()
+        {
+            inputLength = 0;
+            engine.Reset();
+            if (paddedKey != null)
+            {
+                engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+            }
+        }
+
+        private void Pad()
+        {
+            int extra = engine.GetByteLength() - (int)(inputLength % (ulong)engine.GetByteLength());
+            if (extra < 13)  // terminator byte + 96 bits of length
+            {
+                extra += engine.GetByteLength();
+            }
+
+            byte[] padded = new byte[extra];
+
+            padded[0] = (byte)0x80; // Defined in standard;
+
+            // Defined in standard;
+            Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
+
+            engine.BlockUpdate(padded, 0, padded.Length);
+        }
+
+        private byte[] PadKey(byte[] input)
+        {
+            int paddedLen = ((input.Length + engine.GetByteLength() - 1) / engine.GetByteLength()) *engine.GetByteLength();
+
+            int extra = engine.GetByteLength() - (int)(input.Length % engine.GetByteLength());
+            if (extra < 13)  // terminator byte + 96 bits of length
+            {
+                paddedLen += engine.GetByteLength();
+            }
+
+            byte[] padded = new byte[paddedLen];
+
+            Array.Copy(input, 0, padded, 0, input.Length);
+
+            padded[input.Length] = (byte)0x80; // Defined in standard;
+            Pack.UInt32_To_LE((uint)(input.Length * 8), padded, padded.Length - 12); // Defined in standard;
+
+            return padded;
+        }
+    }
+}