MD5/AES/RSA 替换为国密 SM3/SM4/SM2 实现前后端交互

import org.bouncycastle.asn1.gm.GMNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.*; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.crypto.util.PublicKeyFactory; 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.math.ec.ECPoint; import org.bouncycastle.util.encoders.Hex; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.*; import java.security.spec.ECGenParameterSpec; import java.util.ArrayList; import java.util.Base64; import java.util.List; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; public class GMUtil { public static String DEFAULT_ENCODING = "utf-8"; private static String SM4 = "SM4"; private static String SM3 = "SM3"; /** * 加密算法/分组加密模式/分组填充方式 * PKCS5Padding-以8个字节为一组进行分组加密 * 定义分组加密模式使用:PKCS5Padding */ private static String SM4_TRANSFORM = "SM4/ECB/PKCS5Padding"; // "SM4/CBC/PKCS7Padding"; private static String PROVIDER = "BC"; private static String SPEC = "sm2p256v1"; static { Security.addProvider(new BouncyCastleProvider()); } public static String createSm4Key() throws Exception { // 生成 SM4 密钥 KeyGenerator keyGen = KeyGenerator.getInstance(SM4, PROVIDER); keyGen.init(128, new SecureRandom()); // SM4 使用 128 位密钥 SecretKey secretKey = keyGen.generateKey(); return bytesToHex(secretKey.getEncoded()); } public static String sm4Encrypt(String content, String key) throws Exception{ return sm4Encrypt(content, key, DEFAULT_ENCODING); } /** * * @param content * @param hexKey * @param charsetName * @return * @throws Exception */ public static String sm4Encrypt(String content, String hexKey, String charsetName) throws Exception { Cipher cipher = Cipher.getInstance(SM4_TRANSFORM, PROVIDER); byte[] keyBytes = Hex.decode(hexKey); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, SM4)); byte[] ciphertext = cipher.doFinal(content.getBytes(charsetName)); return bytesToHex(ciphertext); } public static String sm4Decrypt(String encryptText, String hexKey) throws Exception { return sm4Decrypt(encryptText, hexKey, DEFAULT_ENCODING); } /** * * @param encryptText * @param hexKey * @param charsetName * @return * @throws Exception */ public static String sm4Decrypt(String encryptText, String hexKey, String charsetName) throws Exception { Cipher cipher = Cipher.getInstance(SM4_TRANSFORM, PROVIDER); byte[] keyBytes = Hex.decode(hexKey); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, SM4)); byte[] ciphertext = cipher.doFinal(Hex.decode(encryptText)); return new String(ciphertext, charsetName); } /** * 生成文本内容的信息摘要 * @param content 文本 * @return 返回长度为 64 的 hex 文本 */ public static String sm3(String content) throws Exception { // 获取 SM3 MessageDigest 实例 MessageDigest digest = MessageDigest.getInstance(SM3, PROVIDER); digest.update(content.getBytes()); return bytesToHex(digest.digest()); } public static String sm3(InputStream is) throws Exception { // 获取 SM3 MessageDigest 实例 MessageDigest digest = MessageDigest.getInstance(SM3, PROVIDER); byte[] buffer = new byte[1024]; int numRead; while ((numRead = is.read(buffer)) > 0) { digest.update(buffer, 0, numRead); } is.close(); return bytesToHex(digest.digest()); } /** * 第一个元素为私钥、第二个元素为公钥、第三个元素为 30 开头的私钥、第四个元素为 30 开头的公钥 * * @return SM2 密码对 * @throws Exception */ public static List<String> createSm2Key() throws Exception { List<String> keys = new ArrayList<>(2); KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC", PROVIDER); keyPairGen.initialize(new ECGenParameterSpec(SPEC), new SecureRandom()); KeyPair keyPair = keyPairGen.generateKeyPair(); BCECPublicKey pubKey = (BCECPublicKey) keyPair.getPublic(); BCECPrivateKey priKey = (BCECPrivateKey) keyPair.getPrivate(); //私钥(16进制字符串,头部不带00长度共64) keys.add(bytesToHex(priKey.getS().toByteArray())); //获取公钥(16进制字符串,头部带04长度共130) keys.add(bytesToHex(((BCECPublicKey)keyPair.getPublic()).getQ().getEncoded(false))); /* 同时添加 30 开头的密钥 在X.509证书中,公钥信息是按照ASN.1编码规则进行编码的,而这种编码可能会在公钥前面加上一些额外的信息,使得整个序列看起来以“30”开头。 “30”在十六进制中对应于ASN.1的SEQUENCE标签,表明这是一个复合数据类型,包含了多个元素,如算法标识符和公钥本身。 */ keys.add(bytesToHex(priKey.getEncoded())); keys.add(bytesToHex(pubKey.getEncoded())); return keys; } public static String sm2Encrypt(String content, String hexPubKey) throws Exception { return sm2Encrypt(content, hexPubKey, DEFAULT_ENCODING); } /** * SM2 加密 * @param content 待加密文本 * @param hexPubKey 公钥串(HEX编码) * @param charsetName 字符集 * @return HEX编码的加密结果 * @throws Exception */ public static String sm2Encrypt(String content, String hexPubKey, String charsetName) throws Exception{ SM2Engine engine = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2); CipherParameters pubKeyParams; if(hexPubKey.length() == 130 && hexPubKey.startsWith("04")){ // 获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName(SPEC); // 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数N ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); //提取公钥点 ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(hexPubKey)); // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04 pubKeyParams = new ECPublicKeyParameters(pukPoint, domainParameters); } else pubKeyParams = PublicKeyFactory.createKey(Hex.decode(hexPubKey)); engine.init(true, new ParametersWithRandom(pubKeyParams)); byte[] bytes = content.getBytes(charsetName); return bytesToHex(engine.processBlock(bytes, 0, bytes.length)); } public static String sm2Decrypt(String encryptText, String hexPriKey)throws Exception { return sm2Decrypt(encryptText, hexPriKey, DEFAULT_ENCODING); } /** * SM2 解密 * @param encryptText * @param hexPriKey * @param charsetName * @return * @throws Exception */ public static String sm2Decrypt(String encryptText, String hexPriKey, String charsetName) throws Exception { SM2Engine engine = new SM2Engine(new SM3Digest(), SM2Engine.Mode.C1C3C2); CipherParameters priKeyParams; if(hexPriKey.length() == 64 || (hexPriKey.length() == 66 && hexPriKey.startsWith("00"))){ //获取一条SM2曲线参数 X9ECParameters sm2ECParameters = GMNamedCurves.getByName(SPEC); //构造domain参数 ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN()); BigInteger privateKeyD = new BigInteger(hexPriKey, 16); priKeyParams = new ECPrivateKeyParameters(privateKeyD, domainParameters); } else priKeyParams = PrivateKeyFactory.createKey(Hex.decode(hexPriKey)); engine.init(false, priKeyParams); byte[] bytes = Hex.decode(encryptText); return new String(engine.processBlock(bytes, 0, bytes.length), charsetName); } public static String hexToBase64(String hex){ return bytesToBase64(Hex.decode(hex)); } public static String base64ToHex(String base64) throws UnsupportedEncodingException { return bytesToHex(Base64.getDecoder().decode(base64)); } /** * 将字节数组转换为十六进制字符串的方法 * @param bytes 字节数组 * @return */ private static String bytesToHex(byte[] bytes) throws UnsupportedEncodingException { return new String(Hex.encode(bytes), DEFAULT_ENCODING); } private static String bytesToBase64(byte[] bytes){ return Base64.getEncoder().encodeToString(bytes); } }
上一篇:【仿真建模-anylogic】数据源组件


下一篇:实现jupyter 指定虚拟环境的配置方法