All Products
Search
Document Center

ID Verification:SM2 encryption

Last Updated:Oct 23, 2026

Some ID Verification API operations support using SM2 encryption to transmit personal information, such as your name and ID card number, in an authentication request. This document explains how to enable SM2 parameter encryption.

SM2 public key

02cd77e007bdc86eeaf9a479ba7a2c22bc0a517ccb3a6975c3f94b4ac93347dea6

Java example

Add the Maven dependency

<dependency>
  <groupId>org.bouncycastle</groupId>
  <artifactId>bcprov-jdk15on</artifactId>
  <version>1.65</version>
</dependency>

Sample code

Important

The Cipher object is stateful and not thread-safe. Do not share a single instance across multiple threads.

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.util.Base64;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;


public class SM2EncryptUtil {

    private static final String publicKey = "02cd77e007bdc86eeaf9a479ba7a2c22bc0a517ccb3a6975c3f94b4ac93347dea6";

    // Adjust based on your actual usage.
    private static final int maxPoolSize = 20;

    private static final BlockingQueue<Cipher> pool = new LinkedBlockingDeque<>(maxPoolSize);

    static {
        try {
            // Initialize the pool.
            for (int i = 0; i < maxPoolSize; i++) {
                Cipher newCipher = createCipher();
                pool.put(newCipher);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * Encrypts data using SM2.
     * @param content2Encrypt The plaintext to encrypt.
     * @return The Base64-encoded ciphertext.
     */
    public static String encrypt(String content2Encrypt) {
        Cipher cipher = null;
        try {
            cipher = borrow();
            return Base64.getEncoder().encodeToString(cipher.doFinal(content2Encrypt.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (cipher != null) {
                release(cipher);
            }
        }
    }

    private static Cipher createCipher() throws Exception {
        BouncyCastleProvider provider = new BouncyCastleProvider();
        // Get SM2 parameters.
        X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
        // Elliptic curve parameter specification.
        ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH());
        // Convert the hexadecimal public key string to an elliptic curve point.
        ECPoint ecPoint = parameters.getCurve().decodePoint(Hex.decode(publicKey));
        // Get the elliptic curve key factory.
        KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
        // Convert the elliptic curve point to a public key object.
        BCECPublicKey bcecPublicKey = (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
        // Get the SM2 cipher.
        Cipher cipher = Cipher.getInstance("SM2", provider);
        // Initialize the cipher for encryption mode.
        cipher.init(Cipher.ENCRYPT_MODE, bcecPublicKey);
        return cipher;
    }

    private static Cipher borrow() throws InterruptedException {
        // The thread will block until a Cipher is available.
        return pool.take();
    }

    private static void release(Cipher cipher) {
        // Prevent duplicate additions.
        if (cipher != null && !pool.contains(cipher)) {
            // Return the Cipher to the pool.
            pool.offer(cipher);
        }
    }

}