All Products
Search
Document Center

Key Management Service:Use an HSM instance cluster

Last Updated:Jun 21, 2026

The HSM instance cluster feature of Cloud Hardware Security Module (CloudHSM) lets you associate HSM instances that serve a common business purpose across different availability zones within the same region. Your application can then use a polling algorithm to select an appropriate HSM and perform cryptographic operations with the same key. This architecture ensures business continuity, high availability for cryptographic computations, load balancing, and horizontal scaling for your application. This topic describes how to use an HSM instance cluster.

Note

To create an HSM cluster for a KMS hardware instance, see Configure an HSM cluster for a KMS hardware instance.

Cluster synchronization methods

Cluster synchronization replicates data, such as keys, SSL certificates, and user information, from the master HSM to child HSMs. The cluster synchronization method depends on when you purchased the HSMs:

  • For HSMs purchased on or after January 9, 2025: When you create a cluster, the cluster synchronization method defaults to automatic synchronization. You do not need to manually synchronize the cluster when data on the master HSM changes.

  • For HSMs purchased before January 9, 2025: When you create a cluster, the cluster synchronization method defaults to manual synchronization. You must manually synchronize the cluster whenever data on the master HSM changes. To upgrade the cluster to automatic synchronization, contact us.

    Warning

    This is an irreversible upgrade that involves the following risks. We strongly recommend performing this upgrade during off-peak hours.

    • For users of KMS hardware key management instances:

      • Control plane operations: Operations such as creating and deleting keys are not supported during the upgrade. They will automatically resume after the upgrade completes.

      • Data plane operations: Operations such as encryption and decryption are not affected during the upgrade.

    • For other users: You must upgrade the HSM SDK used by your application.

      • Control plane operations: Operations such as creating and deleting keys are not supported during the upgrade. They will automatically resume after the upgrade completes.

      • Data plane operations: For some business architectures, there is a risk of service interruption during the upgrade.

Prerequisites

Step 1: Create and activate a cluster

A cluster consists of one master HSM and multiple child HSMs. All HSMs in a cluster must be in the same VPC but can be in the same or different subnets.

Note

If you configured cluster settings when you purchased a GVSM instance, Cloud Hardware Security Module automatically creates a cluster based on your settings. Skip this step.

  1. Enable the master HSM instance.

    1. Go to the VSMs page of the CloudHSM console. In the top navigation bar, select the destination region.

    2. On the VSMs page, find the HSM instance that you created. In the Actions column, click Enable.

    3. In the Configure HSM Instance dialog box, configure the HSM instance and click OK. After configuration succeeds, the Status of the HSM instance changes to Enabled.

      Parameter

      Description

      VPC ID

      Select the VPC to which the HSM instance is attached.

      Important

      This VPC must be the same as the one attached to your ECS instance.

      VPC Subnet

      Select the subnet CIDR block of the VPC where the HSM instance resides.

      Private IP Address

      Assign a private IP address to the HSM instance.

      Important
      • The private IP address must belong to the subnet CIDR block of the VPC. Otherwise, configuration fails.

      • IP addresses ending in 253, 254, or 255 are system reserved IP addresses. Do not use them.

      Configure HSM Whitelist

      Configure the whitelist for accessing the HSM instance. You can enter one IP address or CIDR block per line. You can enter up to 10 entries.

      • If no whitelist is configured, all IP addresses can access the HSM instance.

      • If a whitelist is configured, only requests from IP addresses in the whitelist are allowed. Requests from other IP addresses are denied.

      Important
      • If you create an HSM cluster and configure a whitelist for the cluster, the cluster whitelist takes precedence over the whitelists of individual HSM instances in the cluster.

        For example, if the whitelist of an HSM instance in the cluster is 10.10.10.10 and the cluster whitelist is 172.16.0.1, you can access the HSM instance only from 172.16.0.1.

      • You cannot configure 0.0.0.0/0 (to allow all source IP addresses).

        For security reasons, we do not recommend allowing all source IP addresses. To allow all source IP addresses for temporary testing, leave the whitelist empty.

  2. Create an HSM cluster.

    1. Find the master HSM instance and click Create Cluster in the Actions column.

    2. In the Create and Activate Cluster panel, configure the cluster.

      Parameter

      Description

      Cluster Name

      Enter a custom name for the cluster. The name must be unique and cannot exceed 24 characters.

      Configure Whitelist

      Specify the IP addresses that can access the cluster. If no whitelist is configured, all IP addresses can access the cluster. If a whitelist is configured, requests from IP addresses outside the whitelist are denied.

      You can enter one IP address or CIDR block per line. You can enter up to 10 entries.

      Important
      • The cluster whitelist takes precedence over the whitelists of individual HSM instances in the cluster. For example, if the whitelist of an HSM instance in the cluster is 10.10.10.10 and the cluster whitelist is 172.16.0.1, you can access the HSM instance only from 172.16.0.1.

      • You cannot configure 0.0.0.0/0 (to allow all source IP addresses).

        For security reasons, we do not recommend allowing all source IP addresses. To allow all source IP addresses for temporary testing, leave the whitelist empty.

      Specify vSwitches

      Select vSwitches in the required zones based on your business needs.

      You must configure at least two vSwitches to successfully create and activate an HSM cluster.

    3. Initialize the HSM instance, and then click Next.

      Note

      You can activate the cluster only when the master HSM status is Initialized.

      Initialization method

      Procedure

      Method 1: One-click initialization in the CloudHSM console

      Important

      You can use one-click initialization only if your HSM is a general-purpose HSM (GVSM) and you do not require UKEY support.

      1. At the bottom of the Create and Activate Cluster panel, click Initialize the master HSM with a few clicks.

      2. In the Initialize Instance dialog box, click OK.

      Initialization is expected to take 1 to 5 minutes. Please wait. After the initialization is complete, click the update icon next to Selected Master HSM:. The status changes to Initialized. Do not reinitialize the master HSM in this state.

      Method 2: Initialize using the HSM instance management tool

      Important

      The HSM client management tool runs only on Windows.

      At the bottom of the Create and Activate Cluster panel, click Download HSM instance management tool.

      Extract the HSM software package. Then, refer to the Initial Initialization section in the user manual included in the package to complete initialization.

    4. Follow the on-screen instructions to add child HSMs to the cluster, and then click Complete.

(Optional) Step 2: Configure mutual TLS authentication

Automatic generation

Only GVSM instances support automatic certificate generation when you purchase an HSM. In this scenario, the HSM automatically generates the certificates. You only need to configure the certificates on the client SDK, as the HSM automatically deploys them to the server.

  1. Deploy the certificates on the client.

    Download the client certificate from the console and deploy it to your client.

    1. On the HSM details page, click Get Cluster Certificate. The downloaded folder contains the following files:

      certs/
      ├── client.p12 (Client certificate in PKCS12 format, which contains the client certificate and private key)
      ├── client.pem (Client certificate in PEM format)
      ├── rootca.key (CA private key)
      ├── rootca.pem (CA certificate in PEM format)
      ├── server.p12 (Server certificate in PKCS12 format)
      └── passphrase (Passphrase for the PKCS12 certificate with the .p12 extension)
    2. Deploy the client.p12 and rootca.pem files to the client. In the client configuration file, you must also configure the file paths for client.p12 and rootca.pem, and the passphrase value. For more information, refer to the documentation included in the package that you downloaded from the console.

  2. Deploy the certificate on the server.

    The HSM automatically deploys the certificate to the HSM instance. No action is required.

Important

The default validity period for a certificate is 10 years. Before a certificate expires, the HSM automatically generates a new certificate and rotates the server certificate. Do not use the HSM instance management tool to create a UKEY administrator. Otherwise, the certificate rotation fails.

Manual generation

