AES-NI指令集
AES-NI是一個x86指令集架構的擴充,用於Intel和AMD微處理器,由Intel在2008年3月提出。[1]該指令集的目的是改進應用程式使用進階加密標準(AES)執行加密和解密的速度。這項技術在從企業級的大資料、區塊鏈到個人用的NAS等都用得上. 如何檢查cpu是否支援該功能
$ cat /proc/cpuinfo | grep aes | wc -l如果支援,應該是4核,得出的統計結果也是4//我家15年的佔美移動i5-4200U CPU @ 1.60GHz 居然也支援;但是13年的筆記本上不支援//工作筆記本i5-5200U不支援
成功的對比測試
用了openssl命令,終於發現開啟aes-ni有明顯區別。版本:OpenSSL 1.0.2g 1 Mar 2016
$ openssl speed -elapsed -evp aes-256-cbc$ OPENSSL_ia32cap="~0x200000200000000" openssl speed -elapsed -evp aes-256-cbc$ openssl speed -elapsed -evp aes-128-cbc$ OPENSSL_ia32cap="~0x200000200000000" openssl speed -elapsed -evp aes-128-cbc
|是否開啟|type |16 bytes | 64 bytes | 256 bytes | 1024 bytes |8192 bytes|
|———–|—————–|————-|—————|—————|——————-|—————|
|是 |aes-256-cbc | 364209.02k| 398876.69k | 401026.39k | 398883.84k | 411863.72k|
|否 |aes-256-cbc | 167362.41k | 183630.57k | 188587.43k | 181141.16k | 192430.08k|
|是 |aes-128-cbc | 496741.25k | 549389.38k | 541275.99k | 568249.34k | 557129.73k|
|否 |aes-128-cbc | 228221.45k | 253612.69k | 261900.12k | 252299.61k | 267665.41k|
戲劇場面:如上佔美機cpu比工作筆記本差,但是開啟了AES-NI反而效能好
|是否開啟|type |16 bytes | 64 bytes | 256 bytes | 1024 bytes |8192 bytes|
|———–|—————–|————-|—————|—————|——————-|—————|
|是 |aes-256-cbc |164328.05k | 185898.77k | 188741.03k | 189848.23k | 191176.70k|
|否 |aes-256-cbc |172242.04k | 185854.25k | 189062.06k | 190826.84k | 190308.35k|
|是 |aes-128-cbc |234664.05k | 254232.28k | 262027.18k | 264717.31k | 266376.53k|
|否 |aes-128-cbc |230932.81k | 258159.45k | 260335.87k | 265747.80k | 266283.69k|
肌肉機53在相同測試下的表現
|是否開啟|type |16 bytes | 64 bytes | 256 bytes | 1024 bytes |8192 bytes|
|———–|—————–|————-|—————|—————|——————-|—————|
|是 |aes-256-cbc |368562.35k |422608.32k |422655.83k |428560.38k | 432821.59k|
|否 |aes-256-cbc |163098.28k |199936.81k |201100.63k |203751.77k |204423.17k|
|是 |aes-128-cbc |490116.30k |588865.32k |541665.28k |592911.02k |601513.98k|
|否 |aes-128-cbc |225345.57k |273998.44k |280313.77k |284544.00k |285297.32k| Java對AES-NI是預設支援的嗎。(答案:是的,前提是這台機器的硬體支援)
重要文章解釋如何在Linux上Java開啟AES-NI
Hardware intrinsics were added to use Advanced Encryption Standard (AES). The UseAES and UseAESIntrinsics flags are available to enable the hardware-based AES intrinsics for Intel hardware. The hardware must be 2010 or newer Westmere hardware.
最重要的幾點:1.確認cpu支援 2. 和class的編譯無關,是運行時的一種技術 3.預設開啟的
//如果是開啟支援-XX:+UseAES -XX:+UseAESIntrinsics//如果是取消支援-XX:-UseAES -XX:-UseAESIntrinsics//查看是否已經開啟了jvm的AES-NI支援選項,結果顯示23已經開啟,工作筆記本未開(其他伺服器,包括北軟的也是開啟的);家裡的佔美機是開啟的$ java -XX:+PrintFlagsFinal -version | grep AES
AES-NI may only be available on the server VM. AESNI實測效果
準備對比:工作筆記本沒有AES-NI,但是cpu是i5-5200U,比53肌肉機伺服器至強(Intel(R) Xeon(R) CPU E5-2660 v4 @ 2.00GHz)頻率更高,如果同樣的class運行出來效果比工作筆記本好,說明是AES-NI起了作用;然後在伺服器上關閉AESNI試試
工作筆記本是2.2Ghz的cpu,頻率比伺服器的至強2.0Ghz還要高點,但是工作筆記本是沒有AESNI指令集的,加密AES一億次需要的時間要75秒,相反伺服器上同樣的代碼只要30秒
而且伺服器上也可以關閉AESNI指令集,時間也變為75秒。強烈的對比,開啟與否一倍的差距
[root@vm-yjy-36 blockchain]# java AESNITesterBegin ..End .. 耗時:30517[root@vm-yjy-36 blockchain]# java AESNITesterBegin ..End .. 耗時:29570[root@vm-yjy-36 blockchain]# java -XX:-UseAES -XX:-UseAESIntrinsics AESNITesterBegin ..End .. 耗時:78823[root@vm-yjy-36 blockchain]# java -XX:-UseAES -XX:-UseAESIntrinsics AESNITesterBegin ..End .. 耗時:75427
附:測試檔案的原始碼
import javax.crypto.*;import javax.crypto.spec.IvParameterSpec;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;public class AESNITester { private static final String PLAINTEXT = "ZZZLOVEXUXUANDHENRYZZZLOVEXUXUANDHENRY"; public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { long begintime = System.currentTimeMillis(); System.out.println("Begin .."); //1.產生隨機數 SecureRandom srandom = new SecureRandom(); //2.向量 byte[] iv = new byte[128/8]; srandom.nextBytes(iv); IvParameterSpec ivspec = new IvParameterSpec(iv); //3.密鑰 KeyGenerator kgen = KeyGenerator.getInstance("AES"); SecretKey skey = kgen.generateKey(); //4.初始化 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, skey, ivspec); //5.開始加密 for (int i=0; i<100000000; i++) { byte[] ciphered = cipher.doFinal(PLAINTEXT.getBytes()); } System.out.println("End .. 耗時:" + (System.currentTimeMillis() - begintime));// System.out.println("加密前長度:" + PLAINTEXT.length() + " 加密後長度:" + ciphered.length);// cipher.init(Cipher.DECRYPT_MODE, skey, ivspec);// byte[] recovered = cipher.doFinal(ciphered);// System.out.println("解密成功:" + new String(recovered)); }}
最終確認肌肉機上已經用上了AES-NI指令
驗證伺服器上用的已經使用了AESNI指令(見如下53機上對比測試,純加密時間也節約一半),但是從doFinal到整體,還是有很多工作的,比如密鑰初始化,向量初始化,隨機數產生,純加密提升100%,但是算上這些前期初始化工作,提升不到10%,也就是說純加密計算在整體密碼模組中運行也只佔一部分左右,這也是為什麼之前估計偏差
java -cp .:./ethereumj-core-1.5.0-SNAPSHOT-all.jar AESSpongyTesterEnd ..3694java -XX:-UseAES -XX:-UseAESIntrinsics -cp .:./ethereumj-core-1.5.0-SNAPSHOT-all.jar AESSpongyTesterEnd ..9513
注意:
1.編譯成整個jar包,所需要的類都在裡面了。javac時要加上這個jar為classpath
2.運行時classpath要進一步加上本地目錄(也就是這個孤零零的測試類別在的目錄)