- Add hasAES()
   - Fix bugs in unused hasSSE3(), hasSSE41(), hasSSE42()
 * Crypto: Use JVM AES when faster
 * SystemVersion: Add isJava7() and isX86()
This commit is contained in:
zzz
2014-05-09 15:28:54 +00:00
parent cd91a6b2a4
commit 8d9790fd77
5 changed files with 101 additions and 28 deletions

View File

@ -2,9 +2,10 @@ package freenet.support.CPUInformation;
/**
* Moved out of CPUID.java
* Ref: http://en.wikipedia.org/wiki/CPUID
* @since 0.8.7
*/
abstract class CPUIDCPUInfo
abstract class CPUIDCPUInfo implements CPUInfo
{
protected static boolean isX64 = false;
@ -12,33 +13,48 @@ abstract class CPUIDCPUInfo
{
return CPUID.getCPUVendorID();
}
public boolean hasMMX()
{
return (CPUID.getEDXCPUFlags() & 0x800000) != 0; //EDX Bit 23
}
public boolean hasSSE(){
return (CPUID.getEDXCPUFlags() & 0x2000000) != 0; //EDX Bit 25
}
public boolean hasSSE2()
{
return (CPUID.getEDXCPUFlags() & 0x4000000) != 0; //EDX Bit 26
}
public boolean hasSSE3()
{
return (CPUID.getEDXCPUFlags() & 0x1) != 0; //ECX Bit 0
return (CPUID.getECXCPUFlags() & 0x1) != 0; //ECX Bit 0
}
public boolean hasSSE41()
{
return (CPUID.getEDXCPUFlags() & 0x80000) != 0; //ECX Bit 19
return (CPUID.getECXCPUFlags() & 0x80000) != 0; //ECX Bit 19
}
public boolean hasSSE42()
{
return (CPUID.getEDXCPUFlags() & 0x100000) != 0; //ECX Bit 20
return (CPUID.getECXCPUFlags() & 0x100000) != 0; //ECX Bit 20
}
public boolean hasSSE4A()
{
return (CPUID.getExtendedECXCPUFlags() & 0x40) != 0; //Extended ECX Bit 6
}
/**
* @return true iff the CPU supports the AES-NI instruction set.
* @since 0.9.14
*/
public boolean hasAES() {
return (CPUID.getECXCPUFlags() & 0x2000000) != 0; //ECX Bit 25
}
public abstract boolean hasX64();
}

View File

@ -62,4 +62,10 @@ public interface CPUInfo
* @return true iff the CPU support the SSE4A instruction set.
*/
public boolean hasSSE4A();
/**
* @return true iff the CPU supports the AES-NI instruction set.
* @since 0.9.14
*/
public boolean hasAES();
}

View File

