summary refs log tree commit diff
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2017-08-12 16:01:46 -0400
committerOren Novotny <oren@novotny.org>2017-08-12 16:01:46 -0400
commit8cfb208a2ff65ec9a57e71b8e28715e88c3e1267 (patch)
treeca93f04d29ad042ba22c98ff5b90dad6be78dc1d
parentFix ups after merge from master (diff)
parentCan't use MemoryStream.GetBuffer under PORTABLE (diff)
downloadBouncyCastle.NET-ed25519-8cfb208a2ff65ec9a57e71b8e28715e88c3e1267.tar.xz
merge from master
-rw-r--r--crypto/crypto.csproj76
-rw-r--r--crypto/src/crypto/digests/KeccakDigest.cs451
-rw-r--r--crypto/src/crypto/digests/SHA3Digest.cs5
-rw-r--r--crypto/src/crypto/digests/ShakeDigest.cs12
-rw-r--r--crypto/src/crypto/modes/KCcmBlockCipher.cs59
-rw-r--r--crypto/src/crypto/util/Pack.cs34
-rw-r--r--crypto/src/openpgp/PgpPublicKey.cs33
7 files changed, 354 insertions, 316 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 026a2fe1b..a80ac39ea 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -3309,6 +3309,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\digests\DSTU7564Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\digests\GeneralDigest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3319,6 +3324,21 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\digests\GOST3411_2012Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\GOST3411_2012_256Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\GOST3411_2012_512Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\digests\KeccakDigest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3539,6 +3559,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\engines\Dstu7624Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\Dstu7624WrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\engines\ElGamalEngine.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3909,6 +3939,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\macs\DSTU7564Mac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\DSTU7624Mac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\macs\GMac.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3979,17 +4019,27 @@
                     BuildAction = "Compile"
                 />
                 <File
-                    RelPath = "src\crypto\modes\OCBBlockCipher.cs"
+                    RelPath = "src\crypto\modes\GOFBBlockCipher.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
                 />
                 <File
-                    RelPath = "src\crypto\modes\GOFBBlockCipher.cs"
+                    RelPath = "src\crypto\modes\IAeadBlockCipher.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
                 />
                 <File
-                    RelPath = "src\crypto\modes\IAeadBlockCipher.cs"
+                    RelPath = "src\crypto\modes\KCcmBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\KCtrBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\OCBBlockCipher.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
                 />
@@ -11420,6 +11470,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\DSTU7564Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DSTU7624Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\EAXTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -11500,6 +11560,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\crypto\test\GOST3411_2012_256DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GOST3411_2012_512DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\crypto\test\HCFamilyTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
index 20aa225b8..8b16e5d3a 100644
--- a/crypto/src/crypto/digests/KeccakDigest.cs
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -1,5 +1,7 @@
 using System;
+using System.Diagnostics;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -56,12 +58,11 @@ namespace Org.BouncyCastle.Crypto.Digests
             int x, y, t, newX, newY;
 
             int rhoOffset = 0;
-            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
+            keccakRhoOffsets[0] = rhoOffset;
             x = 1;
             y = 0;
             for (t = 1; t < 25; t++)
             {
-                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
                 rhoOffset = (rhoOffset + t) & 63;
                 keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
                 newX = (0 * x + 1 * y) % 5;
@@ -73,23 +74,15 @@ namespace Org.BouncyCastle.Crypto.Digests
             return keccakRhoOffsets;
         }
 
-        protected byte[] state = new byte[(1600 / 8)];
-        protected byte[] dataQueue = new byte[(1536 / 8)];
+        private static readonly int STATE_LENGTH = (1600 / 8);
+
+        private ulong[] state = new ulong[STATE_LENGTH / 8];
+        protected byte[] dataQueue = new byte[1536 / 8];
         protected int rate;
         protected int bitsInQueue;
         protected int fixedOutputLength;
         protected bool squeezing;
         protected int bitsAvailableForSqueezing;
-        protected byte[] chunk;
-        protected byte[] oneByte;
-
-        private void ClearDataQueueSection(int off, int len)
-        {
-            for (int i = off; i != off + len; i++)
-            {
-                dataQueue[i] = 0;
-            }
-        }
 
         public KeccakDigest()
             : this(288)
