中信公私钥加密方式

This commit is contained in:
hecan 2025-03-26 17:04:07 +08:00
parent 1a41553fb2
commit 29113c35f1
1 changed files with 353 additions and 0 deletions

View File

@ -0,0 +1,353 @@
package com.hzya.frame.seeyon.util;
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.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class SM2Util {
private final static SM2Engine.Mode DIGEST = SM2Engine.Mode.C1C3C2;
private static final String PRIVATE_KEY = "privateKey";
private static final String PUBLIC_KEY = "publicKey";
private static final String STD_NAME = "sm2p256v1";
private static final String ALGORITHM = "EC";
public static final String LF = "\n";
public static final String CR = "\r";
public static final String SPACE = " ";
public static final String EMPTY = "";
/**
* 生成密钥
*
* @return
*/
public Map<String, String> generate() {
Map<String, String> keyMap = new HashMap<>();
try {
ECGenParameterSpec sm2Spec = new ECGenParameterSpec(STD_NAME);
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM, new BouncyCastleProvider());
kpg.initialize(sm2Spec);
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
keyMap.put(PRIVATE_KEY, new String(Base64.getEncoder().encode(privateKey.getEncoded()), StandardCharsets.UTF_8));
keyMap.put(PUBLIC_KEY, new String(Base64.getEncoder().encode(publicKey.getEncoded()), StandardCharsets.UTF_8));
} catch (Exception e) {
/*this.log.info("SM2Util生成密钥出现异常", e);*/
}
return keyMap;
}
/**
* 加密
*
* @param data 数据Str
* @param publicKey 公钥Str
* @return 加密之后的数据
*/
public static String encrypt(String data, String publicKey) {
try {
return new String(Base64.getEncoder().encode(encrypt(data.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(publicKey.getBytes(StandardCharsets.UTF_8)))));
}catch (Exception e){
e.printStackTrace();
}
return null;
}
/**
* 加密
*
* @param data 数据
* @param publicKey 公钥
* @return 加密之后的数据
*/
public static byte[] encrypt(byte[] data, byte[] publicKey) throws Exception {
CipherParameters pubKeyParameters = new ParametersWithRandom(publicKeyToParams("SM2", publicKey));
SM2Engine engine = new SM2Engine(DIGEST);
engine.init(true, pubKeyParameters);
return engine.processBlock(data, 0, data.length);
}
/**
* 解密
*
* @param data 数据
* @param privateKey 私钥
* @return 解密之后的数据
*/
public static String decrypt(String data, String privateKey) throws Exception {
return new String(decrypt(Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8)), Base64.getDecoder().decode(privateKey.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);
}
/**
* 解密
*
* @param data 数据
* @param privateKey 私钥
* @return 解密之后的数据
*/
public static byte[] decrypt(byte[] data, byte[] privateKey) throws Exception {
CipherParameters privateKeyParameters = privateKeyToParams("SM2", privateKey);
SM2Engine engine = new SM2Engine(DIGEST);
engine.init(false, privateKeyParameters);
return engine.processBlock(data, 0, data.length);
}
/**
* SM2密文转换空格等特殊字符
*
* @param sm2Content
* @return
*/
public static String fixSm2Content(String sm2Content) {
if (sm2Content == null) {
return sm2Content;
}
return sm2Content.replace(LF, EMPTY).replace(CR, EMPTY).replace(SPACE, "+");
}
/**
* 私钥转换为 {@link ECPrivateKeyParameters}
*
* @param key key
* @return
* @throws InvalidKeyException
*/
public static ECPrivateKeyParameters privateKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
if (key == null || key.length == 0) {
throw new NullPointerException("key must be not null !");
}
PrivateKey privateKey = generatePrivateKey(algorithm, key);
return (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey);
}
/**
* 生成私钥
*
* @param algorithm 算法
* @param key key
* @return
*/
public static PrivateKey generatePrivateKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
if (isBlank(algorithm)) {
throw new NullPointerException("algorithm must be not null !");
}
if (key == null || key.length == 0) {
throw new NullPointerException("key must be not null !");
}
KeySpec keySpec = new PKCS8EncodedKeySpec(key);
algorithm = getAlgorithmAfterWith(algorithm);
return getKeyFactory(algorithm).generatePrivate(keySpec);
}
/**
* 公钥转换为 {@link ECPublicKeyParameters}
*
* @param key key
* @return
* @throws InvalidKeyException
*/
public static ECPublicKeyParameters publicKeyToParams(String algorithm, byte[] key) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException {
if (isBlank(algorithm)) {
throw new NullPointerException("algorithm must be not null !");
}
if (key == null || key.length == 0) {
throw new NullPointerException("key must be not null !");
}
PublicKey publicKey = generatePublicKey(algorithm, key);
return (ECPublicKeyParameters) ECUtil.generatePublicKeyParameter(publicKey);
}
/**
* 生成公钥
*
* @param algorithm 算法
* @param key key
* @return
*/
public static PublicKey generatePublicKey(String algorithm, byte[] key) throws NoSuchAlgorithmException, InvalidKeySpecException {
if (isBlank(algorithm)) {
throw new NullPointerException("algorithm must be not null !");
}
if (key == null || key.length == 0) {
throw new NullPointerException("key must be not null !");
}
KeySpec keySpec = new X509EncodedKeySpec(key);
algorithm = getAlgorithmAfterWith(algorithm);
return getKeyFactory(algorithm).generatePublic(keySpec);
}
/**
* 获取用于密钥生成的算法<br>
* 获取XXXwithXXX算法的后半部分算法如果为ECDSA或SM2返回算法为EC
*
* @param algorithm XXXwithXXX算法
* @return 算法
*/
private static String getAlgorithmAfterWith(String algorithm) {
if (isBlank(algorithm)) {
throw new NullPointerException("algorithm must be not null !");
}
int indexOfWith = lastIndexOfIgnoreCase(algorithm, "with");
if (indexOfWith > 0) {
algorithm = substring(algorithm, indexOfWith + "with".length());
}
if ("ECDSA".equalsIgnoreCase(algorithm) || "SM2".equalsIgnoreCase(algorithm)) {
algorithm = ALGORITHM;
}
return algorithm;
}
/**
* 获取{@link KeyFactory}
*
* @param algorithm 非对称加密算法
* @return {@link KeyFactory}
*/
private static KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException {
final Provider provider = new BouncyCastleProvider();
return KeyFactory.getInstance(algorithm, provider);
}
public static void main(String[] args) throws Exception {
SM2Util sm2Utils = new SM2Util();
sm2Utils.testSignByQuickpass();
}
private void testSignByQuickpass() throws Exception {
//密钥生成
String privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgtzMo2o6THK3yLIm+83Ch/560+02l2hjjBSFGieWY/Z6gCgYIKoEcz1UBgi2hRANCAATKhwZX4P3XI8vYTKeCOLMVbanUNbaXjrIEZynshwdOzRVgzRQSiPNWo6OBBkAPvqE+2RS+5ABpS82DSlKl81z0";
String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyocGV+D91yPL2EyngjizFW2p1DW2l46yBGcp7IcHTs0VYM0UEojzVqOjgQZAD76hPtkUvuQAaUvNg0pSpfNc9A==";
// 加验签
//String value = "{\"partner\": \"test\",\"tranTime\": \"20240128003627\",\"seqNo\": \"123456\",\"orderNo\": \"order123456\", \"orderAmt\": \"1500\"}";
String value="{\"data\":{\"companyCode\":\"CN000001\",\"purpose\":\"加入中国光伏行业协会会员单位获得行业技术支持2025年会员单位缴纳标准为1万元/年,汇款时需注明“会费”字样,并在备注中注明汇款单位;缴纳会费后,需有付款凭证,将付款凭证发送至协会邮箱,并填写开票信息等内容\",\"recAccountNum\":\"8110701012801540483\",\"recAccountName\":\"\",\"payAccountNum\":\"8110701012601540892\",\"fundType\":\"0001\",\"transAmount\":\"9.90\",\"documentNo\":\"DG202503240321\",\"recBankCode\":\"\",\"settleAccountType\":\"CASH_TRANSFER\",\"sourceFlowNumber\":\"-3854827654841675885_1539\",\"submitUser\":\"user1\",\"digest\":\"加入中国光伏行业协会会员单位获得行业技术支持2025年会\",\"payChannel\":\"DIRECT\",\"currency\":\"CNY\",\"toPublic\":true,\"payAccountName\":\"\",\"payDate\":\"2025-03-26\"}}";
System.out.println("明文:" + value);
//加密
String encryptStr = encrypt(value, publicKey);
//String encryptStr="BAYF5RocTMvWHK4JLruoWNmvoBtSgEK6bHrXUIBcso3dx312VyI57p3bahg/qjcQufpa59XiMd8wA+cjyXmYm9+P4Y7DY5dZJQi6FdPZpL6awouRZMagdlceOL8yW5zDnx8tMqreUTAwkpvViwKn4DydKdV9EW0XuWkBwsN+4ZQftrY3FT/5Y/g8XtNSQMBu9PIwGWtPtpEtwO0HnaGCu7DGCSF+lo4PvYFmIlj0f2hQ1V1osdNIJ3IqUeZ0IZVFulaaOE72+vgAQN7UO0447kPq5iC8++oyXP7Bhf9kfU1gYOVXciIeAXoxIcjX+5DCB1q/FOmzqnOIBLRhSysqRXJa0ZvFgf1Ebpr6Fvz2Beim8SOEl3pXeLnLCJe91qsMuENLfNTOYnuESgSmdE1np3OJKcZwgeryUIt+WP7L28aJ1zNisWhB+TJaGtvWR++zY2fmMeZmwtJEz25jdmN1OWSuxgjXpI7fhIYoDnKQBQJKM5FQ+cWqJJozUMOlKG8Xhf5Lv1NjZOiNM7klp/Uprb3kUQj466ArWvsLzsoT1OOTOyBRJTbhKPSKi39ekcz4/ELuGSNB8Oz0pNg1tjbuyIcbiy2WCQI9/feiE+LyGgQPiUsaNxte10bYZuJJV33UWrBiezL0eA5pSm55zd98ToCX0QnJJq5OGW/8t8O/7+fZcSq5EFXSfS+3An8+EMLnBvI1ycjb9Q7PFVP4PmZ/VFqWJDNyi98iekWV09DVCtnCHqA5ZqEcPgZCeY40ZN5EQARvy11RWzs14Gj8JninjFbV6qtgB1Cadmy/piZS/SZdEvSnBfe04vTOElgG5GhraLrfMyVhnsmLeoqzLXmMT62uktPXKITjvFgr2NfdzbY5TkkDVMJu1b3VhZxOZENnJ4kW6nctYO0I7Z+xpVuMUnNOVxQBSJch2AdwIuyEL3odJSOXUt+RZIXhGNhyKw2Y8PvPQx+hOoCUyKyaUIS8G6RK/LI+TyMZTMsCUXYBEIxP10slFPp/4PCa7RPLhvdHsgik+cWNJj45tJRql9YXF1moWIaAUmLeu/ytCho1arA3V6/NjjckWI9mnqs41U2FAchJXdU2wNdIDB4AgGSsZs+o9sv+chgMgITV8/8xPNchu6g1UuczEXZRPFtKsVXlAJkNzQgBrMwCatby1S4CJFc5S/AJNIYipwLGW+M+3rh2+Ay+3HqDv7+7LUn+MTxgFfiosyK3hxkekY/eUg==";
System.out.println("加密结果:" + encryptStr);
//解密
String decryptStr = decrypt(encryptStr, privateKey);
System.out.println("解密结果:" + decryptStr);
}
/**
* 判断字符串是否为空
*
* @param str 字符串
* @return true/false
*/
public static boolean isBlank(String str) {
int strLen;
if (str != null && (strLen = str.length()) != 0) {
for (int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
}
return true;
}
public static String substring(final String str, int start) {
if (str == null) {
return null;
}
// handle negatives, which means last n characters
if (start < 0) {
start = str.length() + start; // remember start is negative
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return "";
}
return str.substring(start);
}
public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) {
if (str == null || searchStr == null) {
return -1;
}
return lastIndexOfIgnoreCase(str, searchStr, str.length());
}
public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) {
if (str == null || searchStr == null) {
return -1;
}
if (startPos > str.length() - searchStr.length()) {
startPos = str.length() - searchStr.length();
}
if (startPos < 0) {
return -1;
}
if (searchStr.length() == 0) {
return startPos;
}
for (int i = startPos; i >= 0; i--) {
if (regionMatches(str, i, searchStr, searchStr.length())) {
return i;
}
}
return -1;
}
static boolean regionMatches(final CharSequence cs, final int thisStart,
final CharSequence substring, final int length) {
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(true, thisStart, (String) substring, 0, length);
}
int index1 = thisStart;
int index2 = 0;
int tmpLen = length;
// Extract these first so we detect NPEs the same as the java.lang.String version
final int srcLen = cs.length() - thisStart;
final int otherLen = substring.length();
// Check for invalid parameters
if (thisStart < 0 || length < 0) {
return false;
}
// Check that the regions are long enough
if (srcLen < length || otherLen < length) {
return false;
}
while (tmpLen-- > 0) {
final char c1 = cs.charAt(index1++);
final char c2 = substring.charAt(index2++);
if (c1 == c2) {
continue;
}
// The same check as in String.regionMatches():
if (Character.toUpperCase(c1) != Character.toUpperCase(c2)
&& Character.toLowerCase(c1) != Character.toLowerCase(c2)) {
return false;
}
}
return true;
}
}