GVSM supports automatic certificate generation. However, if you did not enable this option during purchase, follow these steps to manually generate and deploy the certificates.

  1. Generate certificates.

    1. Download the certificate generation tool (dkms_cert_tool).

    2. Unzip the downloaded file and run the certificate generation tool to generate a CA certificate, a client certificate, and a server certificate.

      Note
      • The tool is platform-independent and can be run on a local computer, an ECS instance, or any other supported environment.

      • This is a helper tool from Alibaba Cloud. If you can generate the required certificate files yourself, you can skip using this tool.

      Windows

      • Method 1: In the Windows folder, double-click the hsm_certificate_generate.exe file to run it. The certificate files are generated in the certs folder.

        Note

        This method sets the default password for the PKCS12 certificate files (.p12) and CA private key files (.key) to 12345678. To specify a custom password, use Method 2.

      • Method 2: Navigate to the Windows directory and run the following command. The certificate files are generated in the certs folder.

        ./hsm_certificate_generate -dir ./certs -pswd 12345678

        The -dir parameter specifies the output directory. The -pswd parameter specifies the password for the PKCS12 certificate files (.p12) and CA private key files (.key).

      Linux

      Navigate to the Linux directory and run the following command. The certificate files are generated in the certs folder.

      ./hsm_certificate_generate -dir ./certs -pswd 12345678

      The -dir parameter specifies the output directory. The -pswd parameter specifies the password for the PKCS12 certificate files (.p12) and CA private key files (.key).

      macOS

      Navigate to the darwin directory and run the following command. The certificate files are generated in the certs folder.

      ./hsm_certificate_generate -dir ./certs -pswd 12345678

      The -dir parameter specifies the output directory. The -pswd parameter specifies the password for the PKCS12 certificate files (.p12) and CA private key files (.key).

      After the command runs successfully, the following files are generated in the certs folder:

      certs/
      ├── client.p12 (Client certificate in PKCS12 format, which contains the client certificate and private key)
      ├── client.pem (Client certificate in PEM format)
      ├── rootca.key (CA private key)
      ├── rootca.pem (CA certificate in PEM format)
      ├── server.p12 (Server certificate in PKCS12 format)
      └── server.pem (Server certificate in PEM format)
  2. Deploy the certificates on the client.

    Deploy the client.p12 and rootca.pem files to the client. In the client configuration file, you must also configure the file paths for client.p12 and rootca.pem, and the password that you specified when you generated the certificates. For more information, refer to the documentation included in the package that you downloaded from the console.

  3. Deploy the certificates on the server.

    1. Install the HSM instance management tool on an ECS instance.

      Important

      The HSM instance management tool runs on Windows only.

      1. Click the download icon image in the Specifications column for the master HSM to download the HSM instance management tool.

      2. Unzip the downloaded HSM package, find the PKIManager-X.X.X.X.exe file, and upload it to the ECS instance. For more information, see Transfer files to a Windows instance.

    2. Use the HSM instance management tool to configure the master HSM.

      1. On the ECS instance, use the HSM instance management tool to connect to the master GVSM.

        1. Double-click PKIManager-X.X.X.X.exe to open the HSM instance management tool. Choose System > TCP/IP Connection.

        2. In the TCP/IP Connection dialog box, enter the IP address and Port for the master HSM. The port is 8020.

          Find the master HSM's IP address in the IP Address column of the HSM instance list. The master HSM is the instance identified as a Master HSM in the Cluster column.

        3. In the PKIManager dialog box, click Connect. In the PKIManager dialog box that appears, click OK, and then click Login.

          Note

          To improve security, we recommend that you register an administrator account for subsequent logons. For more information, see Sections 2.1.3. Register Administrator and 2.1.2. Administrator Logon in the GVSM User Management Manual, which is included with the HSM instance management tool.

      2. Use the HSM instance management tool to complete the following configurations.

        Parameter

        Actions

        Configure the client certificate (client.pem)

        1. Choose Key Management > Client Management.

        2. In the Client Certificate Management dialog box, click Import Certificate.

        3. In the Import Certificate dialog box, set Certificate Type to International TLS Client RSA Certificate [pem], select the client certificate (client.pem) generated by the tool, and then click Import.

        Configure the server certificate (server.p12)

        1. Choose Instance Monitoring Information > Server Management.

        2. In the Server p12 Certificate Management dialog box, click Import Certificate.

        3. In the Import Certificate dialog box, set Certificate Type to International TLS Server RSA Certificate [p12], select the server certificate (server.p12) that was generated by the tool, and enter the Certificate Password. This password is the one you set during certificate generation. If you did not set one, the default is 12345678.

        4. Click Import.

        Configure device port properties for the master GVSM

        1. Choose .

        2. In the Host Port Properties dialog box, configure the following parameters:

          • Socket KeepAlive Time: 60

          • Message Header Length: 0

          • Message Encoding Format: ASCII

          • Host Service Communication Mode: Bidirectional Communication

          • Host Service Communication Protocol: TLSv1.2

        3. Click Reset.

        4. Click Restart Now, and then click OK.

Step 3: Synchronize cluster data

  • If the Cluster Type is Manual Cluster Synchronization: You must synchronize the cluster after its initial creation and activation, or when data on the master HSM changes. Synchronization is not required when scaling out the cluster.

  • If the Cluster Type is Automatic Cluster Synchronization: Synchronization is automatic. The master HSM automatically synchronizes new keys, configured SSL certificates, and user information to the child HSMs.

Warning

Cluster synchronization takes about 5 minutes. Perform this operation during off-peak hours to avoid service disruptions.

  1. On the VSMs page, find the target master HSM instance. In the cluster synchronization method column of the instance list, check the synchronization type (manual or automatic).

    If the cluster type is Manual Cluster Synchronization, you must synchronize the cluster.

  2. In the Actions column, click Synchronize Cluster. In the dialog box that appears, click Synchronize Cluster again.

Step 4: Create and use an encryption key

The HSM software package includes the HSM developer guide and SDK test programs. You can use the developer guide to call API operations and manage your HSM instance.

Note

You can download the HSM software package on the VSMs page of the CloudHSM console. Find the target HSM instance, click the Specifications column, and then click Download HSM instance management tool. Extract the downloaded file to obtain the HSM software package.

For example, for a general-purpose HSM (GVSM), locate the APITest.java test case in the extracted Alibaba CloudHSM GVSM Software Package>SDK>JAVA>Server HSM Interface Documentation>Test Demo directory. You can use this test case to test the HSM instance. The following provides sample code:

Note