@@ -115,8 +108,6 @@ namespace Org.BouncyCastle.Crypto.Digests
             this.fixedOutputLength = source.fixedOutputLength;
             this.squeezing = source.squeezing;
             this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
-            this.chunk = Arrays.Clone(source.chunk);
-            this.oneByte = Arrays.Clone(source.oneByte);
         }
 
         public virtual string AlgorithmName
@@ -126,24 +117,22 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         public virtual int GetDigestSize()
         {
-            return fixedOutputLength / 8;
+            return fixedOutputLength >> 3;
         }
 
         public virtual void Update(byte input)
         {
-            oneByte[0] = input;
-
-            Absorb(oneByte, 0, 8L);
+            Absorb(new byte[]{ input }, 0, 1);
         }
 
         public virtual void BlockUpdate(byte[] input, int inOff, int len)
         {
-            Absorb(input, inOff, len * 8L);
+            Absorb(input, inOff, len);
         }
 
         public virtual int DoFinal(byte[] output, int outOff)
         {
-            Squeeze(output, outOff, fixedOutputLength);
+            Squeeze(output, outOff, fixedOutputLength >> 3);
 
             Reset();
 
@@ -157,11 +146,10 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             if (partialBits > 0)
             {
-                oneByte[0] = partialByte;
-                Absorb(oneByte, 0, partialBits);
+                AbsorbBits(partialByte, partialBits);
             }
 
-            Squeeze(output, outOff, fixedOutputLength);
+            Squeeze(output, outOff, fixedOutputLength >> 3);
 
             Reset();
 
@@ -180,7 +168,7 @@ namespace Org.BouncyCastle.Crypto.Digests
          */
         public virtual int GetByteLength()
         {
-            return rate / 8;
+            return rate >> 3;
         }
 
         private void Init(int bitLength)
@@ -188,242 +176,170 @@ namespace Org.BouncyCastle.Crypto.Digests
             switch (bitLength)
             {
                 case 128:
-                    InitSponge(1344, 256);
-                    break;
                 case 224:
-                    InitSponge(1152, 448);
-                    break;
                 case 256:
-                    InitSponge(1088, 512);
-                    break;
                 case 288:
-                    InitSponge(1024, 576);
-                    break;
                 case 384:
-                    InitSponge(832, 768);
-                    break;
                 case 512:
-                    InitSponge(576, 1024);
+                    InitSponge(1600 - (bitLength << 1));
                     break;
                 default:
                     throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
             }
         }
 
-        private void InitSponge(int rate, int capacity)
+        private void InitSponge(int rate)
         {
-            if (rate + capacity != 1600)
-            {
-                throw new InvalidOperationException("rate + capacity != 1600");
-            }
-            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
-            {
+            if (rate <= 0 || rate >= 1600 || (rate & 63) != 0)
                 throw new InvalidOperationException("invalid rate value");
-            }
 
             this.rate = rate;
-            // this is never read, need to check to see why we want to save it
-            //  this.capacity = capacity;
-            this.fixedOutputLength = 0;
-            Arrays.Fill(this.state, (byte)0);
+            Array.Clear(state, 0, state.Length);
             Arrays.Fill(this.dataQueue, (byte)0);
             this.bitsInQueue = 0;
             this.squeezing = false;
             this.bitsAvailableForSqueezing = 0;
-            this.fixedOutputLength = capacity / 2;
-            this.chunk = new byte[rate / 8];
-            this.oneByte = new byte[1];
+            this.fixedOutputLength = (1600 - rate) >> 1;
         }
 
