001: package org.bouncycastle.crypto;
002:
003: /**
004: * a buffer wrapper for an asymmetric block cipher, allowing input
005: * to be accumulated in a piecemeal fashion until final processing.
006: */
007: public class BufferedAsymmetricBlockCipher {
008: protected byte[] buf;
009: protected int bufOff;
010:
011: private final AsymmetricBlockCipher cipher;
012:
013: /**
014: * base constructor.
015: *
016: * @param cipher the cipher this buffering object wraps.
017: */
018: public BufferedAsymmetricBlockCipher(AsymmetricBlockCipher cipher) {
019: this .cipher = cipher;
020: }
021:
022: /**
023: * return the underlying cipher for the buffer.
024: *
025: * @return the underlying cipher for the buffer.
026: */
027: public AsymmetricBlockCipher getUnderlyingCipher() {
028: return cipher;
029: }
030:
031: /**
032: * return the amount of data sitting in the buffer.
033: *
034: * @return the amount of data sitting in the buffer.
035: */
036: public int getBufferPosition() {
037: return bufOff;
038: }
039:
040: /**
041: * initialise the buffer and the underlying cipher.
042: *
043: * @param forEncryption if true the cipher is initialised for
044: * encryption, if false for decryption.
045: * @param params the key and other data required by the cipher.
046: */
047: public void init(boolean forEncryption, CipherParameters params) {
048: reset();
049:
050: cipher.init(forEncryption, params);
051:
052: //
053: // we allow for an extra byte where people are using their own padding
054: // mechanisms on a raw cipher.
055: //
056: buf = new byte[cipher.getInputBlockSize()
057: + (forEncryption ? 1 : 0)];
058: bufOff = 0;
059: }
060:
061: /**
062: * returns the largest size an input block can be.
063: *
064: * @return maximum size for an input block.
065: */
066: public int getInputBlockSize() {
067: return cipher.getInputBlockSize();
068: }
069:
070: /**
071: * returns the maximum size of the block produced by this cipher.
072: *
073: * @return maximum size of the output block produced by the cipher.
074: */
075: public int getOutputBlockSize() {
076: return cipher.getOutputBlockSize();
077: }
078:
079: /**
080: * add another byte for processing.
081: *
082: * @param in the input byte.
083: */
084: public void processByte(byte in) {
085: if (bufOff >= buf.length) {
086: throw new DataLengthException(
087: "attempt to process message too long for cipher");
088: }
089:
090: buf[bufOff++] = in;
091: }
092:
093: /**
094: * add len bytes to the buffer for processing.
095: *
096: * @param in the input data
097: * @param inOff offset into the in array where the data starts
098: * @param len the length of the block to be processed.
099: */
100: public void processBytes(byte[] in, int inOff, int len) {
101: if (len == 0) {
102: return;
103: }
104:
105: if (len < 0) {
106: throw new IllegalArgumentException(
107: "Can't have a negative input length!");
108: }
109:
110: if (bufOff + len > buf.length) {
111: throw new DataLengthException(
112: "attempt to process message too long for cipher");
113: }
114:
115: System.arraycopy(in, inOff, buf, bufOff, len);
116: bufOff += len;
117: }
118:
119: /**
120: * process the contents of the buffer using the underlying
121: * cipher.
122: *
123: * @return the result of the encryption/decryption process on the
124: * buffer.
125: * @exception InvalidCipherTextException if we are given a garbage block.
126: */
127: public byte[] doFinal() throws InvalidCipherTextException {
128: byte[] out = cipher.processBlock(buf, 0, bufOff);
129:
130: reset();
131:
132: return out;
133: }
134:
135: /**
136: * Reset the buffer and the underlying cipher.
137: */
138: public void reset() {
139: /*
140: * clean the buffer.
141: */
142: if (buf != null) {
143: for (int i = 0; i < buf.length; i++) {
144: buf[0] = 0;
145: }
146: }
147:
148: bufOff = 0;
149: }
150: }
|