Replace the IP address (192.168.XX.XX) in the test case with the private IP address assigned to your HSM instance.

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);

    /**
     * Symmetric key encrypted by LMK
     */
    byte[] symmetricKey = Forms.hexStringToByteArray("669C1CEDDAFA267CC5D727EA727558B5");
    byte[] verifyValue = Forms.hexStringToByteArray("BD8596C22E5A4D88");

    byte[] symmetricKey1 = Forms.hexStringToByteArray("93EF12C95813586FEC3EFDBC7B37642D");
    byte[] verifyValue1 = Forms.hexStringToByteArray("78306FD68851B8E6");
    /**
     * Ciphertext of session key encrypted by LMK
     */
    byte[] symmetricKeyKEK = Forms.hexStringToByteArray("2E80A42018F186BCCBCF639F644629E8");
    /**
     * Verification value of session key
     */
    byte[] verifyValueMAC = Forms.hexStringToByteArray("734D092CD8C23E38");
    /**
     * Ciphertext protected by protection key
     */
    byte[] protectionKey = Forms.hexStringToByteArray("2EACE685C5EB2638D1208742F3BE60CD44210B43C894A77C");
    /**
     * MAC of ciphertext protected by protection key
     */
    byte[] protectionMAC = Forms.hexStringToByteArray("0CB8702D41CBE487");

    /**
     * RSA public key in DER encoding
     */
    byte[] publicKeyRSA = Forms.hexStringToByteArray("308186028180E14CAAFFCEC6D014457D7CA3E943DBABA1299BDBC17690C8E70F7BFA10EA02450805DA4C6CDC38BFBF1349C95B81A88177BA31C08E366EF965CA41EB36A2DACE611B80A752615A094B8291AAB6F8BB3A5894E72842371F34FA04C10DF42C2FEA95C51B9D49BE8B795E10474954FE01BAAC63532520069465FA62EDB266AADEBB020103");
    /**
     * RSA private key encrypted by LMK
     */
    byte[] privateKeyRSA = Forms.hexStringToByteArray("000202703D0652C7027B7D94B45A896646A9DC7CA89825FB12121B3CC00E37BE933055D5C00E37BE933055D54718ADDAA677519BD9C054CA249B43888FE000B8AAC33BA87A2C326985704335EA54D7F171CABCAD5531B3ADF33255A24075EFFF62691D4375E6280A9442CA36AA46AC59FAB16D9A9A7A283440BB14BAB1E78DBE887AE93A2C94C547779190D3FA801379BA948537281EFEFE567FD963E5D6E5D442D908A68BB6E26F3776EA30B1136A3804844035E26308E9B44BE154E1D09382E5A72BD711A6936373A8C32B62AF88134690C30D8B5505004F3BA01D11D0D791C8FF53D0E0786ED192CF1105FCF82160921EEF23E7BD72F13587B316BD9A771CEABBD0186B45E09C86E718AD4E5444EFFE747FE0C39E85D6190F3347656E72F486C321D5EA0D42127149C99F4F799A31F91E5826B74FF720A6E3CC2BCBBF645DD3D4A6A7D0BC953B4CFEE4E0D2BABFD606292F9F2395464484C306FBD60E4DD293E5F56C60BF1482A05775F0EEBAFBF9B70841DDDCFC974DD4D87E54D6A6A7A1A585EF0F42B0763D5DD7B5ECA83AFE610C26C9EF559B7883AC4716240BDFDC91C6EA19A0C01BB9C053F2A9C7EBCAE7D0AA8FB0DB88EFCF9C50A134E04649DAFF21D724E5C3CC043DE950C2CF246392DC4CA592D28C5A959BEB80B304E3BD949AD33178C06209FE6EB7130A381DFFD80F916AE0E0DD8FFDD9C8C9895BC483993D6011754FAD3C9F83A59C31F47810F8B2B22E5F25EF13671DFF34ECB65DE71D5B13DC5880595BC60B18D4711AE4613C739E2A48B516F6233E9AA9834075CE58975907F06FBA3B85C97E2E90B60BFEF0F23527E770798B571BC7CE29B67920538D509C58B1D8F966AF7E5321CDB2386164844D2BCB");
    /**
     * RSA private key encrypted by protection key
     */
    byte[] privateKeyRSAKEK = Forms.hexStringToByteArray("6B2FB2BCC75604ABF5761FFA1027FF16324E3038B580C9F63AD3B57BD89059D5799974B4E5E9453763D94E682C629C4617C4E5393E9DDBFB0CFA2A4EA0E832F5C6A30F3EE63C327F6E044F3CB630D0C7DD96D93581835AA529797EB11CF3535650E431181717FDD1D7BBD9FB675FB027134BBF7F10F65245D9A82251A9171DAA439C175895904A2BB74F31BD94FF550023F6245C01DF83B2FCEDDF241307DDC831162AD2203BA3EBC4FD99EAE93C3208F16B0AAF85146ACE5FF06B11D7C81215708AA5C2651D380573F0EDA0984A73F5CE38E21541D50AACF5C5BCD42B6C94D064065ECAED4684E7A40C15904A73A801F2697AF6F3E32C3D7E156A1D1085CA32C7A002FA4AEAD439271E6E5904FC9AC3E65EEBAC51399F60DF3C61AF82BDA04D5E28B587382F8EB751096BC970B7A7DF26D997324F2D002D01A4C8F77C37BB65DBD1DED3B4545323DAE9489A08351507224574A2206FA7EAF8EF0A120D23D6B34E84645E95C3B58187BC91B8F6C04EF15075D6AF38B7E7DD77F6D2B8E66F11960C401BCE56BB4C157DAA26234678A37ACCFC7729CB5018449F7B6A23C0B16CA0B6A5FBE9FC7C8F9A3801A4159822DDDE8D9D7B7233CC3F77E7391DE720A2BFC69F6B938B565A28EBC6B4B665C553A9E1F32A17CC66CB8A2D7FE3EF6CB5112815D562F18EB34987B57DCFF064C7C24E97C3DCF3FD9BD50B351A2DD7CF03DA1F2DDA7A1BD2013C8339AFC4D22C135C49859C9C4CA4C9F730D2EE09A779D244C13FB5C3835F2FF04EE12537B01795D0ABE2D9695208542DC2FF8161AFD6F774E8D524B1DE6096530783");
    /**
     * RSA MAC
     */
    byte[] privateKeyRSAKEKMAC = Forms.hexStringToByteArray("701A4D3572D09760");

    /**
     * RSA private key encrypted by KEK
     */
    byte[] privateKeyKEK = Forms.hexStringToByteArray("7A833CC0FAFBA6EC063DF4827B8FD91FF4B9A69FB0C44FD972173C09E9E56F6918730269561A497403F9478D7BB64FE527F748AF86E3CE7C762A92A07D9C8BBCE0731F9F07C5889AE8B0FF7A31FCCCD76CD20A1AFB95B4D12BEA5DB84059B9CB1FB8F778989FD11CB7F8D84D812190F2EE0F479A4020FEB32C634528FBF660B3AD5AB0BA497B932902294C28B02807DC1AC28E8213BA39582AA677050F9E9256879935484B49D1CD115B39C0A41AE2B18263F78EA4CB781C931EA3C638097D1A7D4245C30ADA1B7C7793FD798EFAB86C3A91F573D4D2ECFA188588A31983320052901CC5AECAEDC5296506442546614B3DFDECA958B5E3A659EC8B52C5818E22F8E50C216264B560073F47E07B07E38CEF2DF4F6E4A458665FD31E6AA1C7B2FB5C4A15405C09E5F2B814FB260C1FFC560A2B6F3370C9DD96BA0A15BA72AB3622FE172F847D60383307C936246B977665CAB5E68EFA6E4EE1F9008FAE7A90D4A2A10AB70969714041707D4AD05F96027FA62FC916C81BA3C8601F7FF3115F17A117AD1B9A3D8438A731707A2D3B65BDA3846D293939CF94EBCC681E8115400454CF2CEA3769A614A9098CA62356B131EA22F4D634B56B365D7A430A3703967B50C6FCA93D11BD5ACC60048B5E00EAF353723D6DE878F8E5E4EA03BD43DF7229E6146DE307F9CC51B7F359F07042500AB5C24EE6F80EA8E1E50961BEC347949E5DD1918027A17196BABEE5790332B76D4AFFCD19143D7462177CDF72DE09BE64320C330090C1C6F1B059E81E02C312ABFC68F454D11EFCF1E0609584D06B09A08599D7A0BF5D63BB9F");
    /**
     * RSA private key MAC encrypted by KEK
     */
    byte[] privateKeyRSAMAC = Forms.hexStringToByteArray("06E5A11D968C36DE");

    /**
     * SM2 private key encrypted by KEK
     */
    byte[] privateKeySM2KEK = Forms.hexStringToByteArray("D3C5F579038C8BF3469879DD7F79C2E1B7FF47D7F2D5EFF5B01EFCE51C081D8067E06C0290F8EF6044210B43C894A77C");
    /**
     * SM2 private key MAC encrypted by KEK
     */
    byte[] privateKeySM2MAC = Forms.hexStringToByteArray("83E413861F0C0D15");


    /**
     * SM2 public key in DER encoding
     */
    byte[] privateKeySM2DER = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF5501822D03420004B33D8A2F9E1E1FCA2E8CECCFFB166F52CC2ED0589C25464D0EF85DC87E0537DC16C0D542A53790967A1368B7084F6EFED51FC848D1E3B5370A99BDCB64D17C2F");
    /**
     * SM2 private key encrypted by LMK
     */
    byte[] privateKeySM2 = Forms.hexStringToByteArray("66C9DDB0D6400EE059474F5C7339A296D5AA88F02AF031174F212EB6538C21908C4F5CA6457B435F");
    /**
     * SM2 private key protected by protection key
     */
    byte[] privateKeyKEKSM2 = Forms.hexStringToByteArray("D3C5F579038C8BF3A1624E7DC142A863240A42642337355921C70A7547001B21A0C59D4E0800F99644210B43C894A77C");
    /**
     * SM2 MAC
     */
    byte[] privateKeyKEKSM2MAC = Forms.hexStringToByteArray("B9827812C2E18232");

    /**
     * Randomly generated SM2 key 1002
     */
    byte[] publicSM2 = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF5501822D03420004D93204DF6335BEF43A90F8566CFB6FB5F7B10BE8082E9C0D9A5AA731F994AF07990FCB6913D902C4C9B8A84A3F96ADDD7BEF537D61404D56E58A68C756AEFD40");
    byte[] privateSM2 = Forms.hexStringToByteArray("6F26783DCE6D45B84D3FF39FFBDB365FE93B94EF15C39E00A09DE07212472FA68D1A3B721C09BB28");

    /**
     * Data digest calculated by MD5 algorithm
     */
    byte[] md5 = Forms.hexStringToByte("D41D8CD98F00B204E9800998ECF8427E");
    /**
     * Data digest calculated by SM3 algorithm
     */
    byte[] sm3 = Forms.hexStringToByte("E559D3DE421E81967DD68B28B55E0C26B03FCE10B8A8E5C4E6067497729D40D3");

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

    public APITest() throws TAException, ConfigurationException {
    }


    /**
     * Generate a symmetric key
     *
     * @throws TAException
     */
    @Test
    public void genSymmKey() throws TAException {
        ArrayList<byte[]> bytes = api.genSymmKey(3);
        System.out.println("LMK-encrypted symmetric key: "  + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Verification value of symmetric key: "  + Forms.byteToHexString(bytes.get(1)));

    }

    ///////////////////////////////////////////////////////////////////////////
    // 1015 Test data
    ///////////////////////////////////////////////////////////////////////////

    byte[] sm4Key = Forms.hexStringToByte("EE828FCCFAC494756468B1FECCE81192");
    byte[] sm4CV = Forms.hexStringToByte("BCC22E39C9B72764");

    byte[] sm4ProKeyCipher = Forms.hexStringToByte("7C78B0D533A10812FE9277504181C23F");
    byte[] sm4ProKeyCipherCV = Forms.hexStringToByte("8849C862448CFB73");

    byte[] newSM4 = Forms.hexStringToByte("AE62E4E90FA741090AECE0AC9923B885");
    byte[] newSM4KeyMAC = Forms.hexStringToByte("F7EBEA9FD38EBBD324E7EAAC9B7BE362");
    byte[] newSM4KeyTag = Forms.hexStringToByte("7C05A01A54B63CB90E0C8597DBED6D6D");

    byte[] sm4Key2 = Forms.hexStringToByte("40F7B1FA358855610EB13491B119A4AB");
    byte[] sm4Key2CV = Forms.hexStringToByte("955C2B5828299C51");

    /**
     * Generate a symmetric key and protect it with a protection key
     *
     * @throws TAException
     */
    @Test
    public void generateProtectionKey() throws TAException {
        /**
         * SM4
         * LMK-encrypted symmetric key: B36847D6E86EAB69E4EEB65558A2626C
         * Verification value of symmetric key: 713CA557C1FE2AAB
         */
        ArrayList<byte[]> bytes = api.proGenSymmKey(Forms.hexStringToByteArray("B36847D6E86EAB69E4EEB65558A2626C"),
                TACryptConst.KEY_ALG_SM4, Forms.hexStringToByteArray("713CA557C1FE2AAB"), TACryptConst.KEY_ALG_SM4, b,
                TACryptConst.ENC_MODE_GCM,b, b);
        System.out.println("LMK-encrypted session key ciphertext: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Verification value of session key: " + Forms.byteToHexString(bytes.get(1)));
        System.out.println("Session key ciphertext encrypted by protection key: " + Forms.byteToHexString(bytes.get(2)));
        System.out.println("MAC value of session key: " + Forms.byteToHexString(bytes.get(3)));
        System.out.println("Tags: " + Forms.byteToHexString(bytes.get(4)));

    }

    /**
     * Encrypt and decrypt data using a symmetric key
     *
     * @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 encryption result: " + 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 decryption result: " + new String(bytes1));
//        byte[] paddingData = Padding.PKCS5Padding(Forms.hexStringToByte("30820122300D06092A864886F70D01010105000382010F003082010A0282010100A636C484374F9F039EB4318952B6BA5ABBE096F2B37B12DBC71A09F3B7BEEB83EB4A4BBBBDBBCC9332168E336981C919EF8BB734B3671DFEDCB79459401F95DDAA4EACECB36599451F9F77F5B01BF6B6AA1F94DE8BE5ED8B7BD52CA94929F7B0D3E8F5FDAFA322538AE32F89D7E3C1E4203120EDE6F213A3848F8ECF9E6836BE369A4658B6EB14D2FD3681488A3207CE0A5A9088011B2DA893C7F2C674843BB5254C30CB67D9C8182FEF284BB5CD8A239D6411EA199AD8B93EBE3442716FDAB44FB3932248C076C8794725CEEB5B76674B2B6DC605DC0F9835C6CCBBE4807A4F925065E02C65CAFE2D80A275BF5D096D2E07BA9ED5A75A10D425B03B84BB57990203010001"), 16);
//        byte[] bytes = api.symmKeyDataEnc(28,TACryptConst.ENC_MODE_CBC,TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_AES128,
//                paddingData, b);
//        System.out.println("AES encryption result: " + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.generalDataDec(Forms.hexStringToByte("789F01F9CC1BE0FF7429D7EAB215ABA1"),TACryptConst.ENC_MODE_CBC, TACryptConst.KEY_TYPE_RULE, TACryptConst.KEY_ALG_AES128,
                Forms.hexStringToByte("AE6BA9133D0D4BB0090882E33F03D905D779785299F12C241936CB6AE45B9D2CB5C6B4E6C96D74BEB7D4A53684A18E0764DBE6A2383FB43C8CCCBDC1E84DF4D593141B302CB0F96074B32E06924F54AC342584EF47D41EF0022362A89F07B96071D3D0910C7A581FE0F7BC564F28107C9EBDD060AB11DC0700E3577606BCD666C93207E2AFDCF84E6FA7FE84A60BB39B0B0489EDDBEFB1C95768EA9010C993B2D51B8A752396FE585422F766CBAC3CCC7301C92483D726DEF325A685D861ABFFABF2C91022DB984D8E606CAA8AEE01DA969C72F81F0D13E96DCDE0DEAAF4309517618FB4C5BA6281F262C511E3A90F9ED952FD6D0ACEB6CCD4F5FA96DD6C15A2A2B848C1A224AAE1081102FC7313EB233112B1C0079352310E974EB1155A759374004095E2256B0ADC3BFFFF150AF071"), b);
        System.out.println("AES decryption result: " + Forms.byteToHexString(bytes1));
    }




    /**
     * Encrypt and decrypt data using a symmetric key protected by a protection key
     *
     * @throws TAException
     */
    @Test
    public void protectionKeyEncrypt() throws TAException {
        ArrayList<byte[]> bytes = api.proKeyEncData(sm4Key, TACryptConst.KEY_ALG_SM4, sm4CV,
                Forms.hexStringToByte("C0C64CD82E3B2DC8C8F4D5A33F0EF6B4F5942AF6B880EE6A6AAB159C90C3F46175F2C068A54CF5BA4F0BCF7AC04E08E8"),
                b, Forms.hexStringToByte("75F2C068A54CF5BA4F0BCF7AC04E08E8"), 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("Ciphertext: " + 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("C0C64CD82E3B2DC8C8F4D5A33F0EF6B4F5942AF6B880EE6A6AAB159C90C3F46175F2C068A54CF5BA4F0BCF7AC04E08E8"), b, Forms.hexStringToByte("75F2C068A54CF5BA4F0BCF7AC04E08E8"), 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("Plaintext after decryption: " + new String(bytes1));
    }

    byte[] srcRSACipher = Forms.hexStringToByte("83E265207D4566C7704DF9E6170181378CA028FB1EAA0BCB771DFD188CF5BEA899ECEF9213CA98D6D698CCE6072237768F514B04D68DA6B01400F69F93601976DCDFAE8F2EDDAA4F01BA8CE5E76A77AEB01BAB9D6E59A32B4E30B2B8D21D13B5C3510A1622190621BD3B0B5838A2CCBE423F4D3A7613CB69BBC9857E4BF5D08AAD77DDB96ECDD88989B885D44B909F502DC53A2FB4200FA714ECCFF100E7E986D76B68BD0BEFF5CA33CA698DA42F8B74FFBC09FB8F30483E416D0D2EAC6AF2B2A309F6762B5D292DA619C92428D1AB11A6931C81A859C79D8C01B441B1902ABE001BFF501DEE0E1E241E4567ECC74F9D4665AEA77C4F93AC312347A5087B686DC8361415A85197DB69CEEFD6D00CE94C34C290B8F79F10CC27A79D7C4D8F43736223576649E93457C75BA8C637927EC780A56B45163142DE1483777B4C8222C92B3C82AB372B3B0223D4EE246938EB85A7EC536DC77A291E152CF94E02465137DF2F25140669071913F868E58F379472235564F125B6C71C2705FE895ABEEFE33C656ACA7D489AD5C432B80AB9D8F732C03519F2E99F0DEAC4A7312FC351C059877BA09FB6455EFCB0D0DFE9F597416A5E1D88A7326C64D5539D91519935FADD5BE76EBB4D60FC57103CB8960890B4B1EC822C8D9781CF67B6DD1BE15E87406A0B0B5C06A69F6B07991C95B13CC0C4DBEA91589425E7C8D4E7CFE2CBBEC34D7705E8B52939D2E154B3435B7B4B8E41CD4DCEDF3892EF0F3352C8467CA46DB08A7DC93969E18B405F44508F919F4C0B3F2F7C0B79E661001B79FB0F0205A97CECFBE25DC4C711EA");

    byte[] srcRSACipherMAC = Forms.hexStringToByte("948D9944793CAFAB372E54468349B3E5");

    byte[] srcRSACipherTag = Forms.hexStringToByte("9C8A7CB4C6D1AE08775F0681ED497EDF");

    byte[] srcRSApublicKey = Forms.hexStringToByteArray("308186028180E14CAAFFCEC6D014457D7CA3E943DBABA1299BDBC17690C8E70F7BFA10EA02450805DA4C6CDC38BFBF1349C95B81A88177BA31C08E366EF965CA41EB36A2DACE611B80A752615A094B8291AAB6F8BB3A5894E72842371F34FA04C10DF42C2FEA95C51B9D49BE8B795E10474954FE01BAAC63532520069465FA62EDB266AADEBB020103");
    /**
     * RSA private key encrypted by LMK
     */
    byte[] srcRSAprivateKey = Forms.hexStringToByteArray("000202703D0652C7027B7D94B45A896646A9DC7CA89825FB12121B3CC00E37BE933055D5C00E37BE933055D54718ADDAA677519BD9C054CA249B43888FE000B8AAC33BA87A2C326985704335EA54D7F171CABCAD5531B3ADF33255A24075EFFF62691D4375E6280A9442CA36AA46AC59FAB16D9A9A7A283440BB14BAB1E78DBE887AE93A2C94C547779190D3FA801379BA948537281EFEFE567FD963E5D6E5D442D908A68BB6E26F3776EA30B1136A3804844035E26308E9B44BE154E1D09382E5A72BD711A6936373A8C32B62AF88134690C30D8B5505004F3BA01D11D0D791C8FF53D0E0786ED192CF1105FCF82160921EEF23E7BD72F13587B316BD9A771CEABBD0186B45E09C86E718AD4E5444EFFE747FE0C39E85D6190F3347656E72F486C321D5EA0D42127149C99F4F799A31F91E5826B74FF720A6E3CC2BCBBF645DD3D4A6A7D0BC953B4CFEE4E0D2BABFD606292F9F2395464484C306FBD60E4DD293E5F56C60BF1482A05775F0EEBAFBF9B70841DDDCFC974DD4D87E54D6A6A7A1A585EF0F42B0763D5DD7B5ECA83AFE610C26C9EF559B7883AC4716240BDFDC91C6EA19A0C01BB9C053F2A9C7EBCAE7D0AA8FB0DB88EFCF9C50A134E04649DAFF21D724E5C3CC043DE950C2CF246392DC4CA592D28C5A959BEB80B304E3BD949AD33178C06209FE6EB7130A381DFFD80F916AE0E0DD8FFDD9C8C9895BC483993D6011754FAD3C9F83A59C31F47810F8B2B22E5F25EF13671DFF34ECB65DE71D5B13DC5880595BC60B18D4711AE4613C739E2A48B516F6233E9AA9834075CE58975907F06FBA3B85C97E2E90B60BFEF0F23527E770798B571BC7CE29B67920538D509C58B1D8F966AF7E5321CDB2386164844D2BCB");


    byte[] srcSM2Cipher = Forms.hexStringToByte("83E260209C09CEF21E1AD68B09EC5FA762164497DB6D7C6EEA5D58D14F7C0B8D670537112DFB030F");

    byte[] srcSM2CipherMAC = Forms.hexStringToByte("7DF725131F3E67547F029550F2F073E9");

    byte[] srcSM2CipherTag = Forms.hexStringToByte("A2181C58228D7A32AE37C072987D1B7E");

    byte[] srcSM2publicKey = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF5501822D03420004549EAF3A09B4F486171FF320B81C4037286FC68026AA6E0101D3108C0573CFB0FF431DF8D3F9E5A31C7DE80940637E036B2D6FD36A0F586D4CDC3A610A269E89");

    byte[] srcSM2privateKey = Forms.hexStringToByteArray("79E62264C314D1D3279D9B7752CD137AD4095864801607EB52B6AB9C6ADBF2BC777F8CBE7EC55699");


    /**
     * Encrypt and decrypt large data packets
     */
    @Test
    public void bigDataEnc() throws TAException {
        byte[] enc = api.bigDataEnc(Forms.hexStringToByteArray("6DF7292D86B674B6B81F7C94DDC967A0"), "AES/ECB/PKCS5Padding", "demaxiyazhili".getBytes(), new byte[0]);
        System.out.println(Forms.byteToHexString(enc));
        byte[] dec = api.bigDataDec(Forms.hexStringToByteArray("6DF7292D86B674B6B81F7C94DDC967A0"), "AES/ECB/PKCS5Padding", enc, new byte[0]);
        System.out.println(new String(dec));

    }

    /**
     * Calculate and verify 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 calculation result: " + Forms.byteToHexString(bytes));
        boolean b = api.verifyMAC(1, 0, 2, sm4Key, 7, "1111111111111111".getBytes(),
                new byte[16], bytes);
        System.out.println("MAC verification result: " + b);
    }

    /**
     * Calculate 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)));
        }
    }

    /**
     * Generate an RSA key pair with the private key encrypted by LMK
     */
    @Test
    public void generateRSAKeyPair() throws TAException, IOException {
        ArrayList<byte[]> bytes = api.genRSAKey(2048, 65537);

        System.out.println("Public key in DER encoding: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Private key encrypted by LMK: " + Forms.byteToHexString(bytes.get(1)));
    }


    /**
     * Generate an RSA key pair with the private key encrypted by a protection key
     */
    @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("Public key in DER encoding: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Private key encrypted by LMK: " + Forms.byteToHexString(bytes.get(1)));
        System.out.println("Private key ciphertext encrypted by protection key: " + Forms.byteToHexString(bytes.get(2)));
        System.out.println("Length of asymmetric private key MAC: " + Forms.byteToHexString(bytes.get(3)));
    }

    /**
     * Sign and verify using an RSA private key
     */
    byte[] privateRSA = Forms.hexStringToByte("000204B07672172F114E8E847A5FB9EC3DD32CD1F063E78FE16508F3E13DDCEE227447EBE13DDCEE227447EB80D3FD7BAFF9D6FD4DE2225C31BAFF7C626E7DEFD52ED1EEF9195F538F89B902AF389CF4277EADC1FA18BED9044C4CBCDD6801DA9C8762A3E6715D93AF02D4665D1AE5669288EF9E429C46EDC366C4F60724DED14AE4A3870E6D75DA22CFC304C38B50394BC09F833D3A6A663F0E0863FB7DDBC0C83CD24690BF54B8A45053CAE10C22018D11C10F112B4EECA416D39FCEA9276C93DAE83D8B300E67545B897DCAAC0CF064C9A2F8EE61362AE90694EF300DC7B901F1F093BA167DA76CD5F1432024C8C8FC420BB182B3944F7E104DBAE51BD859F36E92AB32E21754B711288643FB3399B363F776CB614C5EC08569A0E457507D3CA53A56065ECEA0AC7A467E88C4A7D2B63BBF933FE69B64E8F43F766D3D5B219FF00882E85F4C8A9CAD86EE65ACE2129DB6B4EC760E6687DE96B9AFB6F2A98D3C4AFE0F05D4485ADC055580242DD1FAF07808FA75E85E102B879E680004F992979ACA6B6C54885B5A52FF1EA55B3EF9F787D395E2E500D1A8CDE83D7FC05DB124441F2234BC88B9286CA142B22601C5225F8E679CFD3F612E37CA39E67736175B4A298BD69625658664AF8A9B8045A4E3FE2CEF770BD6BF2CE7D6B7C0C72B55C23FA6D0437E2D4DEDE89BCFC77AC90EA1F5B72910A4449EED91BCB778CD86DA88DE8341940E7F4677EB7D322722876A893926326E19D32DF6653EB4068D3C05F24B854F4B77EB0059C7EECD4283CC65F31300FE0EEEA87E97CC39F74B2929847D1A7B5DC2C6281CB8FCB30AEB605155ACF0C3EBE0BFD5E652CCE11C7D59CF89929F2DAE619CB21C7F4E148436951E1EAC41508A51DE2835103892D0FEE9913E82C673470F764CED04F4A3F7512E7BCB38C11685ED5A03D9D3F82977F3D36D53E0E3116D424CFA246E8954136DA20B666C4CBE532CF177A48AD1F6BBA626240D032569FA4CC7158DDD94E800213FC2072A24389757CD97B3CF511D240DC8171593C8F1BCEE73D32A13C894BE1C3F03FC2A3098579D3E0F45F64C3E9E9846F11B3436664B5D591E9F4EF0F96A00AC6CA793215865404C9AB0424E3F5488B5A3AA87D57D90CC56ED5B9C647A38CBD41968AF759961F9B8D8048E1E93AD063199B8D75875578AA8E8409D7837B61C6D56B82A690E08BDF24FAE143BDC4FA8314881ACFCD6EE66F8158F3E446527CE883E1391901DD192B6859625FF2F77B2E22EE9CC3E97FBD4455DF2F4A772FB2962F9A3BCFF7ADA30D07BB53BB2B3C1F60AA4FBE541D2A02457342666FB560906BCD21C701488E6D4548505776190CB0CC79E1B9D1014D70ECE5A9E104608E7940C570960ACA0C6CAFBA80D0FB95E99B52D2E9FDAFE92A6786F14EF387AFF54F3607908408BFC1C31FDE0FFF8C75D1DF431F5275941F665005DD89F6E3F48CEFFD3746E33F63D0F616BA559A292095690B59B907907A41D69281CC90E3A2D68D66E74D44FF7A36AD370693883B9B6440A3674F94B42CC594CB9A56D37FA1C4D76F9A7DDA71D8CEA31D1397678B33A0ECCFE5095FCC98A8B6D30A3DE7EF1963D68A4B15EE45060FDA7EA3DBA42C936CBCDA2C99FBAD98F12DE1A4523A12F2F8D0C7818A1C5B6377A8499AE837EB0B233D98470234F3EAD29C2DAB368CF5463151BCB266DEF496D8E");
    byte[] publicRSA = Forms.hexStringToByte("3082010902820100EED2CF3C2E3624D65718E0F1CCE74F3D5CB93B4C1B3737161E7154AE0027FD911A901B040040FAE50F586AC6E3CC653ADA75F7CF7A36E18C3D662AA81AE25D05CBE5486ED432BCC3925324ADE4592E4577DC004503BC05F9D67AFCFAB58D14E294A8AC3979AE8DC0319F8E180BF948E9E3BE9527546999120EB88DEEF36EE5C589E00421B309145377730AD99337FDB8A1F01F191ED7F761854B86BAAA61253DF821B2C72FDD138134A848278FF94B660C47DEF24EB23163919F199D1637FC1B4E2AB0683CB17B07706D5D307F17D6A8916EAA92AB80B07E9F723C5A96AB382B90F4718E18A620556D927F5DA9529C22D5C701B8B1BB7836D351A815A69116110203010001");
    byte[] publicR77 = Forms.hexStringToByte("3082010A0282010100A636C484374F9F039EB4318952B6BA5ABBE096F2B37B12DBC71A09F3B7BEEB83EB4A4BBBBDBBCC9332168E336981C919EF8BB734B3671DFEDCB79459401F95DDAA4EACECB36599451F9F77F5B01BF6B6AA1F94DE8BE5ED8B7BD52CA94929F7B0D3E8F5FDAFA322538AE32F89D7E3C1E4203120EDE6F213A3848F8ECF9E6836BE369A4658B6EB14D2FD3681488A3207CE0A5A9088011B2DA893C7F2C674843BB5254C30CB67D9C8182FEF284BB5CD8A239D6411EA199AD8B93EBE3442716FDAB44FB3932248C076C8794725CEEB5B76674B2B6DC605DC0F9835C6CCBBE4807A4F925065E02C65CAFE2D80A275BF5D096D2E07BA9ED5A75A10D425B03B84BB57990203010001");
    @Test
    public void RSApriSign() throws TAException, IOException {
        byte[] bytes = api.RSAPriKeySign(privateRSA,TACryptConst.PADDING_MODE_NO, 4, 0,
                0, 0, Forms.hexStringToByte("9ECA5459BA0B5CA0CCBB2A01EA05DE319C9E97DF730F0E2A55E9DC2B6FFA85CE"));
        System.out.println("Signature result: " + Forms.byteToHexString(bytes));
        boolean b = api.RSAPubVerify(publicRSA,TACryptConst.PADDING_MODE_PKCS15, TACryptConst.DIGEST_ALG_SHA256, 0,
                0, 0, bytes, Forms.hexStringToByte("9ECA5459BA0B5CA0CCBB2A01EA05DE319C9E97DF730F0E2A55E9DC2B6FFA85CE"));
        System.out.println("Signature verification result: " + 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("Signature result: " + 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("Signature verification result: " + b);
    }

    /**
     * RSA encryption and decryption
     */
    @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("Public key encryption result: " + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.RSAPriDecData(11, 1, TACryptConst.DIGEST_ALG_SHA256,new byte[0], bytes);
        System.out.println("Private key decryption result: " + Forms.byteToHexString(bytes1));
    }

    /**
     * Decrypt using an RSA private key protected by a protection key
     */
    @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("BFA03DB9BD0A4DE4809B59B04BF663E8E541B0CF0017E0337342B8F7CDEB210C86429D87A51A7E2B4ED760C4BB49A1AD1DE0353B3204D39C8F6FF9DB789C8DEDCDD84012DDB532F3E4554F0C85DCEF1C7241C98888F9CC57D04E902ABD2F422884235FD9E0A80116771AC436ED1EDE46CF272FD1DD4D3A5174D2D178D9A21F3D"));
        System.out.println("Plaintext after decryption: " + Forms.byteToHexString(bytes));
    }

    /**
     * Sign using an RSA private key protected by a protection key
     */
    @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("Signature result: " + 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("Signature verification result: " + b);
    }

    /**
     * Convert RSA asymmetric key encryption from protection key 1 to protection key 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("Item " + i + ": " + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * Import a symmetric key protected by an RSA asymmetric key
     */
    @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("5C59EBCD0A48E51038853E490C76AD83122964E3AA3EAB660966F67DE56722D02E3B477D257BDDB90CA2F901254544933BD0852BCF6E466CE91813AACF8A4AD2C65F2B78888AE249A948BCDCF3E2D0CDCC70DC3BA9445D3237B6D56A701D17E95576AD4FCF0A1D20DC5A0AAB878DADC04903CCE5B3D06219FDB4497905FBEA9E"), "916-zjl".getBytes());
        System.out.println("LMK-encrypted symmetric key: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Verification value of symmetric key: " + Forms.byteToHexString(bytes.get(1)));
    }

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

    /**
     * Generate an SM2/ECC key pair with the private key encrypted by a protection key
     */
    @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("Public key in DER encoding: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Private key encrypted by LMK: " + Forms.byteToHexString(bytes.get(1)));
        System.out.println("Private key ciphertext encrypted by protection key: " + Forms.byteToHexString(bytes.get(2)));
        System.out.println("Asymmetric private key MAC: " + Forms.byteToHexString(bytes.get(3)));
        System.out.println("Tags: " + Forms.byteToHexString(bytes.get(4)));

    }

    /**
     * Generate an SM2 key pair with the private key encrypted by LMK
     */
    @Test
    public void generateSM2Key() throws TAException {
        ArrayList<byte[]> bytes = api.genSM2Key();
        System.out.println("Public key in DER encoding: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Private key encrypted by LMK: " + Forms.byteToHexString(bytes.get(1)));
    }

    /**
     * Generate an ECC key pair with the private key encrypted by LMK
     */
    @Test
    public void generateECCKey() throws TAException {
        ArrayList<byte[]> bytes = api.genECCKey(0x0007);
        System.out.println("Public key in DER encoding: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Private key encrypted by LMK: " + Forms.byteToHexString(bytes.get(1)));
 
    }

    byte[] data = Forms.hexStringToByte("20D90A83A4654FB89AD97E7FF9B178BAA58E12CE8E5C16DE0371B374F76DEFA5");

    /**
     * ECC sign and verify
     */
    @Test
    public void ECCPrivateKeySign() throws TAException {

        byte[] bytes = api.priKeySign(0x0007, Forms.hexStringToByteArray("61971383CD4D760CF77CCA48C187592ACE2375BB54CA886724EE230AE7D94C1C935F18B4CCCFBF3A"), data);
        System.out.println("ECC signature result: " + Forms.byteToHexString(bytes));

        boolean b = api.pubKeyVerify(0x0007, Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF5501822D03420004E6BFD64E16F9FDE831FC2483A703F32D2925C126C435CF4FF0BC0187351E34F627E3421ACA51CB99CD452FA11B5B6BBB4AA31C2DBCC696FC57C8F9F8F01948FE"), data, bytes);
        System.out.println("ECC signature verification result: " + b);
    }

    /**
     * SM2 sign and verify
     */
    @Test
    public void TestSm2() throws TAException {
        byte[] bytes = api.priKeySign(0x0007, privateKeySM2, sm3);
        System.out.println("Signature result: " + Forms.byteToHexString(bytes));
        boolean b = api.pubKeyVerify(0x0007, privateKeySM2DER, sm3, bytes);
        System.out.println("Signature verification result: " +  b);
    }


    @Test
    public void SM2Sign() throws TAException {
        byte[] baInData = "2222222222222222".getBytes();
        //7. Calculate SM3 digest
        System.out.println("Data digest: SM3");
        String sAlg = "SM3";
        byte[] baUserId = new byte[0];
        byte[] baPubKey = Forms.hexStringToByteArray("3059301306072A8648CE3D020106082A811CCF5501822D03420004A45246028D1FE13EAA9BAE7F47929AE6F9993CEEFEA16EB1358526C8D85277BD63F2EB9A1AD40BEEE37267F8F1F97E67BCE29A4E1CCAB0979A1E85F81010E042");
        byte[] baHashInitRes = api.HashInit(sAlg, baUserId, baPubKey);
        byte[] baHashUpdateRes = api.HashUpdate(baHashInitRes, baInData);
        byte[] baHashSm3 = api.HashFinalize(baHashUpdateRes);
        System.out.println(String.format("Data digest: %s", Forms.byteToHexString(baHashSm3)));


        //8. Asymmetric key sign and verify
        System.out.println("Asymmetric sign and verify: SM2");

        int iCurveId = 0x0007;
        System.out.println(String.format("Original data (hash value): %s", Forms.byteToHexString(baHashSm3)));

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


    byte[] sm2 = Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF5501822D03420004E70CB95894768A69B5A184C17B31251710B2B870BB99E0BE150EA2FAF1F4CEECF6B48055A4C790CDE94A1B179CC12A39A856755F6677E87905BD903987425AF3");

    byte[] sm2PrivateKey = Forms.hexStringToByte("4F23C664B68C8A38B31F52727C856211D8D21B1AC76F300D2CD027E5AFD566976CEA234A749F031D");

    /**
     * SM2 encryption and decryption
     */
    @Test
    public void TestSM2EncAndDec() throws TAException {
        byte[] bytes = api.SM2PubKeyEnc(888, Forms.hexStringToByte("11111111111111111111111111111111"));
        System.out.println("Encryption result: " + Forms.byteToHexString(bytes));

        byte[] bytes1 = api.SM2PriKeyDec(888, bytes);
        System.out.println("Decryption result: " + Forms.byteToHexString(bytes1));
    }



    byte[] sm2Key = Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF5501822D03420004E70CB95894768A69B5A184C17B31251710B2B870BB99E0BE150EA2FAF1F4CEECF6B48055A4C790CDE94A1B179CC12A39A856755F6677E87905BD903987425AF3");
    byte[] sm2Cipher = Forms.hexStringToByte("83E260209C09CC3F010349772852D7CD2C3C77DAEBA956791067754DA7FCFD8880E68AC28BFFF0F3");
    byte[] sm2CipherMAC = Forms.hexStringToByte("8184BE3669B2D12AEB673814E59E7700");
    byte[] sm2CipherTag = Forms.hexStringToByte("8FD638CA4D7640BDE213F5777253D192");
    byte[] sm2PriKey = Forms.hexStringToByte("4F23C664B68C8A38B31F52727C856211D8D21B1AC76F300D2CD027E5AFD566976CEA234A749F031D");


    /**
     * Decrypt using an ECC/SM2 private key protected by a protection key
     */
    @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("E9C17D82604F992BB3AB8FE0F766441DACC05EB779D1D1CC9C5FEFF671739A87274713242CBBA04161C3994EA264C30D82BB6DAF8E688D3BADC8768A18226D8EAEB984E5EA739C2E8792921F02AA612F5AB732FACEC8316B880499E6E70260333E9F29CEBCF3F8E10C151F79445276F6"));
        System.out.println("Plaintext after decryption: " + Forms.byteToHexString(bytes));
    }

    /**
     * Sign using an ECC/SM2 private key protected by a protection key
     */
    @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("20D90A83A4654FB89AD97E7FF9B178BAA58E12CE8E5C16DE0371B374F76DEFA5"));
        System.out.println("ECC/SM2 private key signature result (private key protected by protection key): " + Forms.byteToHexString(bytes));

        boolean b = api.pubKeyVerify(7, sm2Key, Forms.hexStringToByteArray("20D90A83A4654FB89AD97E7FF9B178BAA58E12CE8E5C16DE0371B374F76DEFA5"), bytes);
        System.out.println("ECC/SM2 public key signature verification result (private key protected by protection key): " + b);
    }

    /**
     * Import a symmetric key protected by an SM2 asymmetric key
     */
    @Test
    public void SM2ImplKEK() throws TAException {
        ArrayList<byte[]> bytes = api.SM2ImplKEK(sm2PriKey, 300, TACryptConst.KEY_ALG_SM4, Forms.hexStringToByteArray("9A9161F87BCBD3E9BC8866B8706E8F75B682DA2712E7E32A5D0E4867700D8233284BF4EA98E352BE74817D240D92347F969809BA54626192102086000756E2CFD98A3CC8923513B3BF72FA33B39CB999E15613440F2DAD9AE786E3D73349D78FA7915B3CB633EFD9A88E638D93297934"), "914-zjl".getBytes());
        System.out.println("LMK-encrypted symmetric key: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Verification value of symmetric key: " + Forms.byteToHexString(bytes.get(1)));
    }

    /**
     * SM2/ECC asymmetric key conversion encryption
     */
    @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("Item " + i + ": " + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * Digest operation and pad digest data
     */
    @Test
    public void testGenHash() throws TAException {
        byte[] hash = genHash();
        System.out.println("Digest result: " + Forms.byteToHexString(hash));

        // Verify correct digest result
        String string = "704423DF78242B08E821F7F8FA05A5325AA1BD842BE4EB9827C765DFFF434C1A";

        byte[] bytes3 = genHash();
        System.out.println("Verification result: " + Arrays.equals(Forms.hexStringToByteArray(string),bytes3));

        String wrongHash = "669523DF78242B08E821F7F8FA05A5325AA1KD842BE4EB9827C765DFFF434C1A";

        System.out.println("Incorrect verification result: " + 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;
    }


    /**
     * Generate a random number
     */
    @Test
    public void genRandom() throws TAException {
        String s = api.genRandom(15);
        System.out.println(s);
    }

    /**
     * Get HSM status
     */
    @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("Key ciphertext encrypted by protection key: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("MAC output when generating MAC: " + Forms.byteToHexString(bytes.get(1)));
        System.out.println("Tags: " + Forms.byteToHexString(bytes.get(2)));
        System.out.println("Key verification value: " + Forms.byteToHexString(bytes.get(3)));
    }

    /**
     * Convert other encrypted keys to LMK-encrypted keys
     * @throws TAException
     */
    @Test
    public void otherEncKeyToLMLEncKey() throws TAException {
        ArrayList<byte[]> bytes = api.otherEncKeyToLMLEncKey(0, 7, 6,
                Forms.hexStringToByteArray("00000000000000000000000000000000"),
                Forms.hexStringToByteArray("00000000000000000000000000000000"),
                Forms.hexStringToByteArray("71802E75BD4D99E90996A9B9DA6616E9"),
                0,  Forms.hexStringToByteArray("B36847D6E86EAB69E4EEB65558A2626C"),
                new byte[0], new byte[0], 5, -1,-1, new byte[0], 0, 7,
                Forms.hexStringToByte("994056800038295C09C7F45977D291AA"));
        System.out.println("============= Protection key is a symmetric key =============");
        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("7C78EAFE26890D48096AB8141B1D5890BF1921DD899664A7E224C05DC30A7392CAA4BB0E518CBE5721DAC409F85B736A1DAEC40FAB410CA007C114574BAEAD1227560F1D2AE148884814872F0305F821F7245329ADED546F44C52C8F49EAC46647650D9B983224E9E005CFCAA88B019D"));

        System.out.println("============= Protection key is an ECC key =============");
        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("6149EE02F14EE6420BC2B462003CCCE2413CE4911F5C36F720DD123DA9A432EEA17C534A8662F9B1E813C8A5FA929E9A06AC2CFDB2AAB68E66A58C9A4E0C76AF5126785160A665C23F22309ECBF48B8BAFA8BE9D41F334852649D5D204937A4EDA3B0A9B1A7B3054E1D9AE3BA2173028C3A0E2CE400522E06DCBAB44213A85B668764EC33EE71D372F5A904252A539AA"));

        System.out.println("============= Protection key is an RSA key =============");
        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("Digital envelope encapsulation result: " + Forms.byteToHexString(bytes));
        byte[] bytes1 = api.enveopDec(sm2PriKey, bytes);
        System.out.println("Digital envelope decapsulation result: " + new String(bytes1));
    }

    /**
     * Symmetric key conversion encryption & asymmetric conversion encryption
     */
    @Test
    public void symmetryConversionEncryptionAES256() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_AES256,
                Forms.hexStringToByteArray("5BD90CDDBC8645B41AB901DDD8EFE9956755D9560C9FAEB096B6E52CC003D04F"),
                Forms.hexStringToByteArray("F8B6B9D8BB7E4FD3"),
                TACryptConst.KEY_TYPE_SYMMETRY,
                TACryptConst.KEY_ALG_AES256,
                Forms.hexStringToByteArray("CFE8E3D44F753D3F065962462AA9C9E1FE295BC835E4A1FB88EF70B54E65E232"), b,
                Forms.hexStringToByteArray("8F2440B22092CA8757D8D807A832A19F"), TACryptConst.ENC_MODE_GCM, b, new byte[22],
                Forms.hexStringToByteArray("B5294D591009E19E780774B61BA48FA4"),
                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("Item " + i + ": " + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * Symmetric key conversion encryption & asymmetric conversion encryption
     */
    @Test
    public void symmetryConversionEncryption() throws TAException {
        ArrayList<byte[]> bytes = api.conversionEncryption(0, TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("CBDCCE33784FA93FBE0B3BAA46CF3557"),
                Forms.hexStringToByteArray("F6684895E1ABC2AD"),
                0,TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("6BFC84C39CB9277C06C7FA2A30C912A1"), b,
                Forms.hexStringToByteArray("AB75C62580061710B39327B45881F589"), TACryptConst.ENC_MODE_GCM,
                b, new byte[0], Forms.hexStringToByteArray("4A501743FA4B906244A0A8705192C1C8"),0,
                TACryptConst.KEY_ALG_SM4,
                Forms.hexStringToByteArray("CBDCCE33784FA93FBE0B3BAA46CF3557"),
                Forms.hexStringToByteArray("F6684895E1ABC2AD"), b, TACryptConst.ENC_MODE_GCM, b, new byte[0]);
        for (int i = 0; i < bytes.size(); i++) {
            System.out.println("Item " + i + ": " + Forms.byteToHexString(bytes.get(i)));
        }
    }

    /**
     * Symmetric key conversion encryption & asymmetric conversion encryption
     */
    @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("83E260209C09CC3FEFDEFE7F4B620157A3F25E0B3098A4677DAF3A8E9DC327A17AEB2C8919E1E4CF"), b,
                Forms.hexStringToByteArray("E60EFC48823B17C51F68D0EB622298FB"),
                TACryptConst.ENC_MODE_GCM, b, new byte[16],
                Forms.hexStringToByteArray("B200ED220D49D855EC4438649057EB02"),
                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("Item " + i + ": " + Forms.byteToHexString(bytes.get(i)));
        }
    }


    /**
     * Import an asymmetric CMK protected by a symmetric CMK
     */
    @Test
    public void importCMKByCMK() throws TAException {
        ArrayList<byte[]> bytes = api.importCMKByCMK("zjlimpl".getBytes(), 7,
                6,  // DomainKey encryption algorithm identifier for CMK encryption
                new byte[16],     // IV data used for ECB mode decryption
                new byte[16],      // Authentication data used for GCM mode decryption
                Forms.hexStringToByteArray("566F7CE9E52CCA87FF02D7A7667E3F7C"), // MAC value used for GCM mode decryption
                Forms.hexStringToByteArray("DA23B170CEA626F4C772B3F2AE2CCA97"),// Key ciphertext
                Forms.hexStringToByteArray("7192C7C6F1EAAB72BFE8A51BA9256C87"),  // GCM tags
                6, // Protection key encryption mode
                new byte[16],// Protection key IV
                new byte[16], // Authentication data AAD
                Forms.hexStringToByteArray("8DE9DFEE4BE10827C1C08A38BDD8A92F"), // Tags
                5,// Protection key encryption padding mode
                12, // Session key type
                7,  // Algorithm identifier for session CMK asymmetric key
                Forms.hexStringToByteArray("420B9FE23A2B162F3C4574919E9EBD44040F7C5338CDE0C8311C88495D2F3604E9AFC80B18990EF5C6F3A93AB80B41458311EA9F9A1890752427E24F5062AD4A"),// Session private key ciphertext
                "32-1".getBytes(),// Session DomainKey tag
                6,// Session DomainKey encryption algorithm identifier for CMK encryption
                new byte[16],// Session encryption context (IV data used for non-ECB mode encryption)
                new byte[16]// Session authentication context data (authentication data used for GCM mode encryption)
        );
        System.out.println("Key ciphertext encrypted by protection key: " + 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("Key verification value: " + Forms.byteToHexString(bytes.get(3)));
    }

    @Test
    public void testData() throws TAException {
        // Generate a symmetric key and protect it with a protection key
        ArrayList<byte[]> bytes = api.proGenSymmKey(603,
                -1, null, TACryptConst.KEY_ALG_SM4, b,
                TACryptConst.ENC_MODE_GCM,b, b);
        System.out.println("LMK-encrypted session key ciphertext: " + Forms.byteToHexString(bytes.get(0)));
        System.out.println("Verification value of session key: " + Forms.byteToHexString(bytes.get(1)));
        System.out.println("Session key ciphertext encrypted by protection key: " + Forms.byteToHexString(bytes.get(2)));
        System.out.println("MAC value of session key: " + Forms.byteToHexString(bytes.get(3)));
        System.out.println("Tags: " + Forms.byteToHexString(bytes.get(4)));
        System.out.println("-------------------------------------------------");
        // Encrypt data using a symmetric key protected by a protection key
        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("0000000000000000000000000000000000000000000000000000000000000000E43101353F49C7164DAE6C691FC25CD494D9A28D0F6C4B51F3BB9DC85ADDBE09"), new byte[16], new byte[16]);
        System.out.println("Ciphertext: " + 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("3076301006072A8648CE3D020106052B8104002203620004491995797F5C99C17726E4841BE04D333C5BD3511819720388BD7264112905D3073FC25743EED2AE7D1448C2D2D9E014C640FC395CF19650A61D0ABC616D521050C45645477442F9BF8BE9BF81EAD69CDA6C63FCF5244A383C57DDB62465E63B"));
//        System.out.println("secp384r1 agreement result: " + Forms.byteToHexString(bytes));
//        byte[] bytes1 = api.agreementKey(0x0007, 3, 6, Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF5501822D03420004AC3DC24CE9883F26278E97A04D5409AA2A94D57FCE84E7630F4E46CFBED036A6B89791DF9A3DF50D67073CF246FC3406337B50E987F2AC3943D2FF5C7ECAD197"));
//        System.out.println("0x000agreement result: " + Forms.byteToHexString(bytes1));
//        byte[] bytes2 = api.agreementKey(0x0007, 3, Forms.hexStringToByte("E59842CEEC68775E6AD78C7276AD2ADE0E27405E8B60FE02F7DF23E08F7F6B8D"), Forms.hexStringToByte("3059301306072A8648CE3D020106082A811CCF5501822D034200040EF69FB0C3739C3FDC16499AB96985EAD5CBEB4178A985A8FC10145979C315A5519C50B972EB19EA77A6AB74F345688B8458F1015885FCE435A4E3679DE0E34F"));
//        System.out.println("0x0007 external private key plaintext agreement result: " + Forms.byteToHexString(bytes2));
//        byte[] bytes3 = api.agreementKey(0x039B, 0, 5, Forms.hexStringToByte("304A301406072A8648CE3D020106092B24030302080101030332000448D5FAD9CD434E60EF661B65289867B395461D868F7D34BABEEB5A20F7DF5543091DD740DD3780B5EBEF631615571ADC"));
//        System.out.println("0x039B agreement result: " + Forms.byteToHexString(bytes3));
        byte[] bytesA = api.agreementKey(0x019F, 3, 13, Forms.hexStringToByte("3059301306072A8648CE3D020106082A8648CE3D030107034200048D912010F06A7D4B5062F6DC192EEDC8C88FCB2D2830AB8573F0FB30532041D0788F227558F1DA9AC8CDF5E7FA72C9931FA90EE06B3CE07E13A7845A05BA7C73"));
        System.out.println(bytesA.length);
        System.out.println("0x0007 agreement result: " + Forms.byteToHexString(bytesA));
        byte[] bytesB = api.agreementKey(0x019F, 3, 15, Forms.hexStringToByte("3059301306072A8648CE3D020106082A8648CE3D0301070342000481022BD6C8FFBBD2EC4B5A53F7000920D1581C0BC17B4C781627894B0979FFCA115C85C7AB0964E53872FBF0511FF6E7661CF94B7D82C8BF78D211B1FA73F271"));
        System.out.println("0x0007 agreement result: " + Forms.byteToHexString(bytesB));

    }

    /**
     * Get symmetric key details by key index
     */
    @Test
    public void getKeyInfo() throws TAException {
        String[] keyInfo = api.getKeyInfo(66);
        System.out.println(keyInfo[0]);
    }
    /**
     * Get RSA public key by key index
     */
    @Test
    public void exportRSAPublicKey() throws TAException, IOException {
        ArrayList<byte[]> keyInfo = api.exportRSAPublicKey(77,0);
        System.out.println(Forms.byteToHexString(keyInfo.get(0)));
    }
    /**
     * Get ECC public key by key index
     */
    @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("Generate and save RSA key pair: " + (b ? "succeeded":"failed"));
        boolean b1 = api.generateECCKey(0x019F, 8);
        System.out.println("Generate and save ECC key pair: " + (b1 ? "succeeded":"failed"));

    }


}