-        private void AbsorbQueue()
+        protected void Absorb(byte[] data, int off, int len)
         {
-            KeccakAbsorb(state, dataQueue, rate / 8);
-
-            bitsInQueue = 0;
-        }
-
-        protected virtual void Absorb(byte[] data, int off, long databitlen)
-        {
-            long i, j, wholeBlocks;
-
-            if ((bitsInQueue % 8) != 0)
-            {
+            if ((bitsInQueue & 7) != 0)
                 throw new InvalidOperationException("attempt to absorb with odd length queue");
-            }
             if (squeezing)
-            {
                 throw new InvalidOperationException("attempt to absorb while squeezing");
-            }
 
-            i = 0;
-            while (i < databitlen)
+            int bytesInQueue = bitsInQueue >> 3;
+            int rateBytes = rate >> 3;
+
+            int count = 0;
+            while (count < len)
             {
-                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
+                if (bytesInQueue == 0 && count <= (len - rateBytes))
                 {
-                    wholeBlocks = (databitlen - i) / rate;
-
-                    for (j = 0; j < wholeBlocks; j++)
+                    do
                     {
-                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
-
-                        KeccakAbsorb(state, chunk, chunk.Length);
+                        KeccakAbsorb(data, off + count);
+                        count += rateBytes;
                     }
-
-                    i += wholeBlocks * rate;
+                    while (count <= (len - rateBytes));
                 }
                 else
                 {
-                    int partialBlock = (int)(databitlen - i);
-                    if (partialBlock + bitsInQueue > rate)
-                    {
-                        partialBlock = rate - bitsInQueue;
-                    }
-                    int partialByte = partialBlock % 8;
-                    partialBlock -= partialByte;
-                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
+                    int partialBlock = System.Math.Min(rateBytes - bytesInQueue, len - count);
+                    Array.Copy(data, off + count, dataQueue, bytesInQueue, partialBlock);
 
-                    bitsInQueue += partialBlock;
-                    i += partialBlock;
-                    if (bitsInQueue == rate)
-                    {
-                        AbsorbQueue();
-                    }
-                    if (partialByte > 0)
+                    bytesInQueue += partialBlock;
+                    count += partialBlock;
+
+                    if (bytesInQueue == rateBytes)
                     {
-                        int mask = (1 << partialByte) - 1;
-                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
-                        bitsInQueue += partialByte;
-                        i += partialByte;
+                        KeccakAbsorb(dataQueue, 0);
+                        bytesInQueue = 0;
                     }
                 }
             }
+
+            bitsInQueue = bytesInQueue << 3;
+        }
+
+        protected void AbsorbBits(int data, int bits)
+        {
+            if (bits < 1 || bits > 7)
+                throw new ArgumentException("must be in the range 1 to 7", "bits");
+            if ((bitsInQueue & 7) != 0)
+                throw new InvalidOperationException("attempt to absorb with odd length queue");
+            if (squeezing)
+                throw new InvalidOperationException("attempt to absorb while squeezing");
+
+            int mask = (1 << bits) - 1;
+            dataQueue[bitsInQueue >> 3] = (byte)(data & mask);
+
+            // NOTE: After this, bitsInQueue is no longer a multiple of 8, so no more absorbs will work
+            bitsInQueue += bits;
         }
 
         private void PadAndSwitchToSqueezingPhase()
         {
-            if (bitsInQueue + 1 == rate)
-            {
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-                AbsorbQueue();
-                ClearDataQueueSection(0, rate / 8);
-            }
-            else
-            {
-                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-            }
-            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
-            AbsorbQueue();
+            Debug.Assert(bitsInQueue < rate);
 
-            if (rate == 1024)
+            dataQueue[bitsInQueue >> 3] |= (byte)(1U << (bitsInQueue & 7));
+
+            if (++bitsInQueue == rate)
             {
-                KeccakExtract1024bits(state, dataQueue);
-                bitsAvailableForSqueezing = 1024;
+                KeccakAbsorb(dataQueue, 0);
+                bitsInQueue = 0;
             }
-            else
+
             {
-                KeccakExtract(state, dataQueue, rate / 64);
-                bitsAvailableForSqueezing = rate;
+                int full = bitsInQueue >> 6, partial = bitsInQueue & 63;
+                int off = 0;
+                for (int i = 0; i < full; ++i)
+                {
+                    state[i] ^= Pack.LE_To_UInt64(dataQueue, off);
+                    off += 8;
+                }
+                if (partial > 0)
+                {
+                    ulong mask = (1UL << partial) - 1UL;
+                    state[full] ^= Pack.LE_To_UInt64(dataQueue, off) & mask;
+                }
+                state[(rate - 1) >> 6] ^= (1UL << 63);
             }
 
+            KeccakPermutation();
+            KeccakExtract();
+            bitsAvailableForSqueezing = rate;
+
+            bitsInQueue = 0;
             squeezing = true;
         }
 
