diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2020-07-30 16:53:15 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2020-07-30 16:53:15 +0700 |
commit | f03002768049d4e8ac5967d5a8aa99807a29c4fb (patch) | |
tree | c9a507525cc8414a52f143c297f977ac40c4d3af | |
parent | DH standard group updates (diff) | |
download | BouncyCastle.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.cs | 60 |
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); } } |