diff --git a/core/java/test/junit/net/i2p/crypto/AESInputStream.java b/core/java/test/junit/net/i2p/crypto/AESInputStream.java deleted file mode 100644 index 17e19a1c0f..0000000000 --- a/core/java/test/junit/net/i2p/crypto/AESInputStream.java +++ /dev/null @@ -1,470 +0,0 @@ -package net.i2p.crypto; - -/* - * free (adj.): unencumbered; not under the control of others - * Written by jrandom in 2003 and released into the public domain - * with no warranty of any kind, either expressed or implied. - * It probably won't make your computer catch on fire, or eat - * your children, but it might. Use at your own risk. - * - */ - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -import net.i2p.I2PAppContext; -import net.i2p.data.Base64; -import net.i2p.data.DataHelper; -import net.i2p.data.Hash; -import net.i2p.data.SessionKey; -import net.i2p.util.Clock; -import net.i2p.util.Log; -import net.i2p.util.RandomSource; - -/** - * This reads an underlying stream as written by AESOutputStream - AES256 encrypted - * in CBC mode with PKCS#5 padding, with the padding on each and every block of - * 16 bytes. This minimizes the overhead when communication is intermittent, - * rather than when streams of large sets of data are sent (in which case, the - * padding would be on a larger size - say, 1k, though in the worst case that - * would have 1023 bytes of padding, while in the worst case here, we only have - * 15 bytes of padding). So we have an expansion factor of 6.25%. c'est la vie - * - */ -public class AESInputStream extends FilterInputStream { - private Log _log; - private I2PAppContext _context; - private SessionKey _key; - private byte[] _lastBlock; - private boolean _eofFound; - private long _cumulativeRead; // how many read from the source stream - private long _cumulativePrepared; // how many bytes decrypted and added to _readyBuf - private long _cumulativePaddingStripped; // how many bytes have been stripped - - /** read but not yet decrypted */ - private byte _encryptedBuf[]; - /** how many bytes have been added to the encryptedBuf since it was decrypted? */ - private int _writesSinceDecrypt; - /** decrypted bytes ready for reading (first available == index of 0) */ - private int _decryptedBuf[]; - /** how many bytes are available for reading without decrypt? */ - private int _decryptedSize; - - private final static int BLOCK_SIZE = 16; - - public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte[] iv) { - super(source); - _context = context; - _log = context.logManager().getLog(AESInputStream.class); - _key = key; - _lastBlock = new byte[BLOCK_SIZE]; - System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE); - _encryptedBuf = new byte[BLOCK_SIZE]; - _writesSinceDecrypt = 0; - _decryptedBuf = new int[BLOCK_SIZE-1]; - _decryptedSize = 0; - _cumulativePaddingStripped = 0; - _eofFound = false; - } - - @Override - public int read() throws IOException { - while ((!_eofFound) && (_decryptedSize <= 0)) { - refill(); - } - if (_decryptedSize > 0) { - int c = _decryptedBuf[0]; - System.arraycopy(_decryptedBuf, 1, _decryptedBuf, 0, _decryptedBuf.length-1); - _decryptedSize--; - return c; - } else if (_eofFound) { - return -1; - } else { - throw new IOException("Not EOF, but none available? " + _decryptedSize - + "/" + _writesSinceDecrypt - + "/" + _cumulativeRead + "... impossible"); - } - } - - @Override - public int read(byte dest[]) throws IOException { - return read(dest, 0, dest.length); - } - - @Override - public int read(byte dest[], int off, int len) throws IOException { - for (int i = 0; i < len; i++) { - int val = read(); - if (val == -1) { - // no more to read... can they expect more? - if (_eofFound && (i == 0)) { - if (_log.shouldLog(Log.DEBUG)) - _log.info("EOF? " + _eofFound - + "\nread=" + i + " decryptedSize=" + _decryptedSize - + " \nencryptedSize=" + _writesSinceDecrypt - + " \ntotal=" + _cumulativeRead - + " \npadding=" + _cumulativePaddingStripped - + " \nprepared=" + _cumulativePrepared); - return -1; - } else { - if (i != len) - if (_log.shouldLog(Log.DEBUG)) - _log.info("non-terminal eof: " + _eofFound + " i=" + i + " len=" + len); - } - - return i; - } - dest[off+i] = (byte)val; - } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Read the full buffer of size " + len); - return len; - } - - @Override - public long skip(long numBytes) throws IOException { - for (long l = 0; l < numBytes; l++) { - int val = read(); - if (val == -1) return l; - } - return numBytes; - } - - @Override - public int available() throws IOException { - return _decryptedSize; - } - - @Override - public void close() throws IOException { - in.close(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Cumulative bytes read from source/decrypted/stripped: " + _cumulativeRead + "/" - + _cumulativePrepared + "/" + _cumulativePaddingStripped + "] remaining [" + _decryptedSize + " ready, " - + _writesSinceDecrypt + " still encrypted]"); - } - - @Override - public void mark(int readLimit) { // nop - } - - @Override - public void reset() throws IOException { - throw new IOException("Reset not supported"); - } - - @Override - public boolean markSupported() { - return false; - } - - /** - * Read at least one new byte from the underlying stream, and up to max new bytes, - * but not necessarily enough for a new decrypted block. This blocks until at least - * one new byte is read from the stream - * - */ - private void refill() throws IOException { - if ( (!_eofFound) && (_writesSinceDecrypt < BLOCK_SIZE) ) { - int read = in.read(_encryptedBuf, _writesSinceDecrypt, _encryptedBuf.length - _writesSinceDecrypt); - if (read == -1) { - _eofFound = true; - } else if (read > 0) { - _cumulativeRead += read; - _writesSinceDecrypt += read; - } - } - if (_writesSinceDecrypt == BLOCK_SIZE) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("We have " + _writesSinceDecrypt + " available to decrypt... doing so"); - decryptBlock(); - if ( (_writesSinceDecrypt > 0) && (_log.shouldLog(Log.DEBUG)) ) - _log.debug("Bytes left in the encrypted buffer after decrypt: " - + _writesSinceDecrypt); - } - } - - /** - * Decrypt the - */ - private void decryptBlock() throws IOException { - if (_writesSinceDecrypt != BLOCK_SIZE) - throw new IOException("Error decrypting - no data to decrypt"); - - if (_decryptedSize != 0) - throw new IOException("decrypted size is not 0? " + _decryptedSize); - - _context.aes().decrypt(_encryptedBuf, 0, _encryptedBuf, 0, _key, _lastBlock, BLOCK_SIZE); - DataHelper.xor(_encryptedBuf, 0, _lastBlock, 0, _encryptedBuf, 0, BLOCK_SIZE); - int payloadBytes = countBlockPayload(_encryptedBuf, 0); - - for (int i = 0; i < payloadBytes; i++) { - int c = _encryptedBuf[i]; - if (c <= 0) - c += 256; - _decryptedBuf[i] = c; - } - _decryptedSize = payloadBytes; - - _cumulativePaddingStripped += BLOCK_SIZE - payloadBytes; - _cumulativePrepared += payloadBytes; - - System.arraycopy(_encryptedBuf, 0, _lastBlock, 0, BLOCK_SIZE); - - _writesSinceDecrypt = 0; - } - - /** - * How many non-padded bytes are there in the block starting at the given - * location. - * - * PKCS#5 specifies the padding for the block has the # of padding bytes - * located in the last byte of the block, and each of the padding bytes are - * equal to that value. - * e.g. in a 4 byte block: - * 0x0a padded would become - * 0x0a 0x03 0x03 0x03 - * e.g. in a 4 byte block: - * 0x01 0x02 padded would become - * 0x01 0x02 0x02 0x02 - * - * We use 16 byte blocks in this AES implementation - * - * @throws IOException if the padding is invalid - */ - private int countBlockPayload(byte data[], int startIndex) throws IOException { - int numPadBytes = data[startIndex + BLOCK_SIZE - 1]; - if ((numPadBytes >= BLOCK_SIZE) || (numPadBytes <= 0)) { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("countBlockPayload on block index " + startIndex - + numPadBytes + " is an invalid # of pad bytes"); - throw new IOException("Invalid number of pad bytes (" + numPadBytes - + ") for " + startIndex + " index"); - } - - // optional, but a really good idea: verify the padding - if (true) { - for (int i = BLOCK_SIZE - numPadBytes; i < BLOCK_SIZE; i++) { - if (data[startIndex + i] != (byte) numPadBytes) { - throw new IOException("Incorrect padding on decryption: data[" + i - + "] = " + data[startIndex + i] + " not " + numPadBytes); - } - } - } - - return BLOCK_SIZE - numPadBytes; - } - - int remainingBytes() { - return _writesSinceDecrypt; - } - - int readyBytes() { - return _decryptedSize; - } - - /** - * Test AESOutputStream/AESInputStream - */ - public static void main(String args[]) { - I2PAppContext ctx = new I2PAppContext(); - - try { - System.out.println("pwd=" + new java.io.File(".").getAbsolutePath()); - System.out.println("Beginning"); - runTest(ctx); - } catch (Throwable e) { - ctx.logManager().getLog(AESInputStream.class).error("Fail", e); - } - try { Thread.sleep(30*1000); } catch (InterruptedException ie) {} - System.out.println("Done"); - } - private static void runTest(I2PAppContext ctx) { - Log log = ctx.logManager().getLog(AESInputStream.class); - log.setMinimumPriority(Log.DEBUG); - byte orig[] = new byte[1024 * 32]; - RandomSource.getInstance().nextBytes(orig); - //byte orig[] = DataHelper.getASCII("you are my sunshine, my only sunshine"); - SessionKey key = KeyGenerator.getInstance().generateSessionKey(); - byte iv[] = DataHelper.getASCII("there once was a"); - - for (int i = 0; i < 20; i++) { - runTest(ctx, orig, key, iv); - } - - log.info("Done testing 32KB data"); - - orig = new byte[20]; - RandomSource.getInstance().nextBytes(orig); - for (int i = 0; i < 20; i++) { - runTest(ctx, orig, key, iv); - } - - log.info("Done testing 20 byte data"); - - orig = new byte[3]; - RandomSource.getInstance().nextBytes(orig); - for (int i = 0; i < 20; i++) { - runTest(ctx, orig, key, iv); - } - - log.info("Done testing 3 byte data"); - - orig = new byte[0]; - RandomSource.getInstance().nextBytes(orig); - for (int i = 0; i < 20; i++) { - runTest(ctx, orig, key, iv); - } - - log.info("Done testing 0 byte data"); - - for (int i = 0; i <= 32768; i++) { - orig = new byte[i]; - ctx.random().nextBytes(orig); - try { - log.info("Testing " + orig.length); - runTest(ctx, orig, key, iv); - } catch (RuntimeException re) { - log.error("Error testing " + orig.length); - throw re; - } - } - -/* - orig = new byte[615280]; - - RandomSource.getInstance().nextBytes(orig); - for (int i = 0; i < 20; i++) { - runTest(ctx, orig, key, iv); - } - - log.info("Done testing 615280 byte data"); -*/ - /* - for (int i = 0; i < 100; i++) { - orig = new byte[ctx.random().nextInt(1024*1024)]; - ctx.random().nextBytes(orig); - try { - runTest(ctx, orig, key, iv); - } catch (RuntimeException re) { - log.error("Error testing " + orig.length); - throw re; - } - } - - log.info("Done testing 100 random lengths"); - */ - - orig = new byte[32]; - RandomSource.getInstance().nextBytes(orig); - try { - runOffsetTest(ctx, orig, key, iv); - } catch (Exception e) { - log.info("Error running offset test", e); - } - - log.info("Done testing offset test (it should have come back with a statement NOT EQUAL!)"); - - try { - Thread.sleep(30 * 1000); - } catch (InterruptedException ie) { // nop - } - } - - private static void runTest(I2PAppContext ctx, byte orig[], SessionKey key, byte[] iv) { - Log log = ctx.logManager().getLog(AESInputStream.class); - try { - long start = Clock.getInstance().now(); - ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); - out.write(orig); - out.close(); - - byte encrypted[] = origStream.toByteArray(); - long endE = Clock.getInstance().now(); - - ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encrypted); - AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv); - ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - byte buf[] = new byte[1024 * 32]; - int read = DataHelper.read(sin, buf); - if (read > 0) baos.write(buf, 0, read); - sin.close(); - byte fin[] = baos.toByteArray(); - long end = Clock.getInstance().now(); - Hash origHash = SHA256Generator.getInstance().calculateHash(orig); - - Hash newHash = SHA256Generator.getInstance().calculateHash(fin); - boolean eq = origHash.equals(newHash); - if (eq) { - //log.info("Equal hashes. hash: " + origHash); - } else { - throw new RuntimeException("NOT EQUAL! len=" + orig.length + " read=" + read - + "\norig: \t" + Base64.encode(orig) + "\nnew : \t" - + Base64.encode(fin)); - } - boolean ok = DataHelper.eq(orig, fin); - log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); - log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); - log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); - log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); - - } catch (IOException ioe) { - log.error("ERROR transferring", ioe); - } - //try { Thread.sleep(5000); } catch (Throwable t) {} - } - - private static void runOffsetTest(I2PAppContext ctx, byte orig[], SessionKey key, byte[] iv) { - Log log = ctx.logManager().getLog(AESInputStream.class); - try { - long start = Clock.getInstance().now(); - ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); - out.write(orig); - out.close(); - - byte encrypted[] = origStream.toByteArray(); - long endE = Clock.getInstance().now(); - - log.info("Encrypted segment length: " + encrypted.length); - byte encryptedSegment[] = new byte[40]; - System.arraycopy(encrypted, 0, encryptedSegment, 0, 40); - - ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encryptedSegment); - AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv); - ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - byte buf[] = new byte[1024 * 32]; - int read = DataHelper.read(sin, buf); - int remaining = sin.remainingBytes(); - int readyBytes = sin.readyBytes(); - log.info("Read: " + read); - if (read > 0) baos.write(buf, 0, read); - sin.close(); - byte fin[] = baos.toByteArray(); - log.info("fin.length: " + fin.length + " remaining: " + remaining + " ready: " + readyBytes); - long end = Clock.getInstance().now(); - Hash origHash = SHA256Generator.getInstance().calculateHash(orig); - - Hash newHash = SHA256Generator.getInstance().calculateHash(fin); - boolean eq = origHash.equals(newHash); - if (eq) - log.info("Equal hashes. hash: " + origHash); - else - throw new RuntimeException("NOT EQUAL! len=" + orig.length + "\norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin)); - boolean ok = DataHelper.eq(orig, fin); - log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); - log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); - log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); - log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); - } catch (RuntimeException re) { - throw re; - } catch (IOException ioe) { - log.error("ERROR transferring", ioe); - } - //try { Thread.sleep(5000); } catch (Throwable t) {} - } -} diff --git a/core/java/test/junit/net/i2p/crypto/AESInputStreamTest.java b/core/java/test/junit/net/i2p/crypto/AESInputStreamTest.java deleted file mode 100644 index 716aa6ef09..0000000000 --- a/core/java/test/junit/net/i2p/crypto/AESInputStreamTest.java +++ /dev/null @@ -1,104 +0,0 @@ -package net.i2p.crypto; -/* - * free (adj.): unencumbered; not under the control of others - * Written by jrandom in 2003 and released into the public domain - * with no warranty of any kind, either expressed or implied. - * It probably won't make your computer catch on fire, or eat - * your children, but it might. Use at your own risk. - * - */ - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; - -import junit.framework.TestCase; -import net.i2p.I2PAppContext; -import net.i2p.data.DataHelper; -import net.i2p.data.Hash; -import net.i2p.data.SessionKey; -import net.i2p.util.RandomSource; -/** - * @author Comwiz - */ -public class AESInputStreamTest extends TestCase { - public void testMultiple() throws Exception{ - SessionKey key = KeyGenerator.getInstance().generateSessionKey(); - byte iv[] = DataHelper.getASCII("there once was a"); - - int[] sizes = {1024 * 32, 20, 3, 0}; - - for(int j = 0; j < sizes.length; j++){ - byte orig[] = new byte[sizes[j]]; - for (int i = 0; i < 20; i++) { - RandomSource.getInstance().nextBytes(orig); - runTest(orig, key, iv); - } - } - - } - - private static void runTest(byte orig[], SessionKey key, byte[] iv) throws Exception{ - I2PAppContext ctx = I2PAppContext.getGlobalContext(); - - ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); - out.write(orig); - out.close(); - - byte encrypted[] = origStream.toByteArray(); - - ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encrypted); - AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv); - ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - byte buf[] = new byte[1024 * 32]; - int read = DataHelper.read(sin, buf); - if (read > 0) baos.write(buf, 0, read); - sin.close(); - byte fin[] = baos.toByteArray(); - - Hash origHash = SHA256Generator.getInstance().calculateHash(orig); - Hash newHash = SHA256Generator.getInstance().calculateHash(fin); - - assertEquals(origHash, newHash); - assertTrue(DataHelper.eq(orig, fin)); - } - - public static void testOffset() throws Exception{ - I2PAppContext ctx = I2PAppContext.getGlobalContext(); - - byte[] orig = new byte[32]; - RandomSource.getInstance().nextBytes(orig); - - SessionKey key = KeyGenerator.getInstance().generateSessionKey(); - byte iv[] = DataHelper.getASCII("there once was a"); - - ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); - out.write(orig); - out.close(); - - byte encrypted[] = origStream.toByteArray(); - - byte encryptedSegment[] = new byte[40]; - System.arraycopy(encrypted, 0, encryptedSegment, 0, 40); - - ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encryptedSegment); - AESInputStream sin = new AESInputStream(ctx, encryptedStream, key, iv); - ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - byte buf[] = new byte[1024 * 32]; - int read = DataHelper.read(sin, buf); - int remaining = sin.remainingBytes(); - int readyBytes = sin.readyBytes(); - - if (read > 0) - baos.write(buf, 0, read); - sin.close(); - byte fin[] = baos.toByteArray(); - - Hash origHash = SHA256Generator.getInstance().calculateHash(orig); - Hash newHash = SHA256Generator.getInstance().calculateHash(fin); - - assertFalse(origHash.equals(newHash)); - assertFalse(DataHelper.eq(orig, fin)); - } -} diff --git a/core/java/test/junit/net/i2p/crypto/AESOutputStream.java b/core/java/test/junit/net/i2p/crypto/AESOutputStream.java deleted file mode 100644 index c754813e99..0000000000 --- a/core/java/test/junit/net/i2p/crypto/AESOutputStream.java +++ /dev/null @@ -1,152 +0,0 @@ -package net.i2p.crypto; - -/* - * free (adj.): unencumbered; not under the control of others - * Written by jrandom in 2003 and released into the public domain - * with no warranty of any kind, either expressed or implied. - * It probably won't make your computer catch on fire, or eat - * your children, but it might. Use at your own risk. - * - */ - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; - -import net.i2p.I2PAppContext; -import net.i2p.data.DataHelper; -import net.i2p.data.SessionKey; -import net.i2p.util.Log; - -/** - * This writes everything as CBC with PKCS#5 padding, but each block is padded - * so as soon as a block is received it can be decrypted (rather than wait for - * an arbitrary number of blocks to arrive). That means that each block sent - * will contain exactly one padding byte (unless it was flushed with - * numBytes % (BLOCK_SIZE-1) != 0, in which case that last block will be padded - * with up to 15 bytes). So we have an expansion factor of 6.25%. c'est la vie - * - */ -public class AESOutputStream extends FilterOutputStream { - private Log _log; - private I2PAppContext _context; - private SessionKey _key; - private byte[] _lastBlock; - /** - * buffer containing the unwritten bytes. The first unwritten - * byte is _lastCommitted+1, and the last unwritten byte is _nextWrite-1 - * (aka the next byte to be written on the array is _nextWrite) - */ - private byte[] _unencryptedBuf; - private byte _writeBlock[]; - /** how many bytes have we been given since we flushed it to the stream? */ - private int _writesSinceCommit; - private long _cumulativeProvided; // how many bytes provided to this stream - private long _cumulativeWritten; // how many bytes written to the underlying stream - private long _cumulativePadding; // how many bytes of padding written - - public final static float EXPANSION_FACTOR = 1.0625f; // 6% overhead w/ the padding - - private final static int BLOCK_SIZE = 16; - private final static int MAX_BUF = 256; - - public AESOutputStream(I2PAppContext context, OutputStream source, SessionKey key, byte[] iv) { - super(source); - _context = context; - _log = context.logManager().getLog(AESOutputStream.class); - _key = key; - _lastBlock = new byte[BLOCK_SIZE]; - System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE); - _unencryptedBuf = new byte[MAX_BUF]; - _writeBlock = new byte[BLOCK_SIZE]; - _writesSinceCommit = 0; - } - - @Override - public void write(int val) throws IOException { - _cumulativeProvided++; - _unencryptedBuf[_writesSinceCommit++] = (byte)(val & 0xFF); - if (_writesSinceCommit == _unencryptedBuf.length) - doFlush(); - } - - @Override - public void write(byte src[]) throws IOException { - write(src, 0, src.length); - } - - @Override - public void write(byte src[], int off, int len) throws IOException { - // i'm too lazy to unroll this into the partial writes (dealing with - // wrapping around the buffer size) - for (int i = 0; i < len; i++) - write(src[i+off]); - } - - @Override - public void close() throws IOException { - flush(); - out.close(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Cumulative bytes provided to this stream / written out / padded: " - + _cumulativeProvided + "/" + _cumulativeWritten + "/" + _cumulativePadding); - } - - @Override - public void flush() throws IOException { - doFlush(); - out.flush(); - } - - private void doFlush() throws IOException { - if (_log.shouldLog(Log.INFO)) - _log.info("doFlush(): writesSinceCommit=" + _writesSinceCommit); - writeEncrypted(); - _writesSinceCommit = 0; - } - - /** - * Encrypt an arbitrary size array with AES using CBC and PKCS#5 padding, - * write it to the stream, and set _lastBlock to the last encrypted - * block. This operation works by taking every (BLOCK_SIZE-1) bytes - * from the src, padding it with PKCS#5 (aka adding 0x01), and encrypting - * it. If the last block doesn't contain exactly (BLOCK_SIZE-1) bytes, it - * is padded with PKCS#5 as well (adding # padding bytes repeated that many - * times). - * - */ - private void writeEncrypted() throws IOException { - int numBlocks = _writesSinceCommit / (BLOCK_SIZE - 1); - - if (_log.shouldLog(Log.INFO)) - _log.info("writeE(): #=" + _writesSinceCommit + " blocks=" + numBlocks); - - for (int i = 0; i < numBlocks; i++) { - DataHelper.xor(_unencryptedBuf, i * 15, _lastBlock, 0, _writeBlock, 0, 15); - // the padding byte for "full" blocks - _writeBlock[BLOCK_SIZE - 1] = (byte)(_lastBlock[BLOCK_SIZE - 1] ^ 0x01); - _context.aes().encrypt(_writeBlock, 0, _writeBlock, 0, _key, _lastBlock, BLOCK_SIZE); - out.write(_writeBlock); - System.arraycopy(_writeBlock, 0, _lastBlock, 0, BLOCK_SIZE); - _cumulativeWritten += BLOCK_SIZE; - _cumulativePadding++; - } - - if (_writesSinceCommit % 15 != 0) { - // we need to do non trivial padding - int remainingBytes = _writesSinceCommit - numBlocks * 15; - int paddingBytes = BLOCK_SIZE - remainingBytes; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Padding " + _writesSinceCommit + " with " + paddingBytes + " bytes in " + (numBlocks+1) + " blocks"); - System.arraycopy(_unencryptedBuf, numBlocks * 15, _writeBlock, 0, remainingBytes); - Arrays.fill(_writeBlock, remainingBytes, BLOCK_SIZE, (byte) paddingBytes); - DataHelper.xor(_writeBlock, 0, _lastBlock, 0, _writeBlock, 0, BLOCK_SIZE); - _context.aes().encrypt(_writeBlock, 0, _writeBlock, 0, _key, _lastBlock, BLOCK_SIZE); - out.write(_writeBlock); - System.arraycopy(_writeBlock, 0, _lastBlock, 0, BLOCK_SIZE); - _cumulativePadding += paddingBytes; - _cumulativeWritten += BLOCK_SIZE; - } - } -} \ No newline at end of file