forked from I2P_Developers/i2p.i2p
Crypto: Cache AES Ciphers
About a 10% speedup
This commit is contained in:
@@ -12,6 +12,7 @@ package net.i2p.crypto;
|
|||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
// for using system version
|
// for using system version
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
@@ -37,14 +38,21 @@ import net.i2p.util.SystemVersion;
|
|||||||
* @author jrandom, thecrypto
|
* @author jrandom, thecrypto
|
||||||
*/
|
*/
|
||||||
public final class CryptixAESEngine extends AESEngine {
|
public final class CryptixAESEngine extends AESEngine {
|
||||||
|
private final LinkedBlockingQueue<Cipher> _ciphers;
|
||||||
|
|
||||||
private final static CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm();
|
private final static CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm();
|
||||||
// keys are now cached in the SessionKey objects
|
// keys are now cached in the SessionKey objects
|
||||||
//private CryptixAESKeyCache _cache;
|
//private CryptixAESKeyCache _cache;
|
||||||
|
|
||||||
/** see test results below */
|
/** see test results below */
|
||||||
private static final int MIN_SYSTEM_AES_LENGTH = 704;
|
private static final int MIN_SYSTEM_AES_LENGTH = 640;
|
||||||
private static final boolean USE_SYSTEM_AES = hasAESNI() && CryptoCheck.isUnlimited();
|
private static final boolean USE_SYSTEM_AES = hasAESNI() && CryptoCheck.isUnlimited();
|
||||||
|
|
||||||
|
private static final boolean CACHE = true;
|
||||||
|
private static final int CACHE_SIZE = 8;
|
||||||
|
private static final SecretKeySpec ZERO_KEY = new SecretKeySpec(new byte[32], "AES");
|
||||||
|
private static final IvParameterSpec ZERO_IV = new IvParameterSpec(new byte[16], 0, 16);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do we have AES-NI support in the processor and JVM?
|
* Do we have AES-NI support in the processor and JVM?
|
||||||
* Only on 64-bit x86 Java 7 fast JVMs, with AES-NI support.
|
* Only on 64-bit x86 Java 7 fast JVMs, with AES-NI support.
|
||||||
@@ -67,6 +75,9 @@ public final class CryptixAESEngine extends AESEngine {
|
|||||||
/** */
|
/** */
|
||||||
public CryptixAESEngine(I2PAppContext context) {
|
public CryptixAESEngine(I2PAppContext context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
// testing
|
||||||
|
//_ciphers = new LinkedBlockingQueue<Cipher>(CACHE_SIZE);
|
||||||
|
_ciphers = USE_SYSTEM_AES ? new LinkedBlockingQueue<Cipher>(CACHE_SIZE) : null;
|
||||||
//_cache = new CryptixAESKeyCache();
|
//_cache = new CryptixAESKeyCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +117,10 @@ public final class CryptixAESEngine extends AESEngine {
|
|||||||
try {
|
try {
|
||||||
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
|
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
|
||||||
IvParameterSpec ivps = new IvParameterSpec(iv, ivOffset, 16);
|
IvParameterSpec ivps = new IvParameterSpec(iv, ivOffset, 16);
|
||||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
Cipher cipher = acquire();
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, ivps, _context.random());
|
cipher.init(Cipher.ENCRYPT_MODE, key, ivps, _context.random());
|
||||||
cipher.doFinal(payload, payloadIndex, length, out, outIndex);
|
cipher.doFinal(payload, payloadIndex, length, out, outIndex);
|
||||||
|
release(cipher);
|
||||||
return;
|
return;
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
@@ -153,9 +165,10 @@ public final class CryptixAESEngine extends AESEngine {
|
|||||||
try {
|
try {
|
||||||
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
|
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
|
||||||
IvParameterSpec ivps = new IvParameterSpec(iv, ivOffset, 16);
|
IvParameterSpec ivps = new IvParameterSpec(iv, ivOffset, 16);
|
||||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
Cipher cipher = acquire();
|
||||||
cipher.init(Cipher.DECRYPT_MODE, key, ivps, _context.random());
|
cipher.init(Cipher.DECRYPT_MODE, key, ivps, _context.random());
|
||||||
cipher.doFinal(payload, payloadIndex, length, out, outIndex);
|
cipher.doFinal(payload, payloadIndex, length, out, outIndex);
|
||||||
|
release(cipher);
|
||||||
return;
|
return;
|
||||||
} catch (GeneralSecurityException gse) {
|
} catch (GeneralSecurityException gse) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
@@ -250,10 +263,38 @@ public final class CryptixAESEngine extends AESEngine {
|
|||||||
CryptixRijndael_Algorithm.blockDecrypt(payload, rv, inIndex, outIndex, pkey);
|
CryptixRijndael_Algorithm.blockDecrypt(payload, rv, inIndex, outIndex, pkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******
|
/**
|
||||||
private static final int MATCH_RUNS = 11000;
|
* @return cached or new
|
||||||
private static final int TIMING_RUNS = 100000;
|
* @since 0.9.49
|
||||||
******/
|
*/
|
||||||
|
private Cipher acquire() {
|
||||||
|
Cipher rv = _ciphers.poll();
|
||||||
|
if (rv == null) {
|
||||||
|
try {
|
||||||
|
rv = Cipher.getInstance("AES/CBC/NoPadding");
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
throw new UnsupportedOperationException("AES/CBC/NoPadding", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cipher will be initialized with a zero key and IV.
|
||||||
|
*
|
||||||
|
* @since 0.9.49
|
||||||
|
*/
|
||||||
|
private void release(Cipher cipher) {
|
||||||
|
if (CACHE) {
|
||||||
|
try {
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, ZERO_KEY, ZERO_IV, _context.random());
|
||||||
|
} catch (GeneralSecurityException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ciphers.offer(cipher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test results 10K timing runs.
|
* Test results 10K timing runs.
|
||||||
@@ -286,6 +327,8 @@ public final class CryptixAESEngine extends AESEngine {
|
|||||||
*/
|
*/
|
||||||
/*******
|
/*******
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
final int MATCH_RUNS = 11000;
|
||||||
|
final int TIMING_RUNS = 100000;
|
||||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||||
try {
|
try {
|
||||||
boolean canTestSystem = USE_SYSTEM_AES;
|
boolean canTestSystem = USE_SYSTEM_AES;
|
||||||
|
|||||||
Reference in New Issue
Block a user