全部產品
Search
文件中心

Key Management Service:使用密碼機執行個體叢集

更新時間:Aug 26, 2026

Data Encryption Service為您提供密碼機執行個體叢集功能,實現將處於同一地區不同可用性區域、用於相同業務的一組密碼機執行個體關聯起來,應用程式可以基於特定的輪詢演算法選取合適的密碼機,使用同一個密鑰執行密碼運算操作,為業務應用提供商務持續性、密碼計算的高可用性、負載平衡以及橫向擴充的能力。本文介紹如何使用密碼機執行個體叢集。

說明

如果您需要建立KMS硬體密鑰管理執行個體的密碼機叢集,請參見配置KMS硬體密鑰管理執行個體的密碼機叢集

叢集同步方式說明

叢集同步是將主密碼機的密鑰、配置的SSL認證以及使用者資訊等,同步到子密碼機。叢集同步方式與密碼機的購買時間有關:

  • 2025年01月09日及之後購買的密碼機:建立叢集後叢集同步方式預設為自動同步,主密碼機資料變更後您無需手動同步叢集資料。

  • 2025年01月09日之前購買的密碼機:建立叢集後資料同步方式預設為手動同步,即主密碼機資料變更後需要您手動執行同步叢集操作。如果您需要將叢集升級為自動同步,請聯絡我們

    警告

    升級後不支援回退,升級過程中可能存在以下風險,建議您在業務低峰期升級。

    • 配套使用阿里雲KMS硬體密鑰管理執行個體的使用者:

      • 管控類操作:升級時不支援建立密鑰、刪除密鑰等管控類操作,升級完成後自動回復。

      • 業務類操作:升級時加解密等業務類操作不受影響。

    • 其他使用者:需要您配合升級應用所依賴的密碼機SDK版本。

      • 管控類操作:升級時不支援建立密鑰、刪除密鑰等管控類操作,升級完成後自動回復。

      • 業務類操作:部分業務架構下,升級時可能存在業務中斷風險。

前提條件

  • 已購買密碼機。具體操作,請參見購買密碼機

  • 已購買Windows系統的ECS執行個體,且ECS執行個體需要和密碼機執行個體在同一VPC。具體操作,請參見Windows系統執行個體快速入門

    說明

    該ECS執行個體用於安裝密碼機管理工具,而非用於商務服務器。

步驟一:建立並啟用叢集

一個叢集包括一個主密碼機與若干個子密碼機,同一叢集內所有密碼機必須屬於同一VPC,可以屬於同一或不同子網。

說明

如果您購買GVSM(國密)配置了叢集資訊,HSM會根據您配置的叢集資訊自動建立叢集,請跳過本步驟。

  1. 啟用主密碼機執行個體

    1. 訪問Data Encryption Service控制台的虛擬密碼機執行個體頁面,在頂部功能表列,選擇目標地區。

    2. 虛擬密碼機執行個體頁面,定位到已建立的密碼機執行個體,單擊操作列的啟用

    3. 密碼機執行個體配置對話方塊,配置密碼機執行個體,然後單擊確定。配置成功後,密碼機執行個體的狀態變為已啟用

      配置項

      說明

      所屬的VPC網路ID

      選擇密碼機執行個體需要綁定的VPC。

      重要

      需要與您的ECS執行個體綁定的VPC是同一個。

      所屬的VPC子網

      選擇密碼機執行個體所屬的VPC子網網段。

      分配私網IP地址

      為密碼機執行個體分配一個私網IP地址。

      重要
      • 私網IP地址必須是所屬的VPC子網網段中的IP地址,否則配置將會失敗。

      • 末位為253、254、255的IP地址為系統保留地址,請勿使用。

      設定密碼機執行個體白名單

      設定訪問該密碼機執行個體的白名單。您可以輸入單個IP地址或網段地址,每行輸入1條資料,最多可以輸入10條資料。

      • 未設定白名單:所有IP地址都能訪問密碼機執行個體。

      • 設定了白名單:僅支援白名單內的訪問請求,不在白名單內的訪問請求將被拒絕。

      重要
      • 如果您建立了叢集並設定了叢集的白名單,那麼叢集的白名單優先順序高於叢集中密碼機執行個體的白名單。

        例如,叢集中密碼機執行個體的白名單為10.10.10.10,叢集的白名單為172.16.0.1,則您只能通過172.16.0.1訪問叢集中的密碼機執行個體。

      • 不支援配置為0.0.0.0/0(允許存取所有來源IP)。

        基於安全考慮,不推薦您允許存取所有來源IP。如果因臨時測試等原因確實需要允許存取所有來源IP,不配置白名單即可。

  2. 建立密碼機叢集

    1. 定位到主密碼機執行個體,單擊操作列的建立叢集

    2. 建立並啟用叢集面板,建立叢集資訊。

      配置項

      說明

      叢集名稱

      自訂叢集的名稱。名稱不能重複且長度不允許超過24個字元。

      設定叢集訪問白名單

      允許訪問叢集的IP地址。如果未設定白名單,則所有IP地址都能訪問叢集,如果設定了白名單,則不在白名單內的訪問請求將被拒絕。

      您可以輸入單個IP地址或網段地址,每行輸入1條資料,最多可以輸入10條資料。

      重要
      • 叢集的白名單優先順序高於叢集中密碼機執行個體的白名單。例如,您設定的叢集中密碼機執行個體的白名單為10.10.10.10,叢集的白名單為172.16.0.1,則您只能通過172.16.0.1訪問叢集中的密碼機執行個體。

      • 不支援配置為0.0.0.0/0(允許存取所有來源IP)。

        基於安全考慮,不推薦您允許存取所有來源IP。如果因臨時測試等原因確實需要允許存取所有來源IP,不配置白名單即可。

      指定叢集的交換器(2~4個)

      根據業務需要選擇可用性區域的交換器。

      在密碼機執行個體叢集中,您至少配置2個交換器才能成功建立並啟用叢集。

    3. 初始化密碼機執行個體,然後單擊下一步

      說明

      只有主密碼機狀態為已初始化時才能啟用叢集。

      初始化方式

      操作步驟

      方式一:在Data Encryption Service控制台一鍵初始化

      重要

      使用一鍵初始化,您的密碼機必須是通用密碼機GVSM且您沒有使用UKEY的需求。

      1. 建立並啟用叢集面板的最下方,單擊一鍵初始化主密碼機執行個體

      2. 初始化執行個體對話方塊,單擊確定

      初始化預計需要1~5分鐘時間,請耐心等待。初始化完成後,單擊已選主密碼機:後的update表徵圖,狀態會顯示已初始化,該狀態下請勿重複初始化。

      方式二:使用密碼機執行個體管理工具初始化

      重要

      密碼機用戶端管理工具只支援在Windows系統運行。

      建立並啟用叢集面板的最下方,單擊下載密碼機執行個體管理工具

      解壓擷取密碼機軟體包,參考密碼機軟體包中的使用者管理手冊的《原始初始化》章節,完成初始化操作。

    4. 根據頁面提示,添加子密碼機到叢集,然後單擊完成

(可選)步驟二:產生認證並配置TLS雙向認證

購買密碼機-HSM自動產生認證