-        protected virtual void Squeeze(byte[] output, int offset, long outputLength)
+        protected void Squeeze(byte[] output, int off, int len)
         {
-            long i;
-            int partialBlock;
-
             if (!squeezing)
             {
                 PadAndSwitchToSqueezingPhase();
             }
-            if ((outputLength % 8) != 0)
-            {
-                throw new InvalidOperationException("outputLength not a multiple of 8");
-            }
 
-            i = 0;
+            long outputLength = (long)len << 3;
+            long i = 0;
             while (i < outputLength)
             {
                 if (bitsAvailableForSqueezing == 0)
                 {
-                    KeccakPermutation(state);
-
-                    if (rate == 1024)
-                    {
-                        KeccakExtract1024bits(state, dataQueue);
-                        bitsAvailableForSqueezing = 1024;
-                    }
-                    else
-                    {
-                        KeccakExtract(state, dataQueue, rate / 64);
-                        bitsAvailableForSqueezing = rate;
-                    }
-                }
-                partialBlock = bitsAvailableForSqueezing;
-                if ((long)partialBlock > outputLength - i)
-                {
-                    partialBlock = (int)(outputLength - i);
+                    KeccakPermutation();
+                    KeccakExtract();
+                    bitsAvailableForSqueezing = rate;
                 }
 
-                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
+                int partialBlock = (int)System.Math.Min((long)bitsAvailableForSqueezing, outputLength - i);
+                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) >> 3, output, off + (int)(i >> 3), partialBlock >> 3);
                 bitsAvailableForSqueezing -= partialBlock;
                 i += partialBlock;
             }
         }
 
-        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
-        {
-            for (int i = 0; i < (1600 / 64); i++)
-            {
-                stateAsWords[i] = 0;
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
-                }
-            }
-        }
-
-        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        private void KeccakAbsorb(byte[] data, int off)
         {
-            for (int i = 0; i < (1600 / 64); i++)
+            int count = rate >> 6;
+            for (int i = 0; i < count; ++i)
             {
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
-                }
+                state[i] ^= Pack.LE_To_UInt64(data, off);
+                off += 8;
             }
-        }
-
-        private void KeccakPermutation(byte[] state)
-        {
-            ulong[] longState = new ulong[state.Length / 8];
-
-            FromBytesToWords(longState, state);
 
-            KeccakPermutationOnWords(longState);
-
-            FromWordsToBytes(state, longState);
+            KeccakPermutation();
         }
 
-        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        private void KeccakExtract()
         {
-            for (int i = 0; i < dataLengthInBytes; i++)
-            {
-                state[i] ^= data[i];
-            }
-
-            KeccakPermutation(state);
+            Pack.UInt64_To_LE(state, 0, rate >> 6, dataQueue, 0);
         }
 
-        private void KeccakPermutationOnWords(ulong[] state)
+        private void KeccakPermutation()
         {
-            int i;
-
-            for (i = 0; i < 24; i++)
+            for (int i = 0; i < 24; i++)
             {
                 Theta(state);
                 Rho(state);
@@ -433,90 +349,121 @@ namespace Org.BouncyCastle.Crypto.Digests
             }
         }
 
-        ulong[] C = new ulong[5];
-
-        private void Theta(ulong[] A)
+        private static ulong leftRotate(ulong v, int r)
         {
-            for (int x = 0; x < 5; x++)
-            {
-                C[x] = 0;
-                for (int y = 0; y < 5; y++)
-                {
-                    C[x] ^= A[x + 5 * y];
-                }
-            }
-            for (int x = 0; x < 5; x++)
-            {
-                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
-                for (int y = 0; y < 5; y++)
-                {
-                    A[x + 5 * y] ^= dX;
-                }
-            }
+            return (v << r) | (v >> -r);
         }
 
-        private void Rho(ulong[] A)
+        private static void Theta(ulong[] A)
         {
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    int index = x + 5 * y;
-                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
-                }
-            }
-        }
+            ulong C0 = A[0 + 0] ^ A[0 + 5] ^ A[0 + 10] ^ A[0 + 15] ^ A[0 + 20];
+            ulong C1 = A[1 + 0] ^ A[1 + 5] ^ A[1 + 10] ^ A[1 + 15] ^ A[1 + 20];
+            ulong C2 = A[2 + 0] ^ A[2 + 5] ^ A[2 + 10] ^ A[2 + 15] ^ A[2 + 20];
+            ulong C3 = A[3 + 0] ^ A[3 + 5] ^ A[3 + 10] ^ A[3 + 15] ^ A[3 + 20];
+            ulong C4 = A[4 + 0] ^ A[4 + 5] ^ A[4 + 10] ^ A[4 + 15] ^ A[4 + 20];
 
