package org.bouncycastle.crypto.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import org.bouncycastle.util.Arrays;
A SecureRandom that maintains a journal of its output.
/**
* A SecureRandom that maintains a journal of its output.
*/
public class JournalingSecureRandom
extends SecureRandom
{
private static byte[] EMPTY_TRANSCRIPT = new byte[0];
private final SecureRandom base;
private final byte[] transcript;
private TranscriptStream tOut = new TranscriptStream();
private int index = 0;
Base constructor - no prior transcript.
Params: - random – source of randomness we will be journaling.
/**
* Base constructor - no prior transcript.
*
* @param random source of randomness we will be journaling.
*/
public JournalingSecureRandom(SecureRandom random)
{
this.base = random;
this.transcript = EMPTY_TRANSCRIPT;
}
Constructor with a prior transcript. Both the transcript used and
any new randomness are journaled.
Params: - transcript – initial transcript of randomness.
- random – source of randomness we will be journaling when the transcript runs out.
/**
* Constructor with a prior transcript. Both the transcript used and
* any new randomness are journaled.
*
* @param transcript initial transcript of randomness.
* @param random source of randomness we will be journaling when the transcript runs out.
*/
public JournalingSecureRandom(byte[] transcript, SecureRandom random)
{
this.base = random;
this.transcript = Arrays.clone(transcript);
}
Fill bytes with random data, journaling the random data before returning.
Params: - bytes – a block of bytes to be filled with random data.
/**
* Fill bytes with random data, journaling the random data before returning.
*
* @param bytes a block of bytes to be filled with random data.
*/
public final void nextBytes(byte[] bytes)
{
if (index >= transcript.length)
{
base.nextBytes(bytes);
}
else
{
int i = 0;
while (i != bytes.length)
{
if (index < transcript.length)
{
bytes[i] = transcript[index++];
}
else
{
break;
}
i++;
}
if (i != bytes.length)
{
byte[] extra = new byte[bytes.length - i];
base.nextBytes(extra);
System.arraycopy(extra, 0, bytes, i, extra.length);
}
}
try
{
tOut.write(bytes);
}
catch (IOException e)
{
throw new IllegalStateException("unable to record transcript: " + e.getMessage());
}
}
Clear the internals
/**
* Clear the internals
*/
public void clear()
{
Arrays.fill(transcript, (byte)0);
tOut.clear();
}
Return the transcript so far,
Returns: a copy of the randomness produced so far.
/**
* Return the transcript so far,
*
* @return a copy of the randomness produced so far.
*/
public byte[] getTranscript()
{
return tOut.toByteArray();
}
private class TranscriptStream
extends ByteArrayOutputStream
{
public void clear()
{
Arrays.fill(buf, (byte)0);
}
}
}