僅GVSM(國密)支援在購買密碼機時選擇自動產生認證,此時HSM會自動產生認證,您只需在用戶端SDK側配置認證,HSM會自動在服務端加密機內部署認證。

  1. 在用戶端部署認證。

    請在控制台下載用戶端認證,並自行部署至您的用戶端。

    1. 請在密碼機詳情頁面,單擊擷取叢集認證。在下載的檔案夾中包含下列檔案:

      certs/
      ├── client.p12 (PKCS12格式用戶端認證,包含用戶端認證以及私密金鑰)
      ├── client.pem (PEM格式用戶端認證)
      ├── rootca.key (CA私密金鑰)
      ├── rootca.pem (PEM格式CA認證)
      ├── server.p12 (PKCS12格式服務端認證)
      └── passphrase (PKCS12格式認證(尾碼為.p12)的認證保護口令)
    2. 請將client.p12、rootca.pem部署至用戶端,同時用戶端設定檔中需要配置client.p12、rootca.pem的檔案路徑以及passphrase值。詳細介紹,請參見控制台下載的軟體包中的參考文檔。

  2. 在服務端部署認證。

    HSM會自動將認證部署至密碼機,您無需關注。

重要

認證的有效期間預設為10年,到期前HSM會自動產生認證並輪轉服務端認證,建議您不要使用密碼機管理工具建立UKEY管理員,建立UKEY管理員會導致認證輪轉失敗。

購買密碼機-HSM不自動產生認證

