package org.bouncycastle.crypto;
/**
* a buffer wrapper for an asymmetric block cipher, allowing input
* to be accumulated in a piecemeal fashion until final processing.
*/
public class BufferedAsymmetricBlockCipher
{
protected byte[] buf;
protected int bufOff;
private boolean forEncryption;
private AsymmetricBlockCipher cipher;
/**
* base constructor.
*
* @param cipher the cipher this buffering object wraps.
*/
public BufferedAsymmetricBlockCipher(
AsymmetricBlockCipher cipher)
{
this.cipher = cipher;
}
/**
* return the underlying cipher for the buffer.
*
* @return the underlying cipher for the buffer.
*/
public AsymmetricBlockCipher getUnderlyingCipher()
{
return cipher;
}
/**
* return the amount of data sitting in the buffer.
*
* @return the amount of data sitting in the buffer.
*/
public int getBufferPosition()
{
return bufOff;
}
/**
* initialise the buffer and the underlying cipher.
*
* @param forEncryption if true the cipher is initialised for
* encryption, if false for decryption.
* @param param the key and other data required by the cipher.
*/
public void init(
boolean forEncryption,
CipherParameters params)
{
this.forEncryption = forEncryption;
reset();
cipher.init(forEncryption, params);
buf = new byte[cipher.getInputBlockSize()];
bufOff = 0;
}
/**
* returns the largest size an input block can be.
*
* @return maximum size for an input block.
*/
public int getInputBlockSize()
{
return cipher.getInputBlockSize();
}
/**
* returns the maximum size of the block produced by this cipher.
*
* @return maximum size of the output block produced by the cipher.
*/
public int getOutputBlockSize()
{
return cipher.getOutputBlockSize();
}
/**
* add another byte for processing.
*
* @param in the input byte.
*/
public void processByte(
byte in)
{
if (bufOff > buf.length)
{
throw new DataLengthException("attempt to process message to long for cipher");
}
buf[bufOff++] = in;
}
/**
* add len bytes to the buffer for processing.
*
* @param in the input data
* @param inOff offset into the in array where the data starts
* @param len the length of the block to be processed.
*/
public void processBytes(
byte[] in,
int inOff,
int len)
{
if (len == 0)
{
return;
}
if (len < 0)
{
throw new IllegalArgumentException("Can't have a negative input length!");
}
if (bufOff + len > buf.length)
{
throw new DataLengthException("attempt to process message to long for cipher");
}
System.arraycopy(in, inOff, buf, bufOff, len);
bufOff += len;
}
/**
* process the contents of the buffer using the underlying
* cipher.
*
* @return the result of the encryption/decryption process on the
* buffer.
* @exception InvalidCipherTextException if we are given a garbage block.
*/
public byte[] doFinal()
throws InvalidCipherTextException
{
byte[] out = cipher.processBlock(buf, 0, bufOff);
reset();
return out;
}
/**
* Reset the buffer and the underlying cipher.
*/
public void reset()
{
/*
* clean the buffer.
*/
if (buf != null)
{
for (int i = 0; i < buf.length; i++)
{
buf[0] = 0;
}
}
bufOff = 0;
}
}