Skip to content

Commit 5b1f02e

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

File tree

2 files changed

+94
-16
lines changed

2 files changed

+94
-16
lines changed

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

+38-12
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;
@@ -98,6 +102,7 @@ public int generateBytes(byte[] password, byte[] out, int outOff, int outLen)
98102

99103
byte[] tmpBlockBytes = new byte[ARGON2_BLOCK_SIZE];
100104

105+
initMemory(memoryBlocks);
101106
initialize(tmpBlockBytes, password, outLen);
102107
fillMemoryBlocks();
103108
digest(tmpBlockBytes, out, outOff, outLen);
@@ -118,17 +123,18 @@ private void reset()
118123
Block b = memory[i];
119124
if (null != b)
120125
{
121-
b.clear();
126+
pool.deallocate(b);
122127
}
123128
}
124129
}
130+
memory = null;
125131
}
126132

127133
private void doInit(Argon2Parameters parameters)
128134
{
129135
/* 2. Align memory size */
130136
/* Minimum memoryBlocks = 8L blocks, where L is the number of lanes */
131-
int memoryBlocks = parameters.getMemory();
137+
memoryBlocks = parameters.getMemory();
132138

133139
if (memoryBlocks < 2 * Argon2BytesGenerator.ARGON2_SYNC_POINTS * parameters.getLanes())
134140
{
@@ -141,7 +147,11 @@ private void doInit(Argon2Parameters parameters)
141147
/* Ensure that all segments have equal length */
142148
memoryBlocks = segmentLength * (parameters.getLanes() * Argon2BytesGenerator.ARGON2_SYNC_POINTS);
143149

144-
initMemory(memoryBlocks);
150+
pool = parameters.getBlockPool();
151+
if (pool == null) {
152+
// if no pool is provided hold on to enough blocks for the primary memory
153+
pool = new FixedBlockPool(memoryBlocks);
154+
}
145155
}
146156

147157
private void initMemory(int memoryBlocks)
@@ -150,13 +160,13 @@ private void initMemory(int memoryBlocks)
150160

151161
for (int i = 0; i < memory.length; i++)
152162
{
153-
memory[i] = new Block();
163+
memory[i] = pool.allocate();
154164
}
155165
}
156166

157167
private void fillMemoryBlocks()
158168
{
159-
FillBlock filler = new FillBlock();
169+
FillBlock filler = new FillBlock(pool);
160170
Position position = new Position();
161171
for (int pass = 0; pass < parameters.getIterations(); ++pass)
162172
{
@@ -174,6 +184,7 @@ private void fillMemoryBlocks()
174184
}
175185
}
176186
}
187+
filler.deallocate(pool);
177188
}
178189

179190
private void fillSegment(FillBlock filler, Position position)
@@ -548,16 +559,31 @@ private void fillFirstBlocks(byte[] tmpBlockBytes, byte[] initialHashWithZeros)
548559

549560
private long intToLong(int x)
550561
{
551-
return (long)(x & M32L);
562+
return x & M32L;
552563
}
553564

554565
private static class FillBlock
555566
{
556-
Block R = new Block();
557-
Block Z = new Block();
567+
final Block R;
568+
final Block Z;
569+
570+
final Block addressBlock;
571+
final Block inputBlock;
558572

559-
Block addressBlock = new Block();
560-
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+
}
561587

562588
private void applyBlake()
563589
{
@@ -618,14 +644,14 @@ private void fillBlockWithXor(Block X, Block Y, Block currentBlock)
618644
}
619645
}
620646

621-
private static class Block
647+
public static class Block
622648
{
623649
private static final int SIZE = ARGON2_QWORDS_IN_BLOCK;
624650

625651
/* 128 * 8 Byte QWords */
626652
private final long[] v;
627653

628-
private Block()
654+
public Block()
629655
{
630656
v = new long[SIZE];
631657
}

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)