Skip to content

Commit d6d406a

Browse files
committed
fix: allows developers to provide a block pool to argon2
closes: #1646 Signed-off-by: Steve Hawkins <[email protected]>
1 parent 1167a4e commit d6d406a

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

core/src/main/java/org/bouncycastle/crypto/generators/Argon2BytesGenerator.java

+46-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.bouncycastle.crypto.Digest;
44
import org.bouncycastle.crypto.digests.Blake2bDigest;
55
import org.bouncycastle.crypto.params.Argon2Parameters;
6+
import org.bouncycastle.crypto.params.Argon2Parameters.BlockPool;
7+
import org.bouncycastle.crypto.params.Argon2Parameters.FixedBlockPool;
68
import org.bouncycastle.util.Arrays;
79
import org.bouncycastle.util.Longs;
810
import org.bouncycastle.util.Pack;
@@ -37,6 +39,8 @@ public class Argon2BytesGenerator
3739
private static final byte[] ZERO_BYTES = new byte[4];
3840

3941
private Argon2Parameters parameters;
42+
private BlockPool pool;
43+
private int memoryBlocks;
4044
private Block[] memory;
4145
private int segmentLength;
4246
private int laneLength;
@@ -90,10 +94,11 @@ else if (parameters.getIterations() < MIN_ITERATIONS)
9094
memoryBlocks = parameters.getLanes() * laneLength;
9195

9296
this.memory = new Block[memoryBlocks];
93-
94-
for (int i = 0; i < memory.length; i++)
95-
{
96-
memory[i] = new Block();
97+
98+
pool = parameters.getBlockPool();
99+
if (pool == null) {
100+
// if no pool is provided hold on to enough blocks for the primary memory
101+
pool = new FixedBlockPool(memoryBlocks);
97102
}
98103
}
99104

@@ -121,6 +126,7 @@ public int generateBytes(byte[] password, byte[] out, int outOff, int outLen)
121126

122127
byte[] tmpBlockBytes = new byte[ARGON2_BLOCK_SIZE];
123128

129+
initMemory(memoryBlocks);
124130
initialize(tmpBlockBytes, password, outLen);
125131
fillMemoryBlocks();
126132
digest(tmpBlockBytes, out, outOff, outLen);
@@ -141,15 +147,26 @@ private void reset()
141147
Block b = memory[i];
142148
if (null != b)
143149
{
144-
b.clear();
150+
pool.deallocate(b);
145151
}
146152
}
147153
}
154+
memory = null;
155+
}
156+
157+
private void initMemory(int memoryBlocks)
158+
{
159+
this.memory = new Block[memoryBlocks];
160+
161+
for (int i = 0; i < memory.length; i++)
162+
{
163+
memory[i] = pool.allocate();
164+
}
148165
}
149166

150167
private void fillMemoryBlocks()
151168
{
152-
FillBlock filler = new FillBlock();
169+
FillBlock filler = new FillBlock(pool);
153170
Position position = new Position();
154171
for (int pass = 0; pass < parameters.getIterations(); ++pass)
155172
{
@@ -167,6 +184,7 @@ private void fillMemoryBlocks()
167184
}
168185
}
169186
}
187+
filler.deallocate(pool);
170188
}
171189

172190
private void fillSegment(FillBlock filler, Position position)
@@ -541,16 +559,31 @@ private void fillFirstBlocks(byte[] tmpBlockBytes, byte[] initialHashWithZeros)
541559

542560
private long intToLong(int x)
543561
{
544-
return (long)(x & M32L);
562+
return x & M32L;
545563
}
546564

547565
private static class FillBlock
548566
{
549-
Block R = new Block();
550-
Block Z = new Block();
567+
final Block R;
568+
final Block Z;
569+
570+
final Block addressBlock;
571+
final Block inputBlock;
551572

552-
Block addressBlock = new Block();
553-
Block inputBlock = new Block();
573+
private FillBlock(BlockPool pool) {
574+
R = pool.allocate();
575+
Z = pool.allocate();
576+
577+
addressBlock = pool.allocate();
578+
inputBlock = pool.allocate();
579+
}
580+
581+
public void deallocate(BlockPool pool) {
582+
pool.deallocate(addressBlock);
583+
pool.deallocate(inputBlock);
584+
pool.deallocate(R);
585+
pool.deallocate(Z);
586+
}
554587

555588
private void applyBlake()
556589
{
@@ -611,14 +644,14 @@ private void fillBlockWithXor(Block X, Block Y, Block currentBlock)
611644
}
612645
}
613646