GVSM(國密)支援由HSM自動產生認證,但如果您在購買時未配置自動產生認證,參考如下步驟產生並部署認證。

  1. 產生認證。

    1. 下載認證檔案產生工具(dkms_cert_tool)

    2. 將下載的檔案解壓後,運行認證檔案產生工具產生CA認證、用戶端認證和服務端認證。

      說明
      • 工具的運行環境沒有限制,可以是本機電腦、ECS執行個體或其他滿足工具運行條件的環境。

      • 工具僅為阿里雲提供的輔助性工具,如果您有相關技術能力可以自己產生這些認證檔案,則無需使用本工具。

      Windows系統

      • 方式一:在Windows檔案夾,雙擊滑鼠左鍵運行hsm_certificate_generate.exe檔案,在certs檔案夾擷取認證檔案。

        說明

        該方式產生的PKCS12格式認證檔案(尾碼為.p12)和CA私密金鑰檔案(尾碼為.key)的口令為預設值12345678,如果您需要指定口令,請使用方式二。

      • 方式二:切換到Windows檔案夾所在路徑,然後運行以下命令,在certs檔案夾擷取認證檔案。

        ./hsm_certificate_generate -dir ./certs -pswd 12345678

        -dir用於指定產生認證檔案的儲存路徑,-pswd用於指定產生的PKCS12格式認證檔案(尾碼為.p12)和CA私密金鑰檔案(尾碼為.key)的口令。

      Linux系統

      切換到Linux檔案夾所在路徑,然後運行以下命令,在certs檔案夾擷取認證檔案。

      ./hsm_certificate_generate -dir ./certs -pswd 12345678

      -dir用於指定產生認證檔案的儲存路徑,-pswd用於指定產生的PKCS12格式認證檔案(尾碼為.p12)和CA私密金鑰檔案(尾碼為.key)的口令。

      macOS系統

      切換到darwin檔案夾所在路徑,然後運行以下命令,在certs檔案夾擷取認證檔案。

      ./hsm_certificate_generate -dir ./certs -pswd 12345678

      -dir用於指定產生認證檔案的儲存路徑,-pswd用於指定產生的PKCS12格式認證檔案(尾碼為.p12)和CA私密金鑰檔案(尾碼為.key)的口令。

      運行成功後,將在certs檔案夾中產生下列檔案:

      certs/
      ├── client.p12 (PKCS12格式用戶端認證,包含用戶端認證以及私密金鑰)
      ├── client.pem (PEM格式用戶端認證)
      ├── rootca.key (CA私密金鑰)
      ├── rootca.pem (PEM格式CA認證)
      ├── server.p12 (PKCS12格式服務端認證)
      └── server.pem (PEM格式服務端認證)
  2. 在用戶端部署認證。

    請將client.p12、rootca.pem部署至用戶端,同時用戶端設定檔中需要配置client.p12、rootca.pem的檔案路徑以及您產生認證時輸入的口令。詳細介紹,請參見控制台下載的軟體包中的參考文檔。

  3. 在服務端部署認證。

    1. 在ECS執行個體上安裝密碼機執行個體管理工具。

      重要

      密碼機執行個體管理工具只支援在Windows系統運行。

      1. 單擊主密碼機執行個體的規格列的image表徵圖,下載密碼機執行個體管理工具。

      2. 解壓擷取到的密碼機軟體包,找到PKIManager-X.X.X.X.exe然後上傳到ECS執行個體上。具體操作,請參見使用遠端桌面或Windows APP向Windows執行個體傳輸檔案

    2. 使用密碼機執行個體管理工具配置主密碼機。

      1. 在ECS執行個體上使用密碼機執行個體管理工具串連主密碼機GVSM。

        1. 雙擊PKIManager-X.X.X.X.exe開啟密碼機執行個體管理工具,選擇系統>TCP/IP串連

        2. TCP/IP串連對話方塊,輸入主密碼機的IP地址連接埠號碼(固定為8020)。

          IP地址請在控制台此處查看。主密碼機的IP地址可在密碼機執行個體列表的IP地址列中擷取,對應叢集列顯示為主密碼機的執行個體。

        3. 單擊串連,在彈出的PKIManager對話方塊單擊確定,然後單擊登入

          說明

          登入成功後,建議您註冊管理員帳號,使用管理員帳號登入以獲得更高的安全性。具體操作,請參見隨密碼機執行個體管理工具下載的GVSM使用者管理手冊中的2.1.3. 註冊管理員2.1.2. 管理員登入

      2. 使用密碼機執行個體管理工具完成如下配置。

        配置項

        操作步驟

        配置用戶端認證(client.pem

        1. 選擇密鑰管理>用戶端管理

        2. 用戶端認證管理對話方塊,單擊匯入認證

        3. 匯入認證對話方塊,認證類型選擇國際TLS用戶端RSA認證[pem],然後選擇認證檔案產生工具產生的用戶端認證(client.pem),單擊匯入

        佈建服務端認證(server.p12

        1. 選擇執行個體監控資訊>服務端管理

        2. 服務端p12認證管理對話方塊,單擊匯入認證

        3. 匯入認證對話方塊,認證類型選擇國際TLS服務端RSA認證[p12],然後選擇認證檔案產生工具產生的服務端認證(server.p12),輸入認證口令(即您在產生認證檔案時設定的口令,如果您未設定,預設為12345678)。

        4. 單擊匯入

        配置主密碼機GVSM裝置連接埠屬性

        1. 選擇

        2. 主機連接埠屬性對話方塊,配置以下參數:

          • Socket KeepAlive時間:60。

          • 訊息報文頭長度:0。

          • 訊息報文編碼格式:ASCII。

          • 主機服務通訊方式:雙向通訊。

          • 主機服務通訊協議:TLSv1.2。

        3. 單擊重設

        4. 單擊立即重啟,然後單擊確定

步驟三:同步叢集資料

  • 叢集類型手動同步叢集時:第一次建立並啟用叢集後或者主密碼機資料變更後,都需要執行同步叢集操作,擴充叢集時無需同步叢集。

  • 叢集類型自動同步叢集時:無需同步叢集,主密碼機新建立的密鑰、配置的SSL認證以及使用者資訊等,都會自動同步到子密碼機上。

警告

同步叢集預計需要5分鐘,請在業務空閑期進行同步,以免影響業務運行。

  1. 虛擬密碼機執行個體頁面,找到目標主密碼機執行個體,在執行個體列表的叢集類型列查看同步類型(手動同步叢集/自動同步叢集)。

    當叢集類型為手動同步叢集時,執行同步叢集操作。

  2. 操作列單擊同步叢集,在彈出的對話方塊中,再次單擊同步叢集

步驟四:建立密鑰並使用密鑰加解密

在密碼機軟體包中找到密碼機的開發手冊、SDK測試程式等,您可以參考開發手冊,調用API介面使用密碼機執行個體。

說明

您可以在Data Encryption Service控制台的虛擬密碼機執行個體頁面,單擊目標密碼機執行個體的規格列,下載密碼機執行個體管理工具 ,解壓後即得到密碼機軟體包。

以通用密碼機GVSM為例,在解壓後的阿里雲Data Encryption ServiceGVSM軟體包>SDK>JAVA>伺服器密碼機介面資料>測試demo目錄中找到測試案例APITest.java,使用該測試案例來測試密碼機執行個體。程式碼範例如下:

說明

您需要將用例中的IP地址(192.168.XX.XX)修改為密碼機執行個體分配的私網IP地址。

package cn.tass.hsm;

import cn.tass.SJJ1507.devices.RasKeyUtils;
import cn.tass.common.kits.Padding;
import cn.tass.exceptions.TAException;
import cn.tass.hsm.GHSMAPI;
import cn.tass.kits.Forms;
import cn.tass.hsm.Host;
import cn.tass.hsm.LogConfig;
import cn.tass.util.encoders.Base64;
import org.junit.Test;

import javax.naming.ConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class APITest {
    LogConfig logConfig = new LogConfig("error", "./");
    Host host1 = new Host("GHSM", -3, "192.168.XX.XX", 8019, 5);
    List<Host> hosts = new ArrayList<Host>() {{
        add(host1);
    }};

    String config =
            "{"
                    + "[LOGGER];"
                    + "logsw=debug,error;logPath=./;"
                    + "[HOST 1];"
                    + "hsmModel=GHSM;"
                    + "host=192.168.XX.XX;linkNum=-3;"
                    + "port=8019;"
                    + "timeout=5;"
                    + "}";

//    GHSMAPI api = GHSMAPI.getInstance(hosts, logConfig);
    GHSMAPI api = GHSMAPI.getInstance(config);

    /**
     * LMK加密的對稱金鑰
     */
    byte[] symmetricKey = Forms.hexStringToByteArray("669C1CEDDA****5D727EA727558B5");
    byte[] verifyValue = Forms.hexStringToByteArray("BD85****4D88");

    byte[] symmetricKey1 = Forms.hexStringToByteArray("93EF12C958****C3EFDBC7B37642D");
    byte[] verifyValue1 = Forms.hexStringToByteArray("7830****B8E6");
    /**
     * LMK加密的工作階段金鑰密文
     */
    byte[] symmetricKeyKEK = Forms.hexStringToByteArray("2E80A42018****CF639F644629E8");
    /**
     * 工作階段金鑰的校正值
     */
    byte[] verifyValueMAC = Forms.hexStringToByteArray("734D****3E38");
    /**
     * 保護密鑰保護的密文
     */
    byte[] protectionKey = Forms.hexStringToByteArray("2EACE685C5EB2638D120*****CD44210B43C894A77C");
    /**
     * 保護密鑰保護的密文的MAC
     */
    byte[] protectionMAC = Forms.hexStringToByteArray("0CB8****E487");

    /**
     * RSA DER編碼的公開金鑰
     */
    byte[] publicKeyRSA = Forms.hexStringToByteArray("308186028180E14CAAFFCEC6D014457D7CA3E********1299BDBC17690C8E70F7BFA10EA02450805DA4C6CDC38BFBF1349C95B81A88177BA31C08")
     * RSA LMK加密的私密金鑰
     */
    byte[] privateKeyRSA = Forms.hexStringToByteArray("00202703D0652C7027B7D94B45A896646A9*********1B3CC00E37BE933055D5C00E37BE933055D54718ADDAA677519BD9C054CA249B43888")
    /**
     * RSA 保護祕密金鑰加密的私密金鑰
     */
    byte[] privateKeyRSAKEK = Forms.hexStringToByteArray("6B2FB2BCC75604ABF5761FFA1027FF16324*********63AD3B57BD89059D5799974B4E5E9453763D94E682C629C4617C4E5393E9DDBFB")
    /**
     * RSA MAC
     */
    byte[] privateKeyRSAKEKMAC = Forms.hexStringToByteArray("701A****9760");

    /**
     * KEK 加密的RSA私密金鑰
     */
    byte[] privateKeyKEK = Forms.hexStringToByteArray("7A833CC0FAFBA6EC063DF4827B8FD91FF4B9A69F********1E02C312ABFC68F454D11EFCF1E0609584D06B09A08599D7A0BF5D63BB9F");
    /**
     * KEK RSA 私密金鑰MAC
     */
    byte[] privateKeyRSAMAC = Forms.hexStringToByteArray("06E5****36DE");

    /**
     * KEK 加密的SM2私密金鑰
     */
    byte[] privateKeySM2KEK = Forms.hexStringToByteArray("D3C5F579038C8BF34698****EF6044210B43C894A77C");
    /**
     * KEK SM2 私密金鑰MAC
     */
    byte[] privateKeySM2MAC = Forms.hexStringToByteArray("83E4****0D15");


    /**
     * SM2 der編碼的公開金鑰
     */
    byte[] privateKeySM2DER = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF55********42A53790967A1368B7084F6EFED51FC848D1E3B5370A99BDCB64D17C2F");
    /**
     * SM2 lmk加密的私密金鑰
     */
    byte[] privateKeySM2 = Forms.hexStringToByteArray("66C9DDB0D6400EE05947****21908C4F5CA6457B435F");
    /**
     * SM2 保護密鑰保護的私密金鑰
     */
    byte[] privateKeyKEKSM2 = Forms.hexStringToByteArray("D3C5F579038C8BF3A162****F99644210B43C894A77C");
    /**
     * SM2 MAC
     */
    byte[] privateKeyKEKSM2MAC = Forms.hexStringToByteArray("B982****8232");

    /**
     * 隨機產生的sm2密鑰 1002
     */
    byte[] publicSM2 = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF55********6913D902C4C9B8A84A3F96ADDD7BEF537D61404D56E58A68C756AEFD40");
    byte[] privateSM2 = Forms.hexStringToByteArray("6F26783DCE6D45B84D3F****2FA68D1A3B721C09BB28");

    /**
     * MD5 演算法算出的資料摘要
     */
    byte[] md5 = Forms.hexStringToByte("D41D8CD98F00B204E9800998ECF8427E");
    /**
     * SM3 演算法算出的資料摘要
     */
    byte[] sm3 = Forms.hexStringToByte("E559D3DE421E81967DD68B28B55E0C26B03FCE10B8A8E5C4E6067497729D40D3");

    /**
     *
     */
    byte[] b = Forms.hexStringToByteArray("00000000000000000000000000000000");

    public APITest() throws TAException, ConfigurationException {
    }


    /**
     * 產生對稱金鑰
     *
     * @throws TAException
     */
    @Test
    public void genSymmKey() throws TAException {
        ArrayList<byte[]> bytes = api.genSymmKey(3);
        System.out.println("LMK加密的對稱金鑰:"  + Forms.byteToHexString(bytes.get(0)));
        System.out.println("對稱金鑰的校正值:"  + Forms.byteToHexString(bytes.get(1)));

    }

    ///////////////////////////////////////////////////////////////////////////
    // 1015 測試資料
    ///////////////////////////////////////////////////////////////////////////

    byte[] sm4Key = Forms.hexStringToByte("EE828FCCFA****468B1FECCE81192");
    byte[] sm4CV = Forms.hexStringToByte("BCC2****2764");

    byte[] sm4ProKeyCipher = Forms.hexStringToByte("7C78B0D533****E9277504181C23F");
    byte[] sm4ProKeyCipherCV = Forms.hexStringToByte("8849****FB73");

    byte[] newSM4 = Forms.hexStringToByte("AE62E4E90F****AECE0AC9923B885");
    byte[] newSM4KeyMAC = Forms.hexStringToByte("F7EBEA9FD3****4E7EAAC9B7BE362");
    byte[] newSM4KeyTag = Forms.hexStringToByte("7C05A01A54****E0C8597DBED6D6D");

    byte[] sm4Key2 = Forms.hexStringToByte("40F7B1FA35****EB13491B119A4AB");
    byte[] sm4Key2CV = Forms.hexStringToByte("955C****9C51");

    /**
     * 產生對稱金鑰,保護密鑰保護輸出
     *
     * @throws TAException
     */
    @Test
    public void generateProtectionKey() throws TAException {
        /**
         * sm4
         * LMK加密的對稱金鑰:B36847D6E8****4EEB65558A2626C
         * 對稱金鑰的校正值:713C****2AAB
         */
        ArrayList<byte[]> bytes = api.proGenSymmKey(Forms.hexStringToByteArray("B36847D6E8****4EEB65558A2626C"),
                TACryptConst.KEY_ALG_SM4, Forms.hexStringToByteArray("713C****2AAB"), TACryptConst.KEY_ALG_SM4, b,
                TACryptConst.ENC_MODE_GCM,b, b);
        System.out.println("LMK加密的工作階段金鑰密文:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("工作階段金鑰的校正值:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("保護祕密金鑰加密的工作階段金鑰密文:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("工作階段金鑰的MAC值:" + Forms.byteToHexString(bytes.get(3)));
        System.out.println("tags:" + Forms.byteToHexString(bytes.get(4)));

    }

    /**
     * 對稱金鑰加解密資料
     *
     * @throws TAException
     */
    @Test
    public void generalDataEnc() throws TAException {
//        byte[] bytes = api.symmKeyDataEnc(sm4Key,TACryptConst.ENC_MODE_ECB,TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_SM4,
//                "0000000000000000".getBytes(), b);
//        System.out.println("SM4加密結果:" + Forms.byteToHexString(bytes));
//        byte[] bytes1 = api.generalDataDec(sm4Key,TACryptConst.ENC_MODE_ECB, TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_SM4, bytes, b);
//        System.out.println("SM4解密結果:" + new String(bytes1));
//        byte[] paddingData = Padding.PKCS5Padding(Forms.hexStringToByte("30820122300D06092A864886F70D010101050003********FE2D80A275BF5D096D2E07BA9ED5A75A10D425B03B84BB57990203010001"), 16);
//        byte[] bytes = api.symmKeyDataEnc(28,TACryptConst.ENC_MODE_CBC,TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_AES128,
//                paddingData, b);
//        System.out.println("AES加密結果:" + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.generalDataDec(Forms.hexStringToByte("789F01F9CC****429D7EAB215ABA1"),TACryptConst.ENC_MODE_CBC, TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_AES128,
                Forms.hexStringToByte("AE6BA9133D0D4BB0090882E33F03D905D7797852********B1C0079352310E974EB1155A759374004095E2256B0ADC3BFFFF150AF071"), b);
        System.out.println("AES解密結果:" + Forms.byteToHexString(bytes1));
    }




    /**
     * 對稱金鑰(受保護密鑰保護)加解密資料
     *
     * @throws TAException
     */
    @Test
    public void protectionKeyEncrypt() throws TAException {
        ArrayList<byte[]> bytes = api.proKeyEncData(sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV,
                Forms.hexStringToByte("C0C64CD82E3B2DC8C8F4****F5BA4F0BCF7AC04E08E8"),
                b, Forms.hexStringToByte("75F2C068A5****F0BCF7AC04E08E8"), TACryptConst.ENC_MODE_CBC,
                b, new byte[0], new byte[0], TACryptConst.KEY_ALG_AES256, 1, 3,
                new byte[16], TACryptConst.KEY_ALG_SM4, TACryptConst.ENC_MODE_GCM,
                "mingwenshuju".getBytes(), new byte[12], new byte[2]);
        System.out.println("密文: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("tag: " + Forms.byteToHexString(bytes.get(1)));

        byte[] bytes1 = api.proKeyDecData(sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV, Forms.hexStringToByte("C0C64CD82E3B2DC8C8F4****F5BA4F0BCF7AC04E08E8"), b, Forms.hexStringToByte("75F2C068A5****F0BCF7AC04E08E8"), TACryptConst.ENC_MODE_CBC,
                b, new byte[0], new byte[0], TACryptConst.KEY_ALG_AES256, 1, 3, new byte[16], TACryptConst.KEY_ALG_SM4, TACryptConst.ENC_MODE_GCM,
                bytes.get(0), new byte[12], new byte[2], bytes.get(1));

        System.out.println("解密後的資料明文:" + new String(bytes1));
    }

    byte[] srcRSACipher = Forms.hexStringToByte("83E265207D4566C7704DF9E6170181378CA028FB********508F919F4C0B3F2F7C0B79E661001B79FB0F0205A97CECFBE25DC4C711EA");

    byte[] srcRSACipherMAC = Forms.hexStringToByte("948D994479****72E54468349B3E5");

    byte[] srcRSACipherTag = Forms.hexStringToByte("9C8A7CB4C6****75F0681ED497EDF");

    byte[] srcRSApublicKey = Forms.hexStringToByteArray("308186028180E14CAAFFCEC6D014457D7CA3E943********BE8B795E10474954FE01BAAC63532520069465FA62EDB266AADEBB020103");
    /**
     * RSA LMK加密的私密金鑰
     */
    byte[] srcRSAprivateKey = Forms.hexStringToByteArray("000202703D0652C7027B7D94B45A896646A9DC7C********571BC7CE29B67920538D509C58B1D8F966AF7E5321CDB2386164844D2BCB");


    byte[] srcSM2Cipher = Forms.hexStringToByte("83E260209C09CEF21E1A****0B8D670537112DFB030F");

    byte[] srcSM2CipherMAC = Forms.hexStringToByte("7DF725131F****F029550F2F073E9");

    byte[] srcSM2CipherTag = Forms.hexStringToByte("A2181C5822****E37C072987D1B7E");

    byte[] srcSM2publicKey = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF55********F8D3F9E5A31C7DE80940637E036B2D6FD36A0F586D4CDC3A610A269E89");

    byte[] srcSM2privateKey = Forms.hexStringToByteArray("79E62264C314D1D3279D****F2BC777F8CBE7EC55699");


    /**
     * 巨量資料包加解密
     */
    @Test
    public void bigDataEnc() throws TAException {
        byte[] enc = api.bigDataEnc(Forms.hexStringToByteArray("6DF7292D86****81F7C94DDC967A0"), "AES/ECB/PKCS5Padding", "demaxiyazhili".getBytes(), new byte[0]);
        System.out.println(Forms.byteToHexString(enc));
        byte[] dec = api.bigDataDec(Forms.hexStringToByteArray("6DF7292D86****81F7C94DDC967A0"), "AES/ECB/PKCS5Padding", enc, new byte[0]);
        System.out.println(new String(dec));

    }

    /**
     * 計算MAC、校正Mac
     */
    @Test
    public void mac() throws TAException {
        byte[] bytes = api.calMac(1, 0, 2, sm4Key, 7, "1111111111111111".getBytes(),
                new byte[16]);
        System.out.println("計算MAC結果:" + Forms.byteToHexString(bytes));
        boolean b = api.verifyMAC(1, 0, 2, sm4Key, 7, "1111111111111111".getBytes(),
                new byte[16], bytes);
        System.out.println("校正MAC結果:" + b);
    }

    /**
     * 計算HMAC
     */
    @Test
    public void hmac() throws TAException {
        ArrayList<byte[]> hmac = api.hmac(20, 0, 2, sm4Key, new byte[0], "shuyaojisuandeshuju".getBytes());
        for (int i = 0; i < hmac.size(); i++) {
            System.out.println(Forms.byteToHexString(hmac.get(i)));
        }
    }

    /**
     * 產生RSA演算法金鑰組,私密金鑰由LMK加密輸出
     */
    @Test
    public void generateRSAKeyPair() throws TAException, IOException {
        ArrayList<byte[]> bytes = api.genRSAKey(2048, 65537);

        System.out.println("DER編碼的公開金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("LMK加密的私密金鑰:" + Forms.byteToHexString(bytes.get(1)));
    }


    /**
     * 產生RSA金鑰組,保護祕密金鑰加密輸出
     */
    @Test
    public void protectionKeyRSA() throws TAException, IOException {
        ArrayList<byte[]> bytes = api.proGenRSAKey (sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV, 2048, 3,
                b, TACryptConst.ENC_MODE_ECB, b, new byte[2]);
        System.out.println("DER編碼的公開金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("LMK加密的私密金鑰:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("保護祕密金鑰加密私密金鑰的密文:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("非對稱私密金鑰MAC的長度:" + Forms.byteToHexString(bytes.get(3)));
    }

    /**
     * RSA 私密金鑰簽名 驗簽
     */
    byte[] privateRSA = Forms.hexStringToByte("000204B07672172F114E8E847A5FB9EC3DD32CD1********AE837EB0B233D98470234F3EAD29C2DAB368CF5463151BCB266DEF496D8E");
    byte[] publicRSA = Forms.hexStringToByte("3082010902820100EED2CF3C2E3624D65718E0F1********556D927F5DA9529C22D5C701B8B1BB7836D351A815A69116110203010001");
    byte[] publicR77 = Forms.hexStringToByte("3082010A0282010100A636C484374F9F039EB431********FE2D80A275BF5D096D2E07BA9ED5A75A10D425B03B84BB57990203010001");
    @Test
    public void RSApriSign() throws TAException, IOException {
        byte[] bytes = api.RSAPriKeySign(privateRSA,TACryptConst.PADDING_MODE_NO, 4, 0,
                0, 0, Forms.hexStringToByte("9ECA5459BA0B5CA0****55E9DC2B6FFA85CE"));
        System.out.println("簽名結果:" + Forms.byteToHexString(bytes));
        boolean b = api.RSAPubVerify(publicRSA,TACryptConst.PADDING_MODE_PKCS15, TACryptConst.DIGEST_ALG_SHA256, 0,
                0, 0, bytes, Forms.hexStringToByte("9ECA5459BA0B5CA0****55E9DC2B6FFA85CE"));
        System.out.println("驗簽結果:" + b);
//        ArrayList<byte[]> bytes1 = RasKeyUtils.loadDerRsaPublicKey(publicR77);
//        for (int i = 0; i < bytes1.size(); i++) {
//            System.out.println(Forms.byteToHexString(bytes1.get(i)));
//        }
//
//        byte[] bytes = api.RSAPriKeySign(77,TACryptConst.PADDING_MODE_PSS, TACryptConst.DIGEST_ALG_SHA256, TACryptConst.MGF,
//                TACryptConst.DIGEST_ALG_SHA256, 10, "1234567890".getBytes());
//        System.out.println("簽名結果:" + Forms.byteToHexString(bytes));
//        boolean b = api.RSAPubVerify(publicR77,TACryptConst.PADDING_MODE_PSS, TACryptConst.DIGEST_ALG_SHA256, TACryptConst.MGF,
//                TACryptConst.DIGEST_ALG_SHA256, 10, bytes, "1234567890".getBytes());
//        System.out.println("驗簽結果:" + b);
    }

    /**
     * RSA加解密運算
     */
    @Test
    public void RSAencdata() throws TAException {
        byte[] bytes = api.RSAPubEncData(11, 1, TACryptConst.DIGEST_ALG_SHA256, new byte[0], Forms.hexStringToByte("{createTime=1606380202000, createUserId=144, ip=124.204.XX.XX, key=SYJHD202011266020179058, orderNumber=SYJHD202011266020179058, productId=161391, scene=SYJHD}"));
        System.out.println("公開金鑰加密結果:" + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.RSAPriDecData(11, 1, TACryptConst.DIGEST_ALG_SHA256,new byte[0], bytes);
        System.out.println("私密金鑰解密結果:" + Forms.byteToHexString(bytes1));
    }

    /**
     * RSA私密金鑰解密,私密金鑰受保護密鑰保護
     */
    @Test
    public void priDecryptRSA() throws TAException {
        byte[] bytes = api.proRSAPriKeyDec (sm4Key, TACryptConst.KEY_ALG_SM4 , sm4CV, srcRSACipher, b, srcRSACipherMAC, TACryptConst.DIGEST_ALG_SHA256,
                b, new byte[2], srcRSACipherTag, 2, TACryptConst.MGF, TACryptConst.DIGEST_ALG_SHA256,new byte[0], Forms.hexStringToByteArray("BFA03DB9BD0A4DE4809B59B04BF663E8E541B0CF********5FD9E0A80116771AC436ED1EDE46CF272FD1DD4D3A5174D2D178D9A21F3D"));
        System.out.println("解密後的明文資料:" + Forms.byteToHexString(bytes));
    }

    /**
     * RSA私密金鑰簽名,私密金鑰受保護密鑰保護
     */
    @Test
    public void privateSignRSA() throws TAException, IOException {
        byte[] bytes = api.proRSAPriKeyDecSign(sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV, srcRSACipher, b, srcRSACipherMAC, TACryptConst.DIGEST_ALG_SHA256,
                b, new byte[2], srcRSACipherTag, TACryptConst.DIGEST_ALG_SHA256, "1234567890".getBytes(), TACryptConst.PADDING_MODE_PSS, TACryptConst.MGF, TACryptConst.DIGEST_ALG_SHA256, 10);

        System.out.println("簽名結果:" + Forms.byteToHexString(bytes));
        boolean b = api.RSAPubVerify(srcRSApublicKey,TACryptConst.PADDING_MODE_PSS, TACryptConst.DIGEST_ALG_SHA256, TACryptConst.MGF, TACryptConst.DIGEST_ALG_SHA256, 10, bytes, "1234567890".getBytes());
        System.out.println("驗簽結果:" + b);
    }

    /**
     * RSA非對稱金鑰轉加密,由保護密鑰1轉為保護密鑰2加密
     */
    @Test
    public void RSAConversionEncryption() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_SM4, sm4Key, sm4CV, TACryptConst.KEY_TYPE_RSA,
                -1, srcRSACipher, b, srcRSACipherMAC, TACryptConst.ENC_MODE_GCM, b, new byte[2], srcRSACipherTag,
                0,
                TACryptConst.KEY_ALG_SM4, sm4Key2, sm4Key2CV, b, TACryptConst.ENC_MODE_ECB, b, new byte[2]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("第" + i + "個===" + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * RSA非對稱金鑰保護匯入對稱金鑰
     */
    @Test
    public void tets1() throws TAException {
        ArrayList<byte[]> bytes = api.RSAProImplSymm(srcRSAprivateKey, 2, TACryptConst.DIGEST_ALG_SHA256, new byte[10], 200,
                TACryptConst.KEY_ALG_SM4, Forms.hexStringToByteArray("5C59EBCD0A48E51038853E490C76AD83122964E3********AD4FCF0A1D20DC5A0AAB878DADC04903CCE5B3D06219FDB4497905FBEA9E"), "916-zjl".getBytes());
        System.out.println("LMK加密的對稱金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("對稱金鑰的校正值:" + Forms.byteToHexString(bytes.get(1)));
    }

    /* ***************************************************************************************************** */

    /**
     * 產生SM2/ECC金鑰組,保護祕密金鑰加密輸出
     */
    @Test
    public void generateProtectionKeySM2() throws TAException {
        ArrayList<byte[]> bytes = api.proGenSM2OrECCKey (sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV, 0x0007,
                b, TACryptConst.ENC_MODE_GCM, b, new byte[16]);
        System.out.println("DER編碼的公開金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("LMK加密的私密金鑰:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("保護祕密金鑰加密私密金鑰的密文:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("非對稱私密金鑰MAC:" + Forms.byteToHexString(bytes.get(3)));
        System.out.println("tags:" + Forms.byteToHexString(bytes.get(4)));

    }

    /**
     * 產生SM2演算法金鑰組,私密金鑰由LMK加密輸出
     */
    @Test
    public void generateSM2Key() throws TAException {
        ArrayList<byte[]> bytes = api.genSM2Key();
        System.out.println("DER編碼的公開金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("LMK加密的私密金鑰:" + Forms.byteToHexString(bytes.get(1)));
    }

    /**
     * 產生ECC演算法金鑰組,私密金鑰由LMK加密輸出
     */
    @Test
    public void generateECCKey() throws TAException {
        ArrayList<byte[]> bytes = api.genECCKey(0x0007);
        System.out.println("DER編碼的公開金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("LMK加密的私密金鑰:" + Forms.byteToHexString(bytes.get(1)));
 
    }

    byte[] data = Forms.hexStringToByte("20D90A83A4654FB8****0371B374F76DEFA5");

    /**
     * ECC 簽名驗簽
     */
    @Test
    public void ECCPrivateKeySign() throws TAException {

        byte[] bytes = api.priKeySign(0x0007, Forms.hexStringToByteArray("61971383CD4D760CF77C****4C1C935F18B4CCCFBF3A"), data);
        System.out.println("ECC簽名結果:" + Forms.byteToHexString(bytes));

        boolean b = api.pubKeyVerify(0x0007, Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF55********1ACA51CB99CD452FA11B5B6BBB4AA31C2DBCC696FC57C8F9F8F01948FE"), data, bytes);
        System.out.println("ECC驗簽結果:" + b);
    }

    /**
     * SM2 簽名 驗簽
     */
    @Test
    public void TestSm2() throws TAException {
        byte[] bytes = api.priKeySign(0x0007, privateKeySM2, sm3);
        System.out.println("簽名結果:" + Forms.byteToHexString(bytes));
        boolean b = api.pubKeyVerify(0x0007, privateKeySM2DER, sm3, bytes);
        System.out.println("驗簽結果:" +  b);
    }


    @Test
    public void SM2Sign() throws TAException {
        byte[] baInData = "2222222222222222".getBytes();
        //7.計算SM3摘要
        System.out.println("資料摘要:SM3");
        String sAlg = "SM3";
        byte[] baUserId = new byte[0];
        byte[] baPubKey = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF55********9A1AD40BEEE37267F8F1F97E67BCE29A4E1CCAB0979A1E85F81010E042");
        byte[] baHashInitRes = api.HashInit(sAlg, baUserId, baPubKey);
        byte[] baHashUpdateRes = api.HashUpdate(baHashInitRes, baInData);
        byte[] baHashSm3 = api.HashFinalize(baHashUpdateRes);
        System.out.println(String.format("資料摘要: %s", Forms.byteToHexString(baHashSm3)));


        //8.非對稱金鑰簽名驗簽
        System.out.println("資料非對稱簽名驗簽:SM2");

        int iCurveId = 0x0007;
        System.out.println(String.format("資料原文(雜湊值): %s", Forms.byteToHexString(baHashSm3)));

        byte[] baSignatureSm2 = api.priKeySign(iCurveId, 2, baHashSm3);
        System.out.println(String.format("資料簽名: %s", Forms.byteToHexString(baSignatureSm2)));
        boolean blVerifyResSm2 = api.pubKeyVerify(iCurveId, baPubKey, baHashSm3, baSignatureSm2);
        System.out.println(blVerifyResSm2);
    }


    byte[] sm2 = Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF55********55A4C790CDE94A1B179CC12A39A856755F6677E87905BD903987425AF3");

    byte[] sm2PrivateKey = Forms.hexStringToByte("4F23C664B68C8A38B31F****66976CEA234A749F031D");

    /**
     * SM2加密解密運算
     */
    @Test
    public void TestSM2EncAndDec() throws TAException {
        byte[] bytes = api.SM2PubKeyEnc(888, Forms.hexStringToByte("1111111111****111111111111111"));
        System.out.println("加密結果:" + Forms.byteToHexString(bytes));

        byte[] bytes1 = api.SM2PriKeyDec(888, bytes);
        System.out.println("解密結果:" + Forms.byteToHexString(bytes1));
    }



    byte[] sm2Key = Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF55********55A4C790CDE94A1B179CC12A39A856755F6677E87905BD903987425AF3");
    byte[] sm2Cipher = Forms.hexStringToByte("83E260209C09CC3F0103****FD8880E68AC28BFFF0F3");
    byte[] sm2CipherMAC = Forms.hexStringToByte("8184BE3669****B673814E59E7700");
    byte[] sm2CipherTag = Forms.hexStringToByte("8FD638CA4D****213F5777253D192");
    byte[] sm2PriKey = Forms.hexStringToByte("4F23C664B68C8A38B31F****66976CEA234A749F031D");


    /**
     * ECC/SM2私密金鑰解密,私密金鑰受保護密鑰保護
     */
    @Test
    public void protectionPrivateKeyDecrypt() throws TAException {
        byte[] bytes = api.proPriKeyDec(sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV, sm2Cipher, b, sm2CipherMAC, TACryptConst.ENC_MODE_GCM,
                b, new byte[2], sm2CipherTag, Forms.hexStringToByteArray("E9C17D82604F992BB3AB8FE0F766441DACC05EB7********32FACEC8316B880499E6E70260333E9F29CEBCF3F8E10C151F79445276F6"));
        System.out.println("解密後的資料明文:" + Forms.byteToHexString(bytes));
    }

    /**
     * ECC/SM2私密金鑰簽名,私密金鑰受保護密鑰保護
     */
    @Test
    public void privateSignSM2() throws TAException {
        byte[] bytes = api.proPriKeySign(sm4Key,TACryptConst.KEY_ALG_SM4 , sm4CV, sm2Cipher, b, sm2CipherMAC, TACryptConst.ENC_MODE_GCM,
                b, new byte[2], sm2CipherTag, Forms.hexStringToByteArray("20D90A83A4654FB8****0371B374F76DEFA5"));
        System.out.println("ECC/SM2私密金鑰簽名結果(私密金鑰受保護密鑰保護):" + Forms.byteToHexString(bytes));

        boolean b = api.pubKeyVerify(7, sm2Key, Forms.hexStringToByteArray("20D90A83A4654FB8****0371B374F76DEFA5"), bytes);
        System.out.println("ECC/SM2公開金鑰驗簽結果(私密金鑰受保護密鑰保護)" + b);
    }

    /**
     * SM2非對稱金鑰保護匯入對稱金鑰
     */
    @Test
    public void SM2ImplKEK() throws TAException {
        ArrayList<byte[]> bytes = api.SM2ImplKEK(sm2PriKey, 300, TACryptConst.KEY_ALG_SM4, Forms.hexStringToByteArray("9A9161F87BCBD3E9BC8866B8706E8F75B682DA27********13440F2DAD9AE786E3D73349D78FA7915B3CB633EFD9A88E638D93297934"), "914-zjl".getBytes());
        System.out.println("LMK加密的對稱金鑰:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("對稱金鑰的校正值:" + Forms.byteToHexString(bytes.get(1)));
    }

    /**
     * SM2/ECC非對稱轉加密
     */
    @Test
    public void conversionEncryption() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_SM4, sm4Key, sm4CV, 2,
                -1, sm2Cipher, b, sm2CipherMAC, TACryptConst.ENC_MODE_GCM, b, new byte[2], sm2CipherTag, 0,
                TACryptConst.KEY_ALG_SM4, sm4Key2, sm4Key2CV, b, TACryptConst.ENC_MODE_GCM, b, new byte[2]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("第" + i + "個===" + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * 摘要運算,填充摘要資料
     */
    @Test
    public void testGenHash() throws TAException {
        byte[] hash = genHash();
        System.out.println("摘要結果:" + Forms.byteToHexString(hash));

        // 計算校正正確摘要結果
        String string = "704423DF78242B08E821F7F8FA05A5325AA1BD842BE4EB9827C765DFFF434C1A";

        byte[] bytes3 = genHash();
        System.out.println("驗證結果:" + Arrays.equals(Forms.hexStringToByteArray(string),bytes3));

        String wrongHash = "669523DF78242B08E821F7F8FA05A5325AA1KD842BE4EB9827C765DFFF434C1A";

        System.out.println("錯誤驗證結果:" + Arrays.equals(Forms.hexStringToByteArray(wrongHash),bytes3));
    }
    public byte[] genHash() throws TAException {
        byte[] bytes2 = api.HashInit("SM3", new byte[0], privateKeySM2DER);
        byte[] bytes = api.HashUpdate(bytes2, Forms.hexStringToByteArray("1234567890"));
        byte[] bytes1 = api.HashFinalize(bytes);
        return bytes1;
    }


    /**
     * 產生隨機數
     */
    @Test
    public void genRandom() throws TAException {
        String s = api.genRandom(15);
        System.out.println(s);
    }

    /**
     * 擷取加密機狀態
     */
    @Test
    public void getHSMstatus() throws TAException {
        String hsMstatus = api.getHSMstatus();
        System.out.println(hsMstatus);
    }

    /**
     * lmk to kek
     * @throws TAException
     */
    @Test
    public void test3() throws TAException {
        ArrayList<byte[]> bytes = api.LMKToKEK(TACryptConst.KEY_ALG_SM4, TACryptConst.ENC_MODE_GCM, b,
                new byte[2], 0, sm4Key,
                new byte[0], new byte[0], 5, 0,
                1, 0, TACryptConst.KEY_ALG_SM4,
                sm4Key2, new byte[16]);
        System.out.println("使用保護祕密金鑰加密密鑰密文:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("當選擇產生MAC時,輸出MAC:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("tags:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("密鑰校正值:" + Forms.byteToHexString(bytes.get(3)));
    }

    /**
     * 其他祕密金鑰加密轉LMK加密
     * @throws TAException
     */
    @Test
    public void otherEncKeyToLMLEncKey() throws TAException {
        ArrayList<byte[]> bytes = api.otherEncKeyToLMLEncKey(0, 7, 6,
                Forms.hexStringToByteArray("00000000000000000000000000000000"),
                Forms.hexStringToByteArray("00000000000000000000000000000000"),
                Forms.hexStringToByteArray("71802E75BD****996A9B9DA6616E9"),
                0,  Forms.hexStringToByteArray("B36847D6E8****4EEB65558A2626C"),
                new byte[0], new byte[0], 5, -1,-1, new byte[0], 0, 7,
                Forms.hexStringToByte("9940568000****9C7F45977D291AA"));
        System.out.println("=============保護密鑰為對稱金鑰============");
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println(Forms.byteToHexString(bytes.get(i)));
        }

        ArrayList<byte[]> bytes2 = api.otherEncKeyToLMLEncKey(2, -1, -1,
                new byte[0], new byte[0], new byte[0],
                888,  new byte[0], new byte[0],
                new byte[0], 1,
                1, 1, new byte[0], 0, 7,
                Forms.hexStringToByte("7C78EAFE26890D48096AB8141B1D5890BF1921DD********5329ADED546F44C52C8F49EAC46647650D9B983224E9E005CFCAA88B019D"));

        System.out.println("=============保護密鑰為ECC密鑰============");
        for (int i = 0; i < bytes2.size(); i++) {
            System.out.println(Forms.byteToHexString(bytes2.get(i)));
        }
        ArrayList<byte[]> bytes1 = api.otherEncKeyToLMLEncKey(1, -1, -1,
                new byte[0], new byte[0], new byte[0],
                11,  new byte[0], new byte[0], new byte[0], 3,
                1, 1, new byte[0], 0, 7,
                Forms.hexStringToByte("6149EE02F14EE6420BC2B462003CCCE2413CE491********E2CE400522E06DCBAB44213A85B668764EC33EE71D372F5A904252A539AA"));

        System.out.println("=============保護密鑰為RSA密鑰============");
        for (int i = 0; i < bytes1.size(); i++) {
            System.out.println(Forms.byteToHexString(bytes1.get(i)));
        }

    }
    @Test
    public void enveopEncAndDec() throws TAException {
        byte[] bytes = api.enveopEnc(sm2Key, "1111111111111111".getBytes());
        System.out.println("數位信封封裝結果:" + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.enveopDec(sm2PriKey, bytes);
        System.out.println("數位信封拆封結果:" + new String(bytes1));
    }

    /**
     * 對稱金鑰轉加密 & 非對稱轉加密
     */
    @Test
    public void symmetryConversionEncryptionAES256() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_AES256,
                Forms.hexStringToByteArray("5BD90CDDBC8645B4****96B6E52CC003D04F"),
                Forms.hexStringToByteArray("F8B6****4FD3"),
                TACryptConst.KEY_TYPE_SYMMETRY,
                TACryptConst.KEY_ALG_AES256,
                Forms.hexStringToByteArray("CFE8E3D44F753D3F****88EF70B54E65E232"), b,
                Forms.hexStringToByteArray("8F2440B220****7D8D807A832A19F"), TACryptConst.ENC_MODE_GCM, b, new byte[22],
                Forms.hexStringToByteArray("B5294D5910****80774B61BA48FA4"),
                0,
                TACryptConst.KEY_ALG_SM4, sm4Key2, sm4Key2CV, b, TACryptConst.ENC_MODE_CBC, b, new byte[12]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("第" + i + "個===" + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * 對稱金鑰轉加密 & 非對稱轉加密
     */
    @Test
    public void symmetryConversionEncryption() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("CBDCCE3378****E0B3BAA46CF3557"),
                Forms.hexStringToByteArray("F668****C2AD"),
                0,TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("6BFC84C39C****6C7FA2A30C912A1"), b,
                Forms.hexStringToByteArray("AB75C62580****39327B45881F589"), TACryptConst.ENC_MODE_GCM,
                b, new byte[0], Forms.hexStringToByteArray("4A501743FA****4A0A8705192C1C8"),0,
                TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("CBDCCE3378****E0B3BAA46CF3557"),
                Forms.hexStringToByteArray("F668****C2AD"), b, TACryptConst.ENC_MODE_GCM, b, new byte[0]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("第" + i + "個===" + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * 對稱金鑰轉加密 & 非對稱轉加密
     */
    @Test
    public void symmetryConversionEncryption1() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_SM4, sm4Key, sm4CV,
                TACryptConst.KEY_TYPE_ECC_OR_SM2,
                TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("83E260209C09CC3FEFDE****27A17AEB2C8919E1E4CF"), b,
                Forms.hexStringToByteArray("E60EFC4882****F68D0EB622298FB"),
                TACryptConst.ENC_MODE_GCM, b, new byte[16],
                Forms.hexStringToByteArray("B200ED220D****C4438649057EB02"),
                0,
                TACryptConst.KEY_ALG_SM4, sm4Key, sm4CV, b, TACryptConst.ENC_MODE_GCM, b, new byte[16]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("第" + i + "個===" + Forms.byteToHexString(bytes.get(i)));
        }
    }


    /**
     * 對稱演算法 CMK 保護匯入非對稱CMK
     */
    @Test
    public void importCMKByCMK() throws TAException {
        ArrayList<byte[]> bytes = api.importCMKByCMK("zjlimpl".getBytes(), 7,
                6,  //保護CMK DomainKey 加密 CMK 使用演算法模式標識
                new byte[16],     //ECB 模式解密時使用的 IV 資料
                new byte[16],      //GCM 模式解密時的認證資料
                Forms.hexStringToByteArray("566F7CE9E5****F02D7A7667E3F7C"), //GCM 模式解密時的 MAC 值
                Forms.hexStringToByteArray("DA23B170CE****772B3F2AE2CCA97"),//密鑰密文
                Forms.hexStringToByteArray("7192C7C6F1****FE8A51BA9256C87"),  //GCM tags
                6, //保護祕密金鑰加密模式
                new byte[16],//保護密鑰IV
                new byte[16], //認證資料AAD
                Forms.hexStringToByteArray("8DE9DFEE4B****1C08A38BDD8A92F"), //tags
                5,//保護祕密金鑰加密填充方式
                12, //工作階段金鑰類型
                7,  //會話CMK 非對稱金鑰的演算法標識
                Forms.hexStringToByteArray("420B9FE23A2B162F3C4574919E9EBD44040F7C53********0B18990EF5C6F3A93AB80B41458311EA9F9A1890752427E24F5062AD4A"),//會話私密金鑰密文資料
                "32-1".getBytes(),//會話DomainKey 標籤
                6,//會話DomainKey 加密 CMK 使用演算法模式標識
                new byte[16],//會話加密上下文(非 ECB 模式加密時使用的 IV 資料)
                new byte[16]//會話認證上下文資料(GCM 模式加密時的認證資料)
        );
        System.out.println("使用保護祕密金鑰加密密鑰密文:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("MAC:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("tags:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("密鑰校正值:" + Forms.byteToHexString(bytes.get(3)));
    }

    @Test
    public void testData() throws TAException {
        //產生對稱金鑰,保護密鑰保護輸出
        ArrayList<byte[]> bytes = api.proGenSymmKey(603,
                -1, null, TACryptConst.KEY_ALG_SM4, b,
                TACryptConst.ENC_MODE_GCM,b, b);
        System.out.println("LMK加密的工作階段金鑰密文:" + Forms.byteToHexString(bytes.get(0)));
        System.out.println("工作階段金鑰的校正值:" + Forms.byteToHexString(bytes.get(1)));
        System.out.println("保護祕密金鑰加密的工作階段金鑰密文:" + Forms.byteToHexString(bytes.get(2)));
        System.out.println("工作階段金鑰的MAC值:" + Forms.byteToHexString(bytes.get(3)));
        System.out.println("tags:" + Forms.byteToHexString(bytes.get(4)));
        System.out.println("-------------------------------------------------");
        //對稱金鑰(受保護密鑰保護)加密資料
        ArrayList<byte[]> bytes1 = api.proKeyEncData(603, -1, null,
                bytes.get(2),
                b, bytes.get(3), TACryptConst.ENC_MODE_GCM,
                b, b, bytes.get(4),
                TACryptConst.KEY_ALG_SM4, 0, 0,
                new byte[16], TACryptConst.KEY_ALG_SM4, TACryptConst.ENC_MODE_GCM,
                Forms.hexStringToByteArray("0000000000000000000000000000000000000000********353F49C7164DAE6C691FC25CD494D9A28D0F6C4B51F3BB9DC85ADDBE09"), new byte[16], new byte[16]);
        System.out.println("密文: " + Forms.byteToHexString(bytes1.get(0)));
        System.out.println("tag: " + Forms.byteToHexString(bytes1.get(1)));
    }

    @Test
    public void agreementKey() throws TAException {
//        byte[] bytes = api.agreementKey(0x02CB, 4, 4, Forms.hexStringToByte("3076301006072A8648CE3D020106052B81040022********5645477442F9BF8BE9BF81EAD69CDA6C63FCF5244A383C57DDB62465E63B"));
//        System.out.println("secp384r1協商結果:" + Forms.byteToHexString(bytes));
//        byte[] bytes1 = api.agreementKey(0x0007, 3, 6, Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF55********DF9A3DF50D67073CF246FC3406337B50E987F2AC3943D2FF5C7ECAD197"));
//        System.out.println("0x0007協商結果:" + Forms.byteToHexString(bytes1));
//        byte[] bytes2 = api.agreementKey(0x0007, 3, Forms.hexStringToByte("E59842CEEC68775E****F7DF23E08F7F6B8D"), Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF55********B972EB19EA77A6AB74F345688B8458F1015885FCE435A4E3679DE0E34F"));
//        System.out.println("0x0007外部私密金鑰明文協商結果:" + Forms.byteToHexString(bytes2));
//        byte[] bytes3 = api.agreementKey(0x039B, 0, 5, Forms.hexStringToByte("304A301406072A8648CE3D020106092B24030302********868F7D34BABEEB5A20F7DF5543091DD740DD3780B5EBEF631615571ADC"));
//        System.out.println("0x039B協商結果:" + Forms.byteToHexString(bytes3));
        byte[] bytesA = api.agreementKey(0x019F, 3, 13, Forms.hexStringToByte("3059301306072A8648CE3D020106082A8648CE3D********7558F1DA9AC8CDF5E7FA72C9931FA90EE06B3CE07E13A7845A05BA7C73"));
        System.out.println(bytesA.length);
        System.out.println("0x0007協商結果:" + Forms.byteToHexString(bytesA));
        byte[] bytesB = api.agreementKey(0x019F, 3, 15, Forms.hexStringToByte("3059301306072A8648CE3D020106082A8648CE3D********C7AB0964E53872FBF0511FF6E7661CF94B7D82C8BF78D211B1FA73F271"));
        System.out.println("0x0007協商結果:" + Forms.byteToHexString(bytesB));

    }

    /**
     * 根據金鑰索引擷取對稱金鑰詳情
     */
    @Test
    public void getKeyInfo() throws TAException {
        String[] keyInfo = api.getKeyInfo(66);
        System.out.println(keyInfo[0]);
    }
    /**
     * 根據金鑰索引擷取RSA公開金鑰
     */
    @Test
    public void exportRSAPublicKey() throws TAException, IOException {
        ArrayList<byte[]> keyInfo = api.exportRSAPublicKey(77,0);
        System.out.println(Forms.byteToHexString(keyInfo.get(0)));
    }
    /**
     * 根據金鑰索引擷取ECC公開金鑰
     */
    @Test
    public void ExportEncPublicKey() throws TAException {
        byte[] keyInfo = api.exportECCPublicKey(66,0);
        System.out.println(Forms.byteToHexString(keyInfo));
    }

    @Test
    public void generateAndSaveKey() throws Exception {
        ArrayList<byte[]> symmKey = api.generateSymmKey(7, 32);
        for (int i = 0; i < symmKey.size(); i++) {
            System.out.println(Forms.byteToHexString(symmKey.get(i)));
        }
        boolean b = api.generateRSAKey(2048, 65537, 13);
        System.out.println("產生並儲存RSA金鑰組" + (b ? "成功":"失敗"));
        boolean b1 = api.generateECCKey(0x019F, 8);
        System.out.println("產生並儲存ECC金鑰組" + (b1 ? "成功":"失敗"));

    }


}