Skip to content

Commit f030027

Browse files
committed
Allocate memory for SCrypt in 32KiB chunks
- see bcgit/bc-java#713
1 parent 0010553 commit f030027

File tree

1 file changed

+42
-18
lines changed

1 file changed

+42
-18
lines changed

crypto/src/crypto/generators/SCrypt.cs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Org.BouncyCastle.Crypto.Engines;
66
using Org.BouncyCastle.Crypto.Parameters;
77
using Org.BouncyCastle.Crypto.Utilities;
8+
using Org.BouncyCastle.Utilities;
89

910
namespace Org.BouncyCastle.Crypto.Generators
1011
{
@@ -64,12 +65,23 @@ private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen
6465

6566
Pack.LE_To_UInt32(bytes, 0, B);
6667

68+
/*
69+
* Chunk memory allocations; We choose 'd' so that there will be 2**d chunks, each not
70+
* larger than 32KiB, except that the minimum chunk size is 2 * r * 32.
71+
*/
72+
int d = 0, total = N * r;
73+
while ((N - d) > 2 && total > (1 << 10))
74+
{
75+
++d;
76+
total >>= 1;
77+
}
78+
6779
int MFLenWords = MFLenBytes >> 2;
6880
for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
6981
{
7082
// TODO These can be done in parallel threads
71-
SMix(B, BOff, N, r);
72-
}
83+
SMix(B, BOff, N, d, r);
84+
}
7385

7486
Pack.UInt32_To_LE(B, bytes, 0);
7587

@@ -89,37 +101,49 @@ private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen)
89101
return key.GetKey();
90102
}
91103

92-
private static void SMix(uint[] B, int BOff, int N, int r)
104+
private static void SMix(uint[] B, int BOff, int N, int d, int r)
93105
{
106+
int powN = Integers.NumberOfTrailingZeros(N);
107+
int blocksPerChunk = N >> d;
108+
int chunkCount = 1 << d, chunkMask = blocksPerChunk - 1, chunkPow = powN - d;
109+
94110
int BCount = r * 32;
95111

96112
uint[] blockX1 = new uint[16];
97113
uint[] blockX2 = new uint[16];
98114
uint[] blockY = new uint[BCount];
99115

100116
uint[] X = new uint[BCount];
101-
uint[] V = new uint[N * BCount];
117+
uint[][] VV = new uint[chunkCount][];
102118

103119
try
104120
{
105121
Array.Copy(B, BOff, X, 0, BCount);
106122

107-
int off = 0;
108-
for (int i = 0; i < N; i += 2)
123+
for (int c = 0; c < chunkCount; ++c)
109124
{
110-
Array.Copy(X, 0, V, off, BCount);
111-
off += BCount;
112-
BlockMix(X, blockX1, blockX2, blockY, r);
113-
Array.Copy(blockY, 0, V, off, BCount);
114-
off += BCount;
115-
BlockMix(blockY, blockX1, blockX2, X, r);
125+
uint[] V = new uint[blocksPerChunk * BCount];
126+
VV[c] = V;
127+
128+
int off = 0;
129+
for (int i = 0; i < blocksPerChunk; i += 2)
130+
{
131+
Array.Copy(X, 0, V, off, BCount);
132+
off += BCount;
133+
BlockMix(X, blockX1, blockX2, blockY, r);
134+
Array.Copy(blockY, 0, V, off, BCount);
135+
off += BCount;
136+
BlockMix(blockY, blockX1, blockX2, X, r);
137+
}
116138
}
117139

118-
uint mask = (uint)N - 1;
119-
for (int i = 0; i < N; ++i)
120-
{
121-
int j = (int)(X[BCount - 16] & mask);
122-
Array.Copy(V, j * BCount, blockY, 0, BCount);
140+
uint mask = (uint)N - 1;
141+
for (int i = 0; i < N; ++i)
142+
{
143+
int j = (int)(X[BCount - 16] & mask);
144+
uint[] V = VV[j >> chunkPow];
145+
int VOff = (j & chunkMask) * BCount;
146+
Array.Copy(V, VOff, blockY, 0, BCount);
123147
Xor(blockY, X, 0, blockY);
124148
BlockMix(blockY, blockX1, blockX2, X, r);
125149
}
@@ -128,7 +152,7 @@ private static void SMix(uint[] B, int BOff, int N, int r)
128152
}
129153
finally
130154
{
131-
Clear(V);
155+
ClearAll(VV);
132156
ClearAll(X, blockX1, blockX2, blockY);
133157
}
134158
}

0 commit comments

Comments
 (0)