diff --git a/core/java/src/freenet/support/CPUInformation/CPUIDCPUInfo.java b/core/java/src/freenet/support/CPUInformation/CPUIDCPUInfo.java
index 07bf42f3434bfd230737b9dfd0a9e8230e46fa00..8515b2418b4d7743fb169a88441a6cb9ca13b7ef 100644
--- a/core/java/src/freenet/support/CPUInformation/CPUIDCPUInfo.java
+++ b/core/java/src/freenet/support/CPUInformation/CPUIDCPUInfo.java
@@ -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();
 }
diff --git a/core/java/src/freenet/support/CPUInformation/CPUInfo.java b/core/java/src/freenet/support/CPUInformation/CPUInfo.java
index e58d34beb3a86f6b1b7cea7142d91ab186b6417c..472cde9e3a44bbc0dcbc2e8f63479adba129a71c 100644
--- a/core/java/src/freenet/support/CPUInformation/CPUInfo.java
+++ b/core/java/src/freenet/support/CPUInformation/CPUInfo.java
@@ -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();
 }
diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java
index a5af3c2082a27244a8fe0308188711226247ffab..48e2de46e3ccb04439667fe31a1a18e0eb62d607 100644
--- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java
+++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java
@@ -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[]) {
diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java
index 954a8f61912de0e6ba4dec871820f2d1bc064a66..d970d76bdf33decb7d046c61a8ad26c8e6189fbc 100644
--- a/core/java/src/net/i2p/util/NativeBigInteger.java
+++ b/core/java/src/net/i2p/util/NativeBigInteger.java
@@ -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();
 
diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java
index 224b79031e1aa5c7e9e83380e66f198b00b319f0..6411058db95f114d3dd9c20a1ecb2074618c6ec6 100644
--- a/core/java/src/net/i2p/util/SystemVersion.java
+++ b/core/java/src/net/i2p/util/SystemVersion.java
@@ -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