-        ulong[] tempA = new ulong[25];
+            ulong dX = leftRotate(C1, 1) ^ C4;
 
-        private void Pi(ulong[] A)
-        {
-            Array.Copy(A, 0, tempA, 0, tempA.Length);
+            A[0] ^= dX;
+            A[5] ^= dX;
+            A[10] ^= dX;
+            A[15] ^= dX;
+            A[20] ^= dX;
 
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
-                }
-            }
-        }
+            dX = leftRotate(C2, 1) ^ C0;
 
-        ulong[] chiC = new ulong[5];
+            A[1] ^= dX;
+            A[6] ^= dX;
+            A[11] ^= dX;
+            A[16] ^= dX;
+            A[21] ^= dX;
 
-        private void Chi(ulong[] A)
-        {
-            for (int y = 0; y < 5; y++)
-            {
-                for (int x = 0; x < 5; x++)
-                {
-                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
-                }
-                for (int x = 0; x < 5; x++)
-                {
-                    A[x + 5 * y] = chiC[x];
-                }
-            }
-        }
+            dX = leftRotate(C3, 1) ^ C1;
 
-        private static void Iota(ulong[] A, int indexRound)
-        {
-            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
+            A[2] ^= dX;
+            A[7] ^= dX;
+            A[12] ^= dX;
+            A[17] ^= dX;
+            A[22] ^= dX;
+
+            dX = leftRotate(C4, 1) ^ C2;
+
+            A[3] ^= dX;
+            A[8] ^= dX;
+            A[13] ^= dX;
+            A[18] ^= dX;
+            A[23] ^= dX;
+
+            dX = leftRotate(C0, 1) ^ C3;
+
+            A[4] ^= dX;
+            A[9] ^= dX;
+            A[14] ^= dX;
+            A[19] ^= dX;
+            A[24] ^= dX;
         }
 
-        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
+        private static void Rho(ulong[] A)
         {
-            KeccakPermutationAfterXor(byteState, data, dataInBytes);
+            // KeccakRhoOffsets[0] == 0
+            for (int x = 1; x < 25; x++)
+            {
+                A[x] = leftRotate(A[x], KeccakRhoOffsets[x]);
+            }
         }
 
-        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
-        {
-            Array.Copy(byteState, 0, data, 0, 128);
+        private static void Pi(ulong[] A)
+        {
+            ulong a1 = A[1];
+            A[1] = A[6];
+            A[6] = A[9];
+            A[9] = A[22];
+            A[22] = A[14];
+            A[14] = A[20];
+            A[20] = A[2];
+            A[2] = A[12];
+            A[12] = A[13];
+            A[13] = A[19];
+            A[19] = A[23];
+            A[23] = A[15];
+            A[15] = A[4];
+            A[4] = A[24];
+            A[24] = A[21];
+            A[21] = A[8];
+            A[8] = A[16];
+            A[16] = A[5];
+            A[5] = A[3];
+            A[3] = A[18];
+            A[18] = A[17];
+            A[17] = A[11];
+            A[11] = A[7];
+            A[7] = A[10];
+            A[10] = a1;
+        }
+
+        private static void Chi(ulong[] A)
+        {
+            ulong chiC0, chiC1, chiC2, chiC3, chiC4;
+
+            for (int yBy5 = 0; yBy5 < 25; yBy5 += 5)
+            {
+                chiC0 = A[0 + yBy5] ^ ((~A[(((0 + 1) % 5) + yBy5)]) & A[(((0 + 2) % 5) + yBy5)]);
+                chiC1 = A[1 + yBy5] ^ ((~A[(((1 + 1) % 5) + yBy5)]) & A[(((1 + 2) % 5) + yBy5)]);
+                chiC2 = A[2 + yBy5] ^ ((~A[(((2 + 1) % 5) + yBy5)]) & A[(((2 + 2) % 5) + yBy5)]);
+                chiC3 = A[3 + yBy5] ^ ((~A[(((3 + 1) % 5) + yBy5)]) & A[(((3 + 2) % 5) + yBy5)]);
+                chiC4 = A[4 + yBy5] ^ ((~A[(((4 + 1) % 5) + yBy5)]) & A[(((4 + 2) % 5) + yBy5)]);
+
+                A[0 + yBy5] = chiC0;
+                A[1 + yBy5] = chiC1;
+                A[2 + yBy5] = chiC2;
+                A[3 + yBy5] = chiC3;
+                A[4 + yBy5] = chiC4;
+            }
         }
 
-        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
+        private static void Iota(ulong[] A, int indexRound)
         {
-            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+            A[0] ^= KeccakRoundConstants[indexRound];
         }
 
         public virtual IMemoable Copy()
@@ -526,9 +473,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         public virtual void Reset(IMemoable other)
         {
-            KeccakDigest d = (KeccakDigest)other;
-
-            CopyIn(d);
+            CopyIn((KeccakDigest)other);
         }
     }
 }
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index 890b665cf..4683af5b3 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         public override int DoFinal(byte[] output, int outOff)
         {
-            Absorb(new byte[]{ 0x02 }, 0, 2);
+            AbsorbBits(0x02, 2);
 
             return base.DoFinal(output,  outOff);
         }
