Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allows developers to provide a block pool to argon2 #1647

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.crypto.params.Argon2Parameters;
import org.bouncycastle.crypto.params.Argon2Parameters.BlockPool;
import org.bouncycastle.crypto.params.Argon2Parameters.FixedBlockPool;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Longs;
import org.bouncycastle.util.Pack;
Expand Down Expand Up @@ -37,6 +39,8 @@ public class Argon2BytesGenerator
private static final byte[] ZERO_BYTES = new byte[4];

private Argon2Parameters parameters;
private BlockPool pool;
private int memoryBlocks;
private Block[] memory;
private int segmentLength;
private int laneLength;
Expand Down Expand Up @@ -98,6 +102,7 @@ public int generateBytes(byte[] password, byte[] out, int outOff, int outLen)

byte[] tmpBlockBytes = new byte[ARGON2_BLOCK_SIZE];

initMemory(memoryBlocks);
initialize(tmpBlockBytes, password, outLen);
fillMemoryBlocks();
digest(tmpBlockBytes, out, outOff, outLen);
Expand All @@ -118,17 +123,18 @@ private void reset()
Block b = memory[i];
if (null != b)
{
b.clear();
pool.deallocate(b);
}
}
}
memory = null;
}

private void doInit(Argon2Parameters parameters)
{
/* 2. Align memory size */
/* Minimum memoryBlocks = 8L blocks, where L is the number of lanes */
int memoryBlocks = parameters.getMemory();
memoryBlocks = parameters.getMemory();

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

initMemory(memoryBlocks);
pool = parameters.getBlockPool();
if (pool == null) {
// if no pool is provided hold on to enough blocks for the primary memory
pool = new FixedBlockPool(memoryBlocks);
}
}

private void initMemory(int memoryBlocks)
Expand All @@ -150,13 +160,13 @@ private void initMemory(int memoryBlocks)

for (int i = 0; i < memory.length; i++)
{
memory[i] = new Block();
memory[i] = pool.allocate();
}
}

private void fillMemoryBlocks()
{
FillBlock filler = new FillBlock();
FillBlock filler = new FillBlock(pool);
Position position = new Position();
for (int pass = 0; pass < parameters.getIterations(); ++pass)
{
Expand All @@ -174,6 +184,7 @@ private void fillMemoryBlocks()
}
}
}
filler.deallocate(pool);
}

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

private long intToLong(int x)
{
return (long)(x & M32L);
return x & M32L;
}

private static class FillBlock
{
Block R = new Block();
Block Z = new Block();
final Block R;
final Block Z;

final Block addressBlock;
final Block inputBlock;

Block addressBlock = new Block();
Block inputBlock = new Block();
private FillBlock(BlockPool pool) {
R = pool.allocate();
Z = pool.allocate();

addressBlock = pool.allocate();
inputBlock = pool.allocate();
}

public void deallocate(BlockPool pool) {
pool.deallocate(addressBlock);
pool.deallocate(inputBlock);
pool.deallocate(R);
pool.deallocate(Z);
}

private void applyBlake()
{
Expand Down Expand Up @@ -618,14 +644,14 @@ private void fillBlockWithXor(Block X, Block Y, Block currentBlock)
}
}

private static class Block
public static class Block
{
private static final int SIZE = ARGON2_QWORDS_IN_BLOCK;

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

private Block()
public Block()
{
v = new long[SIZE];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,46 @@

import org.bouncycastle.crypto.CharToByteConverter;
import org.bouncycastle.crypto.PasswordConverter;
import org.bouncycastle.crypto.generators.Argon2BytesGenerator.Block;
import org.bouncycastle.util.Arrays;

import java.util.concurrent.LinkedBlockingQueue;

public class Argon2Parameters
{
public static interface BlockPool {
Block allocate();
void deallocate(Block block);
}

public static class FixedBlockPool implements BlockPool {

private LinkedBlockingQueue<Block> blocks;

public FixedBlockPool(int maxBlocks) {
this.blocks = new LinkedBlockingQueue<>(maxBlocks);
}

@Override
public Block allocate() {
Block block = blocks.poll();
if (block == null) {
return new Block();
}
// since we're not tracking which thread deallocated
// we don't know if the clearing is visible in this one
block.clear();
return block;
}

@Override
public void deallocate(Block block) {
block.clear();
blocks.offer(block);
}

}

public static final int ARGON2_d = 0x00;
public static final int ARGON2_i = 0x01;
public static final int ARGON2_id = 0x02;
Expand All @@ -31,9 +67,11 @@ public static class Builder

private int version;
private final int type;

private CharToByteConverter converter = PasswordConverter.UTF8;

private BlockPool blockPool;

public Builder()
{
this(DEFAULT_TYPE);
Expand Down Expand Up @@ -97,16 +135,22 @@ public Builder withVersion(int version)
this.version = version;
return this;
}

public Builder withCharToByteConverter(CharToByteConverter converter)
{
this.converter = converter;
return this;
}

public Builder withBlockPool(BlockPool blockPool)
{
this.blockPool = blockPool;
return this;
}

public Argon2Parameters build()
{
return new Argon2Parameters(type, salt, secret, additional, iterations, memory, lanes, version, converter);
return new Argon2Parameters(type, salt, secret, additional, iterations, memory, lanes, version, converter, blockPool);
}

public void clear()
Expand All @@ -129,6 +173,8 @@ public void clear()
private final int type;
private final CharToByteConverter converter;

private final BlockPool blockPool;

private Argon2Parameters(
int type,
byte[] salt,
Expand All @@ -138,7 +184,8 @@ private Argon2Parameters(
int memory,
int lanes,
int version,
CharToByteConverter converter)
CharToByteConverter converter,
BlockPool blockPool)
{

this.salt = Arrays.clone(salt);
Expand All @@ -150,6 +197,7 @@ private Argon2Parameters(
this.version = version;
this.type = type;
this.converter = converter;
this.blockPool = blockPool;
}

public byte[] getSalt()
Expand Down Expand Up @@ -197,6 +245,10 @@ public CharToByteConverter getCharToByteConverter()
return converter;
}

public BlockPool getBlockPool() {
return blockPool;
}

public void clear()
{
Arrays.clear(salt);
Expand Down