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