@@ -69,8 +69,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 
             if (finalBits >= 8)
             {
-                oneByte[0] = (byte)finalInput;
-                Absorb(oneByte, 0, 8);
+                Absorb(new byte[]{ (byte)finalInput }, 0, 1);
                 finalBits -= 8;
                 finalInput >>= 8;
             }
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
index a7bddccba..13e8838c1 100644
--- a/crypto/src/crypto/digests/ShakeDigest.cs
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -64,10 +64,10 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             if (!squeezing)
             {
-                Absorb(new byte[] { 0x0F }, 0, 4);
+                AbsorbBits(0x0F, 4);
             }
 
-            Squeeze(output, outOff, ((long)outLen) * 8);
+            Squeeze(output, outOff, outLen);
 
             return outLen;
         }
@@ -94,19 +94,17 @@ namespace Org.BouncyCastle.Crypto.Digests
 
             if (finalBits >= 8)
             {
-                oneByte[0] = (byte)finalInput;
-                Absorb(oneByte, 0, 8);
+                Absorb(new byte[]{ (byte)finalInput }, 0, 1);
                 finalBits -= 8;
                 finalInput >>= 8;
             }
 
             if (finalBits > 0)
             {
-                oneByte[0] = (byte)finalInput;
-                Absorb(oneByte, 0, finalBits);
+                AbsorbBits(finalInput, finalBits);
             }
 
-            Squeeze(output, outOff, ((long)outLen) * 8);
+            Squeeze(output, outOff, outLen);
 
             Reset();
 
