forked from I2P_Developers/i2p.i2p
2004-10-08 jrandom
* Revamp the AESInputStream so it doesn't allocate any temporary objects during its operation.
This commit is contained in:
@@ -46,66 +46,81 @@ public class AESInputStream extends FilterInputStream {
|
|||||||
private long _cumulativePrepared; // how many bytes decrypted and added to _readyBuf
|
private long _cumulativePrepared; // how many bytes decrypted and added to _readyBuf
|
||||||
private long _cumulativePaddingStripped; // how many bytes have been stripped
|
private long _cumulativePaddingStripped; // how many bytes have been stripped
|
||||||
|
|
||||||
private ByteArrayOutputStream _encryptedBuf; // read from the stream but not yet decrypted
|
/** read but not yet decrypted */
|
||||||
private List _readyBuf; // list of Bytes ready to be consumed, where index 0 is the first
|
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 = CryptixRijndael_Algorithm._BLOCK_SIZE;
|
private final static int BLOCK_SIZE = CryptixRijndael_Algorithm._BLOCK_SIZE;
|
||||||
private final static int READ_SIZE = BLOCK_SIZE;
|
|
||||||
private final static int DECRYPT_SIZE = BLOCK_SIZE - 1;
|
|
||||||
|
|
||||||
public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte iv[]) {
|
public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte[] iv) {
|
||||||
super(source);
|
super(source);
|
||||||
_context = context;
|
_context = context;
|
||||||
_log = context.logManager().getLog(AESInputStream.class);
|
_log = context.logManager().getLog(AESInputStream.class);
|
||||||
_key = key;
|
_key = key;
|
||||||
_lastBlock = new byte[BLOCK_SIZE];
|
_lastBlock = new byte[BLOCK_SIZE];
|
||||||
System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE);
|
System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||||
_encryptedBuf = new ByteArrayOutputStream(BLOCK_SIZE);
|
_encryptedBuf = new byte[BLOCK_SIZE];
|
||||||
_readyBuf = new ArrayList(1024);
|
_writesSinceDecrypt = 0;
|
||||||
|
_decryptedBuf = new int[BLOCK_SIZE-1];
|
||||||
|
_decryptedSize = 0;
|
||||||
_cumulativePaddingStripped = 0;
|
_cumulativePaddingStripped = 0;
|
||||||
_eofFound = false;
|
_eofFound = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read() throws IOException {
|
public int read() throws IOException {
|
||||||
while ((!_eofFound) && (_readyBuf.size() <= 0)) {
|
while ((!_eofFound) && (_decryptedSize <= 0)) {
|
||||||
refill(READ_SIZE);
|
refill();
|
||||||
}
|
}
|
||||||
Integer nval = getNext();
|
if (_decryptedSize > 0) {
|
||||||
if (nval != null) {
|
int c = _decryptedBuf[0];
|
||||||
return nval.intValue();
|
System.arraycopy(_decryptedBuf, 1, _decryptedBuf, 0, _decryptedBuf.length-1);
|
||||||
}
|
_decryptedSize--;
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
return c;
|
||||||
_log.debug("No byte available. eof? " + _eofFound);
|
} else if (_eofFound) {
|
||||||
|
|
||||||
if (_eofFound)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
} else {
|
||||||
throw new IOException("Not EOF, but none available? " + _readyBuf.size() + "/" + _encryptedBuf.size()
|
throw new IOException("Not EOF, but none available? " + _decryptedSize
|
||||||
+ "/" + _cumulativeRead + "... impossible");
|
+ "/" + _writesSinceDecrypt
|
||||||
|
+ "/" + _cumulativeRead + "... impossible");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read(byte dest[]) throws IOException {
|
public int read(byte dest[]) throws IOException {
|
||||||
for (int i = 0; i < dest.length; i++) {
|
return read(dest, 0, dest.length);
|
||||||
int val = read();
|
|
||||||
if (val == -1) {
|
|
||||||
// no more to read... can they expect more?
|
|
||||||
if (_eofFound && (i == 0)) return -1;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
dest[i] = (byte) val;
|
|
||||||
}
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug("Read the full buffer of size " + dest.length);
|
|
||||||
return dest.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int read(byte dest[], int off, int len) throws IOException {
|
public int read(byte dest[], int off, int len) throws IOException {
|
||||||
byte buf[] = new byte[len];
|
for (int i = 0; i < len; i++) {
|
||||||
int read = read(buf);
|
int val = read();
|
||||||
if (read == -1) return -1;
|
if (val == -1) {
|
||||||
System.arraycopy(buf, 0, dest, off, read);
|
// no more to read... can they expect more?
|
||||||
return read;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long skip(long numBytes) throws IOException {
|
public long skip(long numBytes) throws IOException {
|
||||||
@@ -117,25 +132,15 @@ public class AESInputStream extends FilterInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int available() throws IOException {
|
public int available() throws IOException {
|
||||||
return _readyBuf.size();
|
return _decryptedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
//_log.debug("We have " + _encryptedBuf.size() + " available to decrypt... doing so");
|
|
||||||
//decrypt();
|
|
||||||
//byte buf[] = new byte[_readyBuf.size()];
|
|
||||||
//for (int i = 0; i < buf.length; i++)
|
|
||||||
// buf[i] = ((Integer)_readyBuf.get(i)).byteValue();
|
|
||||||
//_log.debug("After decrypt: readyBuf.size: " + _readyBuf.size() + "\n val:\t" + Base64.encode(buf));
|
|
||||||
int ready = _readyBuf.size();
|
|
||||||
int encrypted = _readyBuf.size();
|
|
||||||
_readyBuf.clear();
|
|
||||||
_encryptedBuf.reset();
|
|
||||||
in.close();
|
in.close();
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Cumulative bytes read from source/decrypted/stripped: " + _cumulativeRead + "/"
|
_log.debug("Cumulative bytes read from source/decrypted/stripped: " + _cumulativeRead + "/"
|
||||||
+ _cumulativePrepared + "/" + _cumulativePaddingStripped + "] remaining [" + ready + " ready, "
|
+ _cumulativePrepared + "/" + _cumulativePaddingStripped + "] remaining [" + _decryptedSize + " ready, "
|
||||||
+ encrypted + " still encrypted]");
|
+ _writesSinceDecrypt + " still encrypted]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mark(int readLimit) { // nop
|
public void mark(int readLimit) { // nop
|
||||||
@@ -149,116 +154,60 @@ public class AESInputStream extends FilterInputStream {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the next ready byte, or null if no bytes are ready. this does not refill or block
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private Integer getNext() {
|
|
||||||
if (_readyBuf.size() > 0) {
|
|
||||||
return (Integer) _readyBuf.remove(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read at least one new byte from the underlying stream, and up to max new bytes,
|
* 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
|
* but not necessarily enough for a new decrypted block. This blocks until at least
|
||||||
* one new byte is read from the stream
|
* one new byte is read from the stream
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void refill(int max) throws IOException {
|
private void refill() throws IOException {
|
||||||
if (!_eofFound) {
|
if (!_eofFound) {
|
||||||
byte buf[] = new byte[max];
|
int read = in.read(_encryptedBuf, _writesSinceDecrypt, _encryptedBuf.length - _writesSinceDecrypt);
|
||||||
int read = in.read(buf);
|
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
_eofFound = true;
|
_eofFound = true;
|
||||||
} else if (read > 0) {
|
} else if (read > 0) {
|
||||||
//_log.debug("Read from the source stream " + read + " bytes");
|
|
||||||
_cumulativeRead += read;
|
_cumulativeRead += read;
|
||||||
_encryptedBuf.write(buf, 0, read);
|
_writesSinceDecrypt += read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (false) return; // true to keep the data for decrypt/display on close
|
if (_writesSinceDecrypt == BLOCK_SIZE) {
|
||||||
if (_encryptedBuf.size() > 0) {
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
if (_encryptedBuf.size() >= DECRYPT_SIZE) {
|
_log.debug("We have " + _writesSinceDecrypt + " available to decrypt... doing so");
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
decryptBlock();
|
||||||
_log.debug("We have " + _encryptedBuf.size() + " available to decrypt... doing so");
|
if ( (_writesSinceDecrypt > 0) && (_log.shouldLog(Log.DEBUG)) )
|
||||||
decrypt();
|
_log.debug("Bytes left in the encrypted buffer after decrypt: "
|
||||||
if ( (_encryptedBuf.size() > 0) && (_log.shouldLog(Log.DEBUG)) )
|
+ _writesSinceDecrypt);
|
||||||
_log.debug("Bytes left in the encrypted buffer after decrypt: " + _encryptedBuf.size());
|
|
||||||
} else {
|
|
||||||
if (_eofFound) {
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug("EOF and not enough bytes to decrypt [size = " + _encryptedBuf.size()
|
|
||||||
+ " totalCumulative: " + _cumulativeRead + "/"+_cumulativePrepared +"]!");
|
|
||||||
} else {
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug("Not enough bytes to decrypt [size = " + _encryptedBuf.size()
|
|
||||||
+ " totalCumulative: " + _cumulativeRead + "/"+_cumulativePrepared +"]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take (n*BLOCK_SIZE) bytes off the _encryptedBuf, decrypt them, and place
|
* Decrypt the
|
||||||
* them on _readyBuf
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
private void decrypt() throws IOException {
|
private void decryptBlock() throws IOException {
|
||||||
byte encrypted[] = _encryptedBuf.toByteArray();
|
if (_writesSinceDecrypt != BLOCK_SIZE)
|
||||||
_encryptedBuf.reset();
|
|
||||||
|
|
||||||
if ((encrypted == null) || (encrypted.length <= 0))
|
|
||||||
throw new IOException("Error decrypting - no data to decrypt");
|
throw new IOException("Error decrypting - no data to decrypt");
|
||||||
|
|
||||||
int numBlocks = encrypted.length / BLOCK_SIZE;
|
if (_decryptedSize != 0)
|
||||||
if ((encrypted.length % BLOCK_SIZE) != 0) {
|
throw new IOException("wtf, decrypted size is not 0? " + _decryptedSize);
|
||||||
// it was flushed / handled off the BLOCK_SIZE segments, so put the excess
|
|
||||||
// back into the _encryptedBuf for later handling
|
_context.aes().decrypt(_encryptedBuf, 0, _encryptedBuf, 0, _key, _lastBlock, BLOCK_SIZE);
|
||||||
int trailing = encrypted.length % BLOCK_SIZE;
|
DataHelper.xor(_encryptedBuf, 0, _lastBlock, 0, _encryptedBuf, 0, BLOCK_SIZE);
|
||||||
_encryptedBuf.write(encrypted, encrypted.length - trailing, trailing);
|
int payloadBytes = countBlockPayload(_encryptedBuf, 0);
|
||||||
byte nencrypted[] = new byte[encrypted.length - trailing];
|
|
||||||
System.arraycopy(encrypted, 0, nencrypted, 0, nencrypted.length);
|
for (int i = 0; i < payloadBytes; i++) {
|
||||||
encrypted = nencrypted;
|
int c = _encryptedBuf[i];
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (c <= 0)
|
||||||
_log.warn("Decrypt got odd segment - " + trailing
|
c += 256;
|
||||||
+ " bytes pushed back for later decryption - corrupted or slow data stream perhaps?");
|
_decryptedBuf[i] = c;
|
||||||
} else {
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
|
||||||
_log.debug(encrypted.length + " bytes makes up " + numBlocks + " blocks to decrypt normally");
|
|
||||||
}
|
}
|
||||||
|
_decryptedSize = payloadBytes;
|
||||||
|
|
||||||
for (int i = 0; i < numBlocks; i++) {
|
_cumulativePaddingStripped += BLOCK_SIZE - payloadBytes;
|
||||||
_context.aes().decrypt(encrypted, i * BLOCK_SIZE, encrypted, i * BLOCK_SIZE, _key, _lastBlock, BLOCK_SIZE);
|
_cumulativePrepared += payloadBytes;
|
||||||
DataHelper.xor(encrypted, i * BLOCK_SIZE, _lastBlock, 0, encrypted, i * BLOCK_SIZE, BLOCK_SIZE);
|
|
||||||
int payloadBytes = countBlockPayload(encrypted, i * BLOCK_SIZE);
|
|
||||||
|
|
||||||
for (int j = 0; j < payloadBytes; j++) {
|
System.arraycopy(_encryptedBuf, 0, _lastBlock, 0, BLOCK_SIZE);
|
||||||
int c = encrypted[j + i * BLOCK_SIZE];
|
|
||||||
if (c <= 0)
|
|
||||||
c += 256;
|
|
||||||
_readyBuf.add(new Integer(c));
|
|
||||||
}
|
|
||||||
_cumulativePaddingStripped += BLOCK_SIZE - payloadBytes;
|
|
||||||
_cumulativePrepared += payloadBytes;
|
|
||||||
|
|
||||||
System.arraycopy(encrypted, i * BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE);
|
_writesSinceDecrypt = 0;
|
||||||
}
|
|
||||||
|
|
||||||
int remaining = encrypted.length % BLOCK_SIZE;
|
|
||||||
if (remaining != 0) {
|
|
||||||
_encryptedBuf.write(encrypted, encrypted.length - remaining, remaining);
|
|
||||||
_log.debug("After pushing " + remaining
|
|
||||||
+ " bytes back onto the buffer, lets delay 1s our action so we don't fast busy until the net transfers data");
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException ie) { // nop
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//_log.debug("No remaining encrypted bytes beyond the block size");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,11 +252,11 @@ public class AESInputStream extends FilterInputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int remainingBytes() {
|
int remainingBytes() {
|
||||||
return _encryptedBuf.size();
|
return _writesSinceDecrypt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int readyBytes() {
|
int readyBytes() {
|
||||||
return _readyBuf.size();
|
return _decryptedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -446,7 +395,9 @@ public class AESInputStream extends FilterInputStream {
|
|||||||
if (eq) {
|
if (eq) {
|
||||||
//log.info("Equal hashes. hash: " + origHash);
|
//log.info("Equal hashes. hash: " + origHash);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("NOT EQUAL! len=" + orig.length + "\norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin));
|
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);
|
boolean ok = DataHelper.eq(orig, fin);
|
||||||
log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length);
|
log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length);
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
$Id: history.txt,v 1.39 2004/10/07 21:08:11 jrandom Exp $
|
$Id: history.txt,v 1.40 2004/10/08 13:38:49 jrandom Exp $
|
||||||
|
|
||||||
|
2004-10-08 jrandom
|
||||||
|
* Revamp the AESInputStream so it doesn't allocate any temporary objects
|
||||||
|
during its operation.
|
||||||
|
|
||||||
2004-10-08 jrandom
|
2004-10-08 jrandom
|
||||||
* Don't kill the establisher threads during a soft restart.
|
* Don't kill the establisher threads during a soft restart.
|
||||||
|
@@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RouterVersion {
|
public class RouterVersion {
|
||||||
public final static String ID = "$Revision: 1.47 $ $Date: 2004/10/07 21:08:11 $";
|
public final static String ID = "$Revision: 1.48 $ $Date: 2004/10/08 13:38:48 $";
|
||||||
public final static String VERSION = "0.4.1.1";
|
public final static String VERSION = "0.4.1.1";
|
||||||
public final static long BUILD = 13;
|
public final static long BUILD = 14;
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
System.out.println("I2P Router version: " + VERSION);
|
System.out.println("I2P Router version: " + VERSION);
|
||||||
System.out.println("Router ID: " + RouterVersion.ID);
|
System.out.println("Router ID: " + RouterVersion.ID);
|
||||||
|
Reference in New Issue
Block a user