加密和解密使用相同的秘钥,常见算法有DES、TDES、AES、SM4、RC2/4
加密和解密使用不同的秘钥,公钥加密私钥解密,私钥加密公钥解密。常见算法有RSA、SM2、ECC
类似于hash,不可逆。常见的信息摘要算法有:MD2/4/5、SHA1/SHA224/SHA256/SHA384、SM3算法、MAC算法等
【数字签名】主要解决了两个核心问题:发送的消息是完整的,未被篡改的;接收的消息一定就是对应发送者发送的,别人无法仿制。前者体现的是数据的完整性,后者体现的是数据的不可抵赖性
数字签名的应用公式如下所示,其中M表示消息原文,S表示数字签名,P表示非对称算法的私钥运算,D表示信息摘要算法的运算。
P(D(M [with any length])) = S [with fixed length]
具体来说,发送方产生一个数据签名,需要经过以下几个步骤:
经过以上的步骤后,发送方就成功将信息原文和对应的数字签名,传递给了接收方;剩余的事,就是接收方对数据的验签操作。
接收方收到发送方发送的数据报文(信息原文+数字签名)后,需要经历以下步骤来完成对报文消息的验签操作:
首先,对数据报文进行分解,提取出信息原文部分和数字签名部分;
与产生数字签名流程一样,使用相同的信息摘要算法对信息原文做摘要运算,得出消息原文的摘要D1;
与产生数字签名流程相反,使用【非对称加密算法】中签名私钥对应的公钥对数字签名部分做解密 运算,解密后得到原始发送方发送的经填充后的摘要D2;
与产生数字签名流程相反,使用相同的数据填充标准对摘要D2做去填充操作,得到原始消息的附带的摘要D3;
比较D3和D1;如果两者相等,则表示对数字签名的验签是OK的,消息原文的数据是可信任的;反之,若D3不等于D1,则可以认为消息原文是不可信任的,数字签名中的【完整性】和【不可抵赖性】可能遭到了破坏;我们应该摒弃信息原文。
数字签名算法,就是使用RSA、MD5、SM2、SHA、SM3等非对称算法和信息摘要算法进行混搭组合。数字签名算法的基本表示格式为:xxxWithYYYEncryption,其中xxx表示信息摘要算法,yyy表示非对称加密算法。常见有的以下几种:
private static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // 秘钥长度为 128 位
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
/**
* 二进制byte[]转十六进制string
*/
public static String byteToHexString(byte[] bytes){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < bytes.length; i++) {
String strHex=Integer.toHexString(bytes[i]);
if(strHex.length() > 3){
sb.append(strHex.substring(6));
} else {
if(strHex.length() < 2){
sb.append("0" + strHex);
} else {
sb.append(strHex);
}
}
}
return sb.toString();
}
public static void main(String[] args) {
SecretKey secretKey = generateKey();
System.out.println(byteToHexString(secretKey.getEncoded()));
// b30957dc3e032f462866c917ff461088
}
// 使用hutool工具类
String aesKey = "b30957dc3e032f462866c917ff461088";
AES aes = SecureUtil.aes(aesKey.getBytes());
// 加密 encrpy = 9OqWLbnVeW/EsL6nevQfZQ==
String encrypt = aes.encryptBase64("你好");
// 解密 decrypt = 你好
String decrypt = aes.decryptStr(encrypt);
public static void genKeyPair() {
try {
// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024); // 设置密钥长度
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
String publicKeyStr = encoder.encodeToString(publicKey.getEncoded());
String privateKeyStr = encoder.encodeToString(privateKey.getEncoded());
// 打印公钥和私钥
System.out.println("公钥: " + publicKeyStr);
System.out.println("私钥: " + privateKeyStr);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
公钥: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpG4FQWx7NMG8DQF1VJNegLBxtsyGjvQGdoMDl0mXnZT7eU+DrJ0G5nKdKI+CWr+1tvSR/1dIblYsJK+M1cotSjUN9l4qraxnFha5Js1ldfxcTlJuWOBgWAWVJ+C3hZGkzAo8F+0CCtwij9dpLd+5kbHpdBd9Vh3V0WgiBY2M3nQIDAQAB
私钥: MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKkbgVBbHs0wbwNAXVUk16AsHG2zIaO9AZ2gwOXSZedlPt5T4OsnQbmcp0oj4Jav7W29JH/V0huViwkr4zVyi1KNQ32XiqtrGcWFrkmzWV1/FxOUm5Y4GBYBZUn4LeFkaTMCjwX7QIK3CKP12kt37mRsel0F31WHdXRaCIFjYzedAgMBAAECgYBOwnOwtC+dSzB46DJP5G/Utpaq9OH2+6FUA7mzkBFL+xiTvackfk0bIH29hwYjyF4hXRUxwKkxla2CoQEaNHX0Q6MX8LxdbEGzHypLuaB+gNQSbWT41AVLB+GmikLc6yaNKAbr6/rdGWCIYVzzf4XuH8FI4d0Zr2HV7vBeBCeV9QJBANu9LkT7+8VRI8fq/XE9gsMPQSO5gBqBprPvag32wwiP3Hsv/9BYs7BbvQASijgqzuoC74YJioPi66kyWS8XFjcCQQDFA2hCQjYHd6rzkjWBL707+scl4ddfIccl1YBE2fyM2djXzZEVkgqW4NILIZC3nMEvGoBiympdelnq7n0LQzbLAkEAwCosaZW4M3HnCbFenQZ+8VjIzZYvCn8xqxAHvlh7bWRqG6z5WVoJIoTHv2V3TPFa7FlO4Pg9E2OCVgA68CyPdwJAK9OVNuApysF5OxP0aReonhYshSXXVmdaOPVkwmxHvUGc9mzZcJX7WxMKRsWhvubVJthbZR6oSME2DYgeMwoxvwJAaxrWhkBVde5L1/nFaN19Yb4w82/z+lmjd2itjLybhe62Z1HqS86pc4rZKOaoegBeHT0omcCBMnGxYnYlYlgWpg==
package com.echo.java8.encipher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;
/**
* RSA签名,加解密处理核心文件,注意:密钥长度1024
*/
public class RSAHelper {
@SuppressWarnings("unused")
private static Logger LOGGER = LoggerFactory.getLogger(RSAHelper.class);
/*
* 签名算法
*/
public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/*
* 加密算法RSA
*/
public static final String KEY_ALGORITHM = "RSA";
/*
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/*
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
public static void genKeyPair() {
try {
// 生成RSA密钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024); // 设置密钥长度
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥和私钥
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
String publicKeyStr = encoder.encodeToString(publicKey.getEncoded());
String privateKeyStr = encoder.encodeToString(privateKey.getEncoded());
// 打印公钥和私钥
System.out.println("公钥: " + publicKeyStr);
System.out.println("私钥: " + privateKeyStr);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 签名字符串
*
* @param text 需要签名的字符串
* @param privateKey 私钥(BASE64编码)
* @param charset 编码格式
* @return 签名结果(BASE64编码)
* @throws Exception
*/
public static String sign(String text, String privateKey, String charset) throws Exception {
return sign(text, privateKey, charset, SIGNATURE_ALGORITHM);
}
public static String sign(String text, String privateKey, String charset,
String signatureAlgorithm) throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(signatureAlgorithm);
signature.initSign(privateK);
signature.update(getContentBytes(text, charset));
return Base64Utils.encodeToString(signature.sign());
} catch (Exception e) {
throw new Exception("RSA sign exception:" + e.getMessage());
}
}
/**
* 验签字符串
*
* @param text 需要签名的字符串
* @param sign 客户签名结果
* @param publicKey 公钥(BASE64编码)
* @param charset 编码格式
* @return 验签结果
* @throws Exception
*/
public static boolean verify(String text, String sign, String publicKey, String charset) throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory;
try {
keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK);
signature.update(getContentBytes(text, charset));
return signature.verify(Base64Utils.decodeFromString(sign));
} catch (Exception e) {
LOGGER.warn("RSA verify exception", e);
throw new Exception("RSA verify exception:" + e.getMessage());
}
}
/**
*
* 私钥解密
*
*
* @param encryptedData 已加密数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
public static String decryptByPublicKey(String encryptedData, String publicKey) throws Exception {
byte[] bytes = decryptByPublicKey(Base64Utils.decodeFromString(encryptedData), publicKey);
return new String(bytes);
}
/**
*
* 公钥解密
*
*
* @param encryptedData 已加密数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}
/**
*
* 公钥加密
*
*
* @param data 源数据
* @param publicKey 公钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey, String cipherArgs) throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = null;
if (Objects.isNull(cipherArgs)) {
cipher = Cipher.getInstance(keyFactory.getAlgorithm());
} else {
cipher = Cipher.getInstance(cipherArgs);
}
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
*
* 私钥加密
*
*
* @param data 源数据
* @param privateKey 私钥(BASE64编码)
* @return
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}
/**
* @param content
* @param charset
* @return
* @throws SignatureException
* @throws UnsupportedEncodingException
*/
private static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
public static void main(String[] args) throws Exception {
String text = "hello";
// rsaKeyGenerate("test");
String publicKeyStr = " MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLSTLXzr70geYHPD8uSLj8it7LvdZRz4hhYPHPQ6MvdJ9mLuooiXtXEwOgTWAIWtXXWL2EYoIo/AhaE3B91hpkIsXtdlotaMJSLv3vilZnd6nLISJXQiWJ7IKOShAByXJFGr8aT+blTQOwYUayKKXycXL1Sg1KINjJSiNKfZF+KwIDAQAB";
String privateKeyStr = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAItJMtfOvvSB5gc8Py5IuPyK3su91lHPiGFg8c9Doy90n2Yu6iiJe1cTA6BNYAha1ddYvYRigij8CFoTcH3WGmQixe12Wi1owlIu/e+KVmd3qcshIldCJYnsgo5KEAHJckUavxpP5uVNA7BhRrIopfJxcvVKDUog2MlKI0p9kX4rAgMBAAECgYB7YDxEAqMMq99Yu1nvooURVeUhracg0maocxneELiEeZYUCixp+dWh/HqyzLbqz6MpXDaLBELtEMpJF30GSdcXWh+/9kN7IeWnlTZxmpc4FxeQydCGOJdgLv+GsR0ulYp4vH8L5cEDy6TZ4C7AHRv8KZOzrwBkZSTL1UayzIDncQJBAM267L4Tz51G/pxXsxjzMfM1mzgr/SvsWlj5OpwECYm7s2kGVxrVtdsCMj2rSYbjrR0TCZe7cKIXRR0lARIxTikCQQCtUfnBqoFHny5twGD/HlvDYoalnxxCYJJg+mBdR5s5ElMzkpjuKRWrvxTeroY+vPpL+7RHSU0qNCpXTvqmDQwzAkAVU817Hv6k5Vk7x/OvIHcLKYF/3z+NsCDlnGCxD9IVTzoYJyochA8oNyASOJGUxEGMBA84hZv1kcf+b3me8zGRAkBrC89jAskYEEOfu4rs5rYsRcT9s/jDMlwWE23DDv/azuueVbOonK1qxvi/1DDLvPImTc55nNdQ8qkYBYqfVj2rAkAnHEKLtgxWXreWRAbujoMgLOR2AEUyG7Vbw+0s/JPSU04DGex3Wj6/+bJQdejAiXUTJSTJjE69aHKwPKBx3fBN";
byte[] bytes = encryptByPrivateKey(text.getBytes("UTF-8"), privateKeyStr);
String s = Base64Utils.encodeToString(bytes);
System.out.println("s:"+s);
String sign = sign(s, privateKeyStr, "UTF-8");
System.out.println(sign);
System.out.println(verify(s, sign, publicKeyStr, "UTF-8"));
System.out.println(decryptByPublicKey(s, publicKeyStr));
}
}
openssl生成RSA证书对,证书生成参考 密码:zsqq
// 将公钥文件转化为字符串
public static String parsePubStr( String publicFile) throws Exception {
InputStream is = new FileInputStream(publicFile);
CertificateFactory cf = CertificateFactory.getInstance("x509");
X509Certificate cerCert = (X509Certificate) cf.generateCertificate(is);
// 生成PublicKey
PublicKey publicKey = cerCert.getPublicKey();
BASE64Encoder base64Encoder = new BASE64Encoder();
String publicKeyString = base64Encoder.encode(publicKey.getEncoded());
return publicKeyString;
}
// 将私钥文件转化为字符串
public static String parsePriStr( String privateFile) throws Exception {
InputStream is = new FileInputStream(privateFile);
KeyStore tKeyStore = KeyStore.getInstance("PKCS12");
tKeyStore.load(is, "ht123456".toCharArray());
Enumeration e = tKeyStore.aliases();
String tAliases = null;
while (e.hasMoreElements()) {
tAliases = (String) e.nextElement();
break;
}
PrivateKey privateKey = (PrivateKey) tKeyStore.getKey(tAliases, "ht123456".toCharArray());
Base64.Encoder encoder = Base64.getEncoder();
String s = encoder.encodeToString(privateKey.getEncoded());
return s;
}
加密、加签、验签、解密
package com.echo.java8.encipher;
import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
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.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.ECFieldFp;
import java.security.spec.EllipticCurve;
/**
* @description:
* @author: echo
* @Date: 2023/10/10 11:02
* @Version: 1.0.0
*/
@Slf4j
public class SmUtils {
// 添加 Bouncy Castle 提供者
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 以下为SM2推荐曲线参数
*/
public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
public static final BigInteger SM2_ECC_P = CURVE.getQ();
public static final BigInteger SM2_ECC_A = CURVE.getA().toBigInteger();
public static final BigInteger SM2_ECC_B = CURVE.getB().toBigInteger();
public static final BigInteger SM2_ECC_N = CURVE.getOrder();
public static final BigInteger SM2_ECC_H = CURVE.getCofactor();
public static final BigInteger SM2_ECC_GX = new BigInteger(
"32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
public static final BigInteger SM2_ECC_GY = new BigInteger(
"BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
public static final org.bouncycastle.math.ec.ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
SM2_ECC_N, SM2_ECC_H);
public static final EllipticCurve JDK_CURVE = new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B);
public static final java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint(
G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger());
public static final java.security.spec.ECParameterSpec JDK_EC_SPEC = new java.security.spec.ECParameterSpec(
JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue());
public static final String SM3_SM2 = "SM3withSM2";
private static String encoding = "GBK";
private static final String BC = "BC";
/**
* 字符串转PublicKey
* @param publicString
* @return
*/
public static BCECPublicKey stringToPublic(String publicString) {
try {
String publicKeyHex = ByteUtils.toHexString(Base64.decode(publicString.getBytes(StandardCharsets.UTF_8)));
BouncyCastleProvider provider = new BouncyCastleProvider();
// 椭圆曲线参数规格
ECParameterSpec ecParameterSpec = new ECParameterSpec(CURVE, G_POINT,
SM2_ECC_N, SM2_ECC_H);
// 将私钥HEX字符串转换为X值
BigInteger bigInteger = new BigInteger(publicKeyHex, 16);
// 将公钥HEX字符串转换为椭圆曲线对应的点
ECPoint ecPoint = CURVE.decodePoint(bigInteger.toByteArray());
// 获取椭圆曲线KEY生成器
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
// 将椭圆曲线点转为公钥KEY对象
return (BCECPublicKey) keyFactory.generatePublic(new ECPublicKeySpec(ecPoint, ecParameterSpec));
} catch (Exception e) {
log.error("", e);
throw new RuntimeException("字符串转公钥失败");
}
}
/**
* 字符串转PrivateKey
* @param privateString
* @return
*/
public static BCECPrivateKey stringToPrivate(String privateString) {
try {
String privateHex = ByteUtils.toHexString(Base64.decode(privateString.getBytes(StandardCharsets.UTF_8)));
BouncyCastleProvider provider = new BouncyCastleProvider();
BigInteger bigInteger = new BigInteger(privateHex, 16);
// 将X值转为私钥KEY对象
KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
return (BCECPrivateKey) keyFactory.generatePrivate(new ECPrivateKeySpec(bigInteger, new ECParameterSpec(CURVE, G_POINT, SM2_ECC_N)));
} catch (Exception e) {
log.error("", e);
throw new RuntimeException("字符串转私钥失败");
}
}
private static String encrypt(String data, String publicKeyString) {
BCECPublicKey bcecPublicKey = stringToPublic(publicKeyString);
ECPublicKeyParameters pubKeyParameters = convertPublicKeyToParameters(bcecPublicKey);
SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());
engine.init(true, pwr);
try {
return Base64.encode(engine.processBlock(data.getBytes(), 0, data.getBytes().length));
} catch (Exception e) {
log.error("", e);
throw new RuntimeException("加密失败");
}
}
private static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
ECParameterSpec parameterSpec = ecPubKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
parameterSpec.getN(), parameterSpec.getH());
return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters);
}
private static String signSm3WithSm2(String privateKeyString, String data) {
try {
PrivateKey privateKey = stringToPrivate(privateKeyString);
Signature signature = Signature.getInstance(SM3_SM2, BC);
signature.initSign(privateKey);
signature.update(data.getBytes(encoding));
byte signed[] = signature.sign();
byte sign_asc[] = new byte[signed.length * 2];
hex2Ascii(signed.length, signed, sign_asc);
return new String(sign_asc);
} catch (Exception e) {
log.error("", e);
throw new RuntimeException("加签失败");
}
}
public static boolean verifySign(String publicKeyString,String signedStr,String data) throws Exception{
BCECPublicKey bcecPublicKey = stringToPublic(publicKeyString);
Signature signature = Signature.getInstance(SM3_SM2, BC);
signature.initVerify(bcecPublicKey);
byte signedData[] = new byte[signedStr.length() / 2];
ascii2Hex(signedStr.length(), signedStr.getBytes(encoding), signedData);
signature.update(data.getBytes(encoding));
return signature.verify(signedData);
}
public static String decrypt(String encryptData, String privateString) {
BCECPrivateKey privateKey = stringToPrivate(privateString);
byte[] decode = Base64.decode(encryptData.getBytes());
ECPrivateKeyParameters priKeyParameters = convertPrivateKeyToParameters(privateKey);
SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
engine.init(false, priKeyParameters);
try {
return new String(engine.processBlock(decode, 0, decode.length));
} catch (Exception e) {
log.error("", e);
throw new RuntimeException("解密失败");
}
}
private static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
ECParameterSpec parameterSpec = ecPriKey.getParameters();
ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
parameterSpec.getN(), parameterSpec.getH());
return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
}
/**
* 将十六进制数据转换成ASCII字符串
*
* @param len 十六进制数据长度
* @param data_in 待转换的十六进制数据
* @param data_out 已转换的ASCII字符串
*/
private static void hex2Ascii(int len, byte data_in[], byte data_out[]) {
byte temp1[] = new byte[1];
byte temp2[] = new byte[1];
for (int i = 0, j = 0; i < len; i++) {
temp1[0] = data_in[i];
temp1[0] = (byte) (temp1[0] >>> 4);
temp1[0] = (byte) (temp1[0] & 0x0f);
temp2[0] = data_in[i];
temp2[0] = (byte) (temp2[0] & 0x0f);
if (temp1[0] >= 0x00 && temp1[0] <= 0x09) {
(data_out[j]) = (byte) (temp1[0] + '0');
} else if (temp1[0] >= 0x0a && temp1[0] <= 0x0f) {
(data_out[j]) = (byte) (temp1[0] + 0x57);
}
if (temp2[0] >= 0x00 && temp2[0] <= 0x09) {
(data_out[j + 1]) = (byte) (temp2[0] + '0');
} else if (temp2[0] >= 0x0a && temp2[0] <= 0x0f) {
(data_out[j + 1]) = (byte) (temp2[0] + 0x57);
}
j += 2;
}
}
/**
* 将ASCII字符串转换成十六进制数据
*
* @param len ASCII字符串长度
* @param data_in 待转换的ASCII字符串
* @param data_out 已转换的十六进制数据
*/
private static void ascii2Hex(int len, byte data_in[], byte data_out[]) {
byte[] temp1 = new byte[1];
byte[] temp2 = new byte[1];
for (int i = 0, j = 0; i < len; j++) {
temp1[0] = data_in[i];
temp2[0] = data_in[i + 1];
if (temp1[0] >= '0' && temp1[0] <= '9') {
temp1[0] -= '0';
temp1[0] = (byte) (temp1[0] << 4);
temp1[0] = (byte) (temp1[0] & 0xf0);
} else if (temp1[0] >= 'a' && temp1[0] <= 'f') {
temp1[0] -= 0x57;
temp1[0] = (byte) (temp1[0] << 4);
temp1[0] = (byte) (temp1[0] & 0xf0);
}
if (temp2[0] >= '0' && temp2[0] <= '9') {
temp2[0] -= '0';
temp2[0] = (byte) (temp2[0] & 0x0f);
} else if (temp2[0] >= 'a' && temp2[0] <= 'f') {
temp2[0] -= 0x57;
temp2[0] = (byte) (temp2[0] & 0x0f);
}
data_out[j] = (byte) (temp1[0] | temp2[0]);
i += 2;
}
}
public static void main(String[] args) throws Exception {
String publicKeyString = "BM6zmWApBExWzuVezdk3QwdE8PTzUBW/6JadWgAbq0XYNzcQcefZmknBZW0Cvo5GvMjDJeOUYYKuyzELNOCNfPQ=";
String privateKeyString = "AKELqaUjpIrFu3S5xRhWZ1BIXnSosZQ+vKCjzQ47pJJT";
String dataStr = "张晓慧";
// 加密
String encrypt = encrypt(dataStr, publicKeyString);
System.out.println("加密后数据:"+encrypt);
String decrypt = decrypt(encrypt, privateKeyString);
System.out.println("机密后数据:"+decrypt);
// 加签
String sign = signSm3WithSm2(privateKeyString, encrypt);
System.out.println("加密后数据加签:"+sign);
// 验签
boolean verifySign = verifySign(publicKeyString, sign, encrypt);
System.out.println("是否验签成功:"+verifySign);
// 打印数据
// 加密后数据:BLmEbT49DDfVT5IHvRcP+4yTGfLSfSbSo1U0hgUuKLWKYS6zkpIvaAurNSNG9KrfqXZInZJDUqw6W2jN82nJwcPbzECtaBmkgvXjaPRq5pG/kjBqfonSEF+hU7CUuRq0RdB39aP1Srl82g==
// 机密后数据:张晓慧
// 加密后数据加签:304502207c01cc3feef31f4a8b0ea1c5b9f45464e6ab6cd02dae6225f9d4c9ec0a4ddffc022100df39ee367d893d774f8529412698fd60c13bb1f5d97f85dbf62122a9a1d87f50
// 是否验签成功:true
}
}
参考文档:https://blog.csdn.net/rtthreadiotos/article/details/121033533