diff --git a/crypto/src/crypto/modes/KCcmBlockCipher.cs b/crypto/src/crypto/modes/KCcmBlockCipher.cs
index 4cb11a784..4f7821452 100644
--- a/crypto/src/crypto/modes/KCcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCcmBlockCipher.cs
@@ -1,10 +1,10 @@
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Utilities;
-using System;
-using System.Collections.Generic;
+using System;
 using System.IO;
 using System.Text;
 
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Modes
 {
     public class KCcmBlockCipher: IAeadBlockCipher
@@ -229,10 +229,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual int ProcessBytes(byte[] input, int inOff, int inLen, byte[] output, int outOff)
         {
-            if (input.Length< (inOff + inLen))
-            {
-                throw new DataLengthException("input buffer too short");
-            }
+            Check.DataLength(input, inOff, inLen, "input buffer too short");
+
             data.Write(input, inOff, inLen);
 
             return 0;
@@ -240,42 +238,27 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public int ProcessPacket(byte[] input, int inOff, int len, byte[] output, int outOff)
         {
-            if (input.Length - inOff<len)
-            {
-                throw new ArgumentException("input buffer too short");
-            }
-
-            if (output.Length - outOff<len)
-            {
-                throw new ArgumentException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.OutputLength(output, outOff, len, "output buffer too short");
 
             if (associatedText.Length > 0)
             {
-
 #if PORTABLE
-                byte[] buf = associatedText.ToArray();
-                int bufLen = buf.Length;
+                byte[] aad = associatedText.ToArray();
+                int aadLen = aad.Length;
 #else
-                byte[] buf = associatedText.GetBuffer();
-                int bufLen = (int)buf.Length;
+                byte[] aad = associatedText.GetBuffer();
+                int aadLen = (int)associatedText.Length;
 #endif
-                if (forEncryption)
-                {
-                    ProcessAAD(buf, 0, bufLen, (int)data.Length);
-                }
-                else
-                {
-                    ProcessAAD(buf, 0, bufLen, (int)data.Length - macSize);
-                }
+
+                int dataLen = forEncryption ? (int)data.Length : ((int)data.Length - macSize);
+
+                ProcessAAD(aad, 0, aadLen, dataLen);
             }
 
             if (forEncryption)
             {
-                if ((len % engine.GetBlockSize()) != 0)
-                {
-                    throw new DataLengthException("partial blocks not supported");
-                }
+                Check.DataLength(len % engine.GetBlockSize() != 0, "partial blocks not supported");
 
                 CalculateMac(input, inOff, len);
                 engine.ProcessBlock(nonce, 0, s, 0);
@@ -309,10 +292,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
             else
             {
-                if ((len - macSize) % engine.GetBlockSize() != 0)
-                {
-                    throw new DataLengthException("partial blocks not supported");
-                }
+                Check.DataLength((len - macSize) % engine.GetBlockSize() != 0, "partial blocks not supported");
 
                 engine.ProcessBlock(nonce, 0, s, 0);
 
@@ -410,8 +390,9 @@ namespace Org.BouncyCastle.Crypto.Modes
             int bufLen = buf.Length;
 #else
             byte[] buf = data.GetBuffer();
-            int bufLen = (int)buf.Length;
+            int bufLen = (int)data.Length;
 #endif
+
             int len = ProcessPacket(buf, 0, bufLen, output, outOff);
 
             Reset();
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index ebe5b7af1..1b94fee0e 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -285,6 +285,31 @@ namespace Org.BouncyCastle.Crypto.Utilities
             UInt32_To_LE((uint)(n >> 32), bs, off + 4);
         }
 
+        internal static byte[] UInt64_To_LE(ulong[] ns)
+        {
+            byte[] bs = new byte[8 * ns.Length];
+            UInt64_To_LE(ns, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt64_To_LE(ulong[] ns, byte[] bs, int off)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                UInt64_To_LE(ns[i], bs, off);
+                off += 8;
+            }
+        }
+
+        internal static void UInt64_To_LE(ulong[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
+        {
+            for (int i = 0; i < nsLen; ++i)
+            {
+                UInt64_To_LE(ns[nsOff + i], bs, bsOff);
+                bsOff += 8;
+            }
+        }
+
         internal static ulong LE_To_UInt64(byte[] bs)
         {
             uint lo = LE_To_UInt32(bs);
@@ -307,5 +332,14 @@ namespace Org.BouncyCastle.Crypto.Utilities
                 off += 8;
             }
         }
+
+        internal static void LE_To_UInt64(byte[] bs, int bsOff, ulong[] ns, int nsOff, int nsLen)
+        {
+            for (int i = 0; i < nsLen; ++i)
+            {
+                ns[nsOff + i] = LE_To_UInt64(bs, bsOff);
+                bsOff += 8;
+            }
+        }
     }
 }
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index 904e29913..fc125e8c8 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -374,26 +374,37 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             return 0;
         }
 
-        private long GetExpirationTimeFromSig(
-            bool	selfSigned,
-            int		signatureType)
+        private long GetExpirationTimeFromSig(bool selfSigned, int signatureType)
         {
+            long expiryTime = -1;
+            long lastDate = -1;
+
             foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
             {
-                if (!selfSigned || sig.KeyId == KeyId)
-                {
-                    PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+                if (selfSigned && sig.KeyId != this.KeyId)
+                    continue;
+
+                PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+                if (hashed == null)
+                    continue;
 
-                    if (hashed != null)
+                long current = hashed.GetKeyExpirationTime();
+
+                if (sig.KeyId == this.KeyId)
+                {
+                    if (sig.CreationTime.Ticks > lastDate)
                     {
-                        return hashed.GetKeyExpirationTime();
+                        lastDate = sig.CreationTime.Ticks;
+                        expiryTime = current;
                     }
-
-                    return 0;
+                }
+                else if (current == 0 || current > expiryTime)
+                {
+                    expiryTime = current;
                 }
             }
 
-            return -1;
+            return expiryTime;
         }
 
         /// <summary>The keyId associated with the public key.</summary>