summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2020-07-30 16:53:15 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2020-07-30 16:53:15 +0700
commitf03002768049d4e8ac5967d5a8aa99807a29c4fb (patch)
treec9a507525cc8414a52f143c297f977ac40c4d3af
parentDH standard group updates (diff)
downloadBouncyCastle.NET-ed25519-f03002768049d4e8ac5967d5a8aa99807a29c4fb.tar.xz
Allocate memory for SCrypt in 32KiB chunks
- see https://github.com/bcgit/bc-java/issues/713
-rw-r--r--crypto/src/crypto/generators/SCrypt.cs60
1 files changed, 42 insertions, 18 deletions
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
index 9c204e786..0753820c9 100644
--- a/crypto/src/crypto/generators/SCrypt.cs
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
@@ -64,12 +65,23 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 				Pack.LE_To_UInt32(bytes, 0, B);
 
+                /*
+                 * Chunk memory allocations; We choose 'd' so that there will be 2**d chunks, each not
+                 * larger than 32KiB, except that the minimum chunk size is 2 * r * 32.
+                 */
+                int d = 0, total = N * r;
+                while ((N - d) > 2 && total > (1 << 10))
+                {
+                    ++d;
+                    total >>= 1;
+                }
+
 				int MFLenWords = MFLenBytes >> 2;
 				for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
 				{
 					// TODO These can be done in parallel threads
-					SMix(B, BOff, N, r);
-				}
+                    SMix(B, BOff, N, d, r);
+                }
 
 				Pack.UInt32_To_LE(B, bytes, 0);
 
@@ -89,8 +101,12 @@ namespace Org.BouncyCastle.Crypto.Generators
 			return key.GetKey();
 		}
 
-		private static void SMix(uint[] B, int BOff, int N, int r)
+		private static void SMix(uint[] B, int BOff, int N, int d, int r)
 		{
+            int powN = Integers.NumberOfTrailingZeros(N);
+            int blocksPerChunk = N >> d;
+            int chunkCount = 1 << d, chunkMask = blocksPerChunk - 1, chunkPow = powN - d;
+
 			int BCount = r * 32;
 
 			uint[] blockX1 = new uint[16];
@@ -98,28 +114,36 @@ namespace Org.BouncyCastle.Crypto.Generators
 			uint[] blockY = new uint[BCount];
 
 			uint[] X = new uint[BCount];
-            uint[] V = new uint[N * BCount];
+            uint[][] VV = new uint[chunkCount][];
 
 			try
 			{
 				Array.Copy(B, BOff, X, 0, BCount);
 
-                int off = 0;
-                for (int i = 0; i < N; i += 2)
+                for (int c = 0; c < chunkCount; ++c)
                 {
-                    Array.Copy(X, 0, V, off, BCount);
-                    off += BCount;
-                    BlockMix(X, blockX1, blockX2, blockY, r);
-                    Array.Copy(blockY, 0, V, off, BCount);
-                    off += BCount;
-                    BlockMix(blockY, blockX1, blockX2, X, r);
+                    uint[] V = new uint[blocksPerChunk * BCount];
+                    VV[c] = V;
+
+                    int off = 0;
+                    for (int i = 0; i < blocksPerChunk; i += 2)
+                    {
+                        Array.Copy(X, 0, V, off, BCount);
+                        off += BCount;
+                        BlockMix(X, blockX1, blockX2, blockY, r);
+                        Array.Copy(blockY, 0, V, off, BCount);
+                        off += BCount;
+                        BlockMix(blockY, blockX1, blockX2, X, r);
+                    }
                 }
 
-				uint mask = (uint)N - 1;
-				for (int i = 0; i < N; ++i)
-				{
-					int j = (int)(X[BCount - 16] & mask);
-                    Array.Copy(V, j * BCount, blockY, 0, BCount);
+                uint mask = (uint)N - 1;
+                for (int i = 0; i < N; ++i)
+                {
+                    int j = (int)(X[BCount - 16] & mask);
+                    uint[] V = VV[j >> chunkPow];
+                    int VOff = (j & chunkMask) * BCount;
+                    Array.Copy(V, VOff, blockY, 0, BCount);
                     Xor(blockY, X, 0, blockY);
                     BlockMix(blockY, blockX1, blockX2, X, r);
                 }
@@ -128,7 +152,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 			}
 			finally
 			{
-				Clear(V);
+				ClearAll(VV);
 				ClearAll(X, blockX1, blockX2, blockY);
 			}
 		}