614-
private static class Block
647+
public static class Block
615648
{
616649
private static final int SIZE = ARGON2_QWORDS_IN_BLOCK;
617650

618651
/* 128 * 8 Byte QWords */
619652
private final long[] v;
620653

621-
private Block()
654+
public Block()
622655
{
623656
v = new long[SIZE];
624657
}

core/src/main/java/org/bouncycastle/crypto/params/Argon2Parameters.java

+56-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,46 @@
22

33
import org.bouncycastle.crypto.CharToByteConverter;
44
import org.bouncycastle.crypto.PasswordConverter;
5+
import org.bouncycastle.crypto.generators.Argon2BytesGenerator.Block;
56
import org.bouncycastle.util.Arrays;
67

8+
import java.util.concurrent.LinkedBlockingQueue;
9+
710
public class Argon2Parameters
811
{
12+
public static interface BlockPool {
13+
Block allocate();
14+
void deallocate(Block block);
15+
}
16+
17+
public static class FixedBlockPool implements BlockPool {
18+
19+
private LinkedBlockingQueue<Block> blocks;
20+
21+
public FixedBlockPool(int maxBlocks) {
22+
this.blocks = new LinkedBlockingQueue<>(maxBlocks);
23+
}
24+
25+
@Override
26+
public Block allocate() {
27+
Block block = blocks.poll();
28+
if (block == null) {
29+
return new Block();
30+
}
31+
// since we're not tracking which thread deallocated
32+
// we don't know if the clearing is visible in this one
33+
block.clear();
34+
return block;
35+
}
36+
37+
@Override
38+
public void deallocate(Block block) {
39+
block.clear();
40+
blocks.offer(block);
41+
}
42+
43+
}
44+
945
public static final int ARGON2_d = 0x00;
1046
public static final int ARGON2_i = 0x01;
1147
public static final int ARGON2_id = 0x02;
@@ -31,9 +67,11 @@ public static class Builder
3167

3268
private int version;
3369
private final int type;
34-
70+
3571
private CharToByteConverter converter = PasswordConverter.UTF8;
3672

73+
private BlockPool blockPool;
74+
3775
public Builder()
3876
{
3977
this(DEFAULT_TYPE);
@@ -97,16 +135,22 @@ public Builder withVersion(int version)
97135
this.version = version;
98136
return this;
99137
}
100-
138+
101139
public Builder withCharToByteConverter(CharToByteConverter converter)
102140
{
103141
this.converter = converter;
104142
return this;
105143
}
106144

145+
public Builder withBlockPool(BlockPool blockPool)
146+
{
147+
this.blockPool = blockPool;
148+
return this;
149+
}
150+
107151
public Argon2Parameters build()
108152
{
109-
return new Argon2Parameters(type, salt, secret, additional, iterations, memory, lanes, version, converter);
153+
return new Argon2Parameters(type, salt, secret, additional, iterations, memory, lanes, version, converter, blockPool);
110154
}
111155

112156
public void clear()
@@ -129,6 +173,8 @@ public void clear()
129173
private final int type;
130174
private final CharToByteConverter converter;
131175

176+
private final BlockPool blockPool;
177+
132178
private Argon2Parameters(
133179
int type,
134180
byte[] salt,
@@ -138,7 +184,8 @@ private Argon2Parameters(
138184
int memory,
139185
int lanes,
140186
int version,
141-
CharToByteConverter converter)
187+
CharToByteConverter converter,
188+
BlockPool blockPool)
142189
{
143190

144191
this.salt = Arrays.clone(salt);
@@ -150,6 +197,7 @@ private Argon2Parameters(
150197
this.version = version;
151198
this.type = type;
152199
this.converter = converter;
200+
this.blockPool = blockPool;
153201
}
154202

155203
public byte[] getSalt()
@@ -197,6 +245,10 @@ public CharToByteConverter getCharToByteConverter()
197245
return converter;
198246
}
199247

248+
public BlockPool getBlockPool() {
249+
return blockPool;
250+
}
251+
200252
public void clear()
201253
{
202254
Arrays.clear(salt);

0 commit comments

Comments
 (0)