package org.spongycastle.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 final 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 params the key and other data required by the cipher. */ public void init( boolean forEncryption, CipherParameters params) { reset(); cipher.init(forEncryption, params); // // we allow for an extra byte where people are using their own padding // mechanisms on a raw cipher. // buf = new byte[cipher.getInputBlockSize() + (forEncryption ? 1 : 0)]; 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 too 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 too 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[i] = 0; } } bufOff = 0; } }