1. 国密sm2

椭圆曲线:prime256v1

国产公钥密码学算法SM2使用的椭圆曲线称为sm2p256v1

SM1是采用硬件实现;

SM2是非对称加密算法;

SM3是摘要算法;

SM4是对称加密算法;

2. 非对称加密的基本步骤

客户用他们的 私钥 把明文签名

客户把 明文+签名 用我们的公钥加密

客户发给我们

我们用我们的 私钥 解密密文,得到 明文+签名

我们用 客户的公钥 验证 明文签名

签名正确 后入库。

3. Groovy实例代码

import org.bouncycastle.crypto.CipherParameters
import org.bouncycastle.crypto.engines.SM2Engine
import org.bouncycastle.crypto.params.ECPrivateKeyParameters
import org.bouncycastle.crypto.params.ECPublicKeyParameters
import org.bouncycastle.crypto.params.ParametersWithRandom
import org.bouncycastle.crypto.signers.SM2Signer
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.PrivateKey
import java.security.PublicKey
import java.security.SecureRandom
import java.security.spec.ECGenParameterSpec
import java.security.spec.KeySpec
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
/**
 * SM2算法生成密钥对
 *
 * @return 密钥对信息
 */
 
static KeyPair generateSm2KeyPair() {
 
    try {
 
        final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1")
 
        final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider())
 
        SecureRandom random = new SecureRandom()
 
        kpg.initialize(sm2Spec, random)
 
        KeyPair keyPair = kpg.generateKeyPair()
 
        return keyPair
 
    } catch (Exception e) {
 
        println(e.message)
 
        throw new RuntimeException("Failed to generate sm2keypair");
 
    }
 
}
/**
 
 * sm2公钥加密
 
 *
 
 * @param data
 
 * @param key
 
 * @return
 
 * @throws Exception
 
 */
 
static byte[] encrypt(byte[] data, byte[] key) throws Exception {
 
    KeySpec keySpec = new X509EncodedKeySpec(key)
 
    PublicKey publicKey = KeyFactory.getInstance("EC", new BouncyCastleProvider()).generatePublic(keySpec)
 
    ECPublicKeyParameters parameters = (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey)
 
    CipherParameters pubKeyParameters = new ParametersWithRandom(parameters)
 
    SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C2C3)
 
    engine.init(true, pubKeyParameters)
 
    return engine.processBlock(data, 0, data.length)
 
}
/**
 
 * sm2私钥解密
 
 * @param data
 
 * @param key
 
 * @return
 
 * @throws Exception
 
 */
 
static byte[] decrypt(byte[] data, byte[] key) throws Exception {
 
    KeySpec keySpec = new PKCS8EncodedKeySpec(key)
 
    KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider())
 
    PrivateKey privateKey = keyFactory.generatePrivate(keySpec)
 
    CipherParameters privateKeyParameters = ECUtil.generatePrivateKeyParameter(privateKey)
 
    SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C2C3)
 
    engine.init(false, privateKeyParameters)
 
    byte[] byteDate = engine.processBlock(data, 0, data.length)
 
    return byteDate
 
}
/**
 
 * 私钥签名
 
 * @param data
 
 * @param key
 
 * @return
 
 * @throws Exception
 
 */
 
static byte[] sign(byte[] data, byte[] key) throws Exception {
 
    SM2Signer signer = new SM2Signer()
 
    KeySpec keySpec = new PKCS8EncodedKeySpec(key)
 
    KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider())
 
    PrivateKey privateKey = keyFactory.generatePrivate(keySpec)
 
    ECPrivateKeyParameters keyParameters = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey)
 
    CipherParameters param = new ParametersWithRandom(keyParameters)
 
    signer.init(true, param)
 
    signer.update(data, 0, data.length)
 
    return signer.generateSignature()
 
}
/**
 
 * 公钥验签
 
 * @param data
 
 * @param sign
 
 * @param key
 
 * @return
 
 * @throws Exception
 
 */
 
static boolean verify(byte[] data, byte[] sign, byte[] key) throws Exception {
 
    SM2Signer signer = new SM2Signer()
 
    KeySpec keySpec = new X509EncodedKeySpec(key)
 
    PublicKey publicKey = KeyFactory.getInstance("EC", new BouncyCastleProvider()).generatePublic(keySpec)
 
    CipherParameters param = ECUtil.generatePublicKeyParameter(publicKey)
 
    signer.init(false, param)
 
    signer.update(data, 0, data.length)
 
    return signer.verifySignature(sign)
 
}
 
static void main(String[] args) {
 
    println "Hello world!"
 
    KeyPair keyPair = generateSm2KeyPair()
 
    String publicKey = Base64.encoder.encodeToString(keyPair.getPublic().getEncoded())
 
    String privateKey = Base64.encoder.encodeToString(keyPair.getPrivate().getEncoded())
 
    println("sm2_PublicKey: " + publicKey)
 
    println("sm2_PrivateKey: " + privateKey)
 
    String plaintext = "Something need to encrypt"
 
    // 客户用他们的 私钥 把明文签名
 
    // 客户把 明文+签名 用我们的公钥加密
 
    // 客户发给我们
 
    // 我们用我们的 私钥 解密密文,得到 明文+签名
 
    // 我们用 客户的公钥 验证 明文签名
 
    // 签名正确 后入库。
 
    // 明文使用私钥签名,签名转base64
 
    String signature = Base64.encoder.encodeToString((sign(plaintext.getBytes("utf-8"), keyPair.getPrivate().getEncoded())))
 
    println("signature: " + signature)
 
    // 公钥加密,密文转base64
 
    String ciphertext = Base64.encoder.encodeToString(encrypt(plaintext.getBytes("utf-8"), Base64.decoder.decode(publicKey)))
 
    println("ciphertext: " + ciphertext)
 
    // base64 转密文,私钥解密
 
    plaintext = new String(decrypt(Base64.decoder.decode(ciphertext), Base64.decoder.decode(privateKey)), "utf-8")
 
    println("plaintext: " + plaintext)
 
    // base64 转签名,公钥验证 明文签名
 
    boolean result = verify(plaintext.getBytes("utf-8"), Base64.decoder.decode(signature), keyPair.getPublic().getEncoded())
 
    println("verify result: " + result)
 
}