@ -12,16 +12,21 @@ package net.i2p.crypto;
import java.security.InvalidKeyException;
// for using system version
//import java.security.GeneralSecurityException;
//import javax.crypto.Cipher;
//import javax.crypto.spec.IvParameterSpec;
//import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import freenet.support.CPUInformation.CPUID;
import freenet.support.CPUInformation.CPUInfo;
import freenet.support.CPUInformation.UnknownCPUException;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.SessionKey;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
import net.i2p.util.SystemVersion;
/**
* Wrapper for AES cypher operation using Cryptix's Rijndael implementation. Implements
@ -37,28 +42,47 @@ public class CryptixAESEngine extends AESEngine {
// keys are now cached in the SessionKey objects
//private CryptixAESKeyCache _cache;
/**** see comments for main() below
private static final boolean USE_SYSTEM_AES;
static {
boolean systemOK = false;
try {
systemOK = Cipher.getMaxAllowedKeyLength("AES") >= 256;
} catch (GeneralSecurityException gse) {
// a NoSuchAlgorithmException
} catch (NoSuchMethodError nsme) {
// JamVM, gij
if (hasAESNI()) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
systemOK = true;
systemOK = Cipher.getMaxAllowedKeyLength("AES") >= 256;
} catch (GeneralSecurityException gse) {
// a NoSuchAlgorithmException
} catch (NoSuchMethodError nsme) {
// JamVM, gij
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
systemOK = true;
} catch (GeneralSecurityException gse) {
}
}
}
USE_SYSTEM_AES = systemOK;
//System.out.println("Using system AES? " + systemOK);
}
****/
/**
* Do we have AES-NI support in the processor and JVM?
* Only on 64-bit x86 Java 7 fast JVMs, with AES-NI support.
* See comments in main() below.
* @since 0.9.14
*/
private static boolean hasAESNI() {
if (SystemVersion.isX86() && SystemVersion.is64Bit() && SystemVersion.isJava7() &&
!SystemVersion.isApache() && !SystemVersion.isGNU()) {
try {
return CPUID.getInfo().hasAES();
} catch (UnknownCPUException e) {
return false;
}
} else {
return false;
}
}
/** */
public CryptixAESEngine(I2PAppContext context) {
@ -104,7 +128,6 @@ public class CryptixAESEngine extends AESEngine {
return;
}
/****
if (USE_SYSTEM_AES) {
try {
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
@ -118,7 +141,6 @@ public class CryptixAESEngine extends AESEngine {
_log.warn("Java encrypt fail", gse);
}
}
****/
int numblock = length / 16;
@ -159,7 +181,6 @@ public class CryptixAESEngine extends AESEngine {
return ;
}
/****
if (USE_SYSTEM_AES) {
try {
SecretKeySpec key = new SecretKeySpec(sessionKey.getData(), "AES");
@ -173,7 +194,6 @@ public class CryptixAESEngine extends AESEngine {
_log.warn("Java decrypt fail", gse);
}
}
****/
int numblock = length / 16;
if (length % 16 != 0) {
@ -261,8 +281,8 @@ public class CryptixAESEngine extends AESEngine {
}
/******
private static final int MATCH_RUNS = 5000;
private static final int TIMING_RUNS = 10000;
private static final int MATCH_RUNS = 11000;
private static final int TIMING_RUNS = 100000;
******/
/**
@ -282,6 +302,15 @@ public class CryptixAESEngine extends AESEngine {
* jrockit 9780 n/a
*</pre>
*
* Speed ups with AES-NI:
* May 2014 AMD Hexcore 100K runs:
*<pre>
* JVM Cryptix (ms) System (ms)
* OpenJDK 6 3314 5030
* OpenJDK 7 3285 2476
*</pre>
*
*
*/
/*******
public static void main(String args[]) {

View File

@ -181,8 +181,7 @@ public class NativeBigInteger extends BigInteger {
*/
private static final boolean _is64 = SystemVersion.is64Bit();
private static final boolean _isX86 = System.getProperty("os.arch").contains("86") ||
System.getProperty("os.arch").equals("amd64");
private static final boolean _isX86 = SystemVersion.isX86();
private static final boolean _isArm = SystemVersion.isARM();

View File

@ -16,6 +16,8 @@ public abstract class SystemVersion {
private static final boolean _isWin = System.getProperty("os.name").startsWith("Win");
private static final boolean _isMac = System.getProperty("os.name").startsWith("Mac");
private static final boolean _isArm = System.getProperty("os.arch").startsWith("arm");
private static final boolean _isX86 = System.getProperty("os.arch").contains("86") ||
System.getProperty("os.arch").equals("amd64");
private static final boolean _isAndroid;
private static final boolean _isApache;
private static final boolean _isGNU;
@ -23,6 +25,7 @@ public abstract class SystemVersion {
private static final boolean _hasWrapper = System.getProperty("wrapper.version") != null;
private static final boolean _oneDotSix;
private static final boolean _oneDotSeven;
private static final int _androidSDK;
static {
@ -56,8 +59,10 @@ public abstract class SystemVersion {
if (_isAndroid) {
_oneDotSix = _androidSDK >= 9;
_oneDotSeven = _androidSDK >= 19;
} else {
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
_oneDotSeven = VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
}
}
@ -94,6 +99,13 @@ public abstract class SystemVersion {
return _isArm;
}
/**
* @since 0.9.14
*/
public static boolean isX86() {
return _isX86;
}
/**
* Better than (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0
* as it handles Android also, where java.version = "0".
@ -104,6 +116,17 @@ public abstract class SystemVersion {
return _oneDotSix;
}
/**
* Better than (new VersionComparator()).compare(System.getProperty("java.version"), "1.7") >= 0
* as it handles Android also, where java.version = "0".
*
* @return true if Java 1.7 or higher, or Android API 19 or higher
* @since 0.9.14
*/
public static boolean isJava7() {
return _oneDotSeven;
}
/**
* This isn't always correct.
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit