SM2非对称加密
公钥 = 04xxxxxxxxxxxxxxxxxxxx,私钥 = 276xxxx原文:你哦哈1232154 3654 {} ,俺可接受不符点
公钥私钥是我后台自己生成的
java代码实现
pom.xml
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15to18</artifactId><version>1.71</version></dependency>
国密sm2算法秘钥对
package com.sm.mscmsm2;/*** 描述: 国密sm2算法秘钥对 - 对象 <br>* 时间: 2022-07-14 16:01 <br>* 作者:IT学习道场*/public class SM2KeyPairs {/***公钥*/private String publicKey;/*** 私钥*/private String privateKey;public SM2KeyPairs() {}public SM2KeyPairs(String publicKey, String privateKey) {this.publicKey = publicKey;this.privateKey = privateKey;}public String getPublicKey() {return publicKey;}public void setPublicKey(String publicKey) {this.publicKey = publicKey;}public String getPrivateKey() {return privateKey;}public void setPrivateKey(String privateKey) {this.privateKey = privateKey;}@Overridepublic String toString() {return "SM2KeyPairs{" +"publicKey='" + publicKey + '\'' +", privateKey='" + privateKey + '\'' +'}';}}
SM2辅助工具类
package com.sm.mscmsm2;import lombok.extern.slf4j.Slf4j;import org.bouncycastle.asn1.gm.GMNamedCurves;import org.bouncycastle.asn1.x9.X9ECParameters;import org.bouncycastle.crypto.AsymmetricCipherKeyPair;import org.bouncycastle.crypto.InvalidCipherTextException;import org.bouncycastle.crypto.engines.SM2Engine;import org.bouncycastle.crypto.generators.ECKeyPairGenerator;import org.bouncycastle.crypto.params.*;import org.bouncycastle.math.ec.ECPoint;import org.bouncycastle.util.encoders.Hex;import java.io.UnsupportedEncodingException;import java.math.BigInteger;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;import java.util.Base64;/*** 描述: 美术传媒sm2 <br>* 时间: 2022-07-25 17:32 <br>* 作者:王林冲*/@Slf4jpublic class SM2Util {private static final ECDomainParameters domainParameters;private static final X9ECParameters sm2ECParameters;static {sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());}public static SM2KeyPairs getSM2KeyPairs(){//生成密钥对ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();try {keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();//私钥,16进制格式,自己保存,格式如a2081b5b81fbea0b6b973a3ab6dbbbc65b1164488bf22d8ae2ff0b8260f64853BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();String privateKeyHex = privatekey.toString(16);//公钥,16进制格式,发给前端,格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbbaECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));SM2KeyPairs pairs = new SM2KeyPairs(publicKeyHex, privateKeyHex);return pairs;} catch (NoSuchAlgorithmException e) {log.error(e.getMessage(), e);throw new RuntimeException(e.getMessage());}}public static String decrypt(String data, String privateKey) {byte[] cipherDataByte = Hex.decode(data);//刚才的私钥Hex,先还原私钥BigInteger privateKeyD = new BigInteger(privateKey, 16);ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);//用私钥解密SM2Engine sm2Engine = new SM2Engine();sm2Engine.init(false, privateKeyParameters);//processBlock得到Base64格式,记得解码byte[] arrayOfBytes = new byte[0];try {arrayOfBytes = Base64.getDecoder().decode(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length));} catch (InvalidCipherTextException e) {log.error(e.getMessage(), e);throw new RuntimeException(e.getMessage());}//得到明文:SM2 Encryption Testreturn new String(arrayOfBytes);}public static String encrypt(String data, String publicKey){//提取公钥点ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(publicKey));//刚才的私钥Hex,先还原私钥ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);SM2Engine sm2Engine = new SM2Engine();sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));byte[] arrayOfBytes = new byte[0];try {byte[] in = Base64.getEncoder().encode(data.getBytes("utf-8"));arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);} catch (Exception e) {log.error(e.getMessage(), e);throw new RuntimeException(e.getMessage());}return Hex.toHexString(arrayOfBytes);}public static void main(String[] args) throws InvalidCipherTextException, UnsupportedEncodingException {//SM2KeyPairs sm2KeyPairs = getSM2KeyPairs();//System.out.println(sm2KeyPairs.toString());String publicKey = "0419080a9bdb6968f0ef31b2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";String privateKey = "2766001cc5d2888xxxxxxxxxxxxxxxxxxxxxxxxx";String text = "你哦哈1232154 3654 {} ,俺可接受不符点";String encrypt = encrypt(text, publicKey);System.out.println("encrypt = "+ encrypt);//String encrypt = "041fccce91d7a35a429f449aea758364826f688577bad9d3b9c99a1ab5c390fdf63f00232e0af4fcab8fccd70c46b636e42024f260973d73c8d1b6c3d41c2b26238b8a09c994e0a912ba2022b342af049b164979018af08e75cb63a66408fe9dfd553e7a350fb0d12405b984bde185ba38ca693c9c12b06dbe445abc5b9fc754f2424bab2a766d62c12b1832c51b2cab44ba4dc0049b5f3b479fe1cc348bcfd77f65db4267";String jm = decrypt(encrypt, privateKey);System.out.println(jm);}}
JavaScript实现
html使用demo
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>sm2加密</title><script src="./lib/crypto-js.js"></script><script src="./lib/sm2.js"></script></head><body><script type="text/javascript">//私钥:2766001cc5d2888553efe566781d8fb25557aecd6435e731d21ad362af8a4eaf//公钥:前缀04+x坐标+y坐标var pubkeyHex = "04190xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";var msg='你哦哈1232154 3654 {} ,俺可接受不符点';//加密格式0: C1C2C3、1: C1C3C2var encryptData = sm2Encrypt(msg, pubkeyHex, 0);document.write(encryptData);</script></body></html>
Android端和java端一样,jar包采用 bcprov-jdk15to18-1.71.jar
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.4</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.57</version></dependency>
SM2KeyPairs
package com.sm.hutoolsm2;/*** 描述: 国密sm2算法秘钥对 - 对象 <br>* 时间: 2022-07-14 16:01 <br>* 作者:IT学习道场*/public class SM2KeyPairs {/***公钥*/private String publicKey;/*** 私钥*/private String privateKey;public SM2KeyPairs() {}public SM2KeyPairs(String publicKey, String privateKey) {this.publicKey = publicKey;this.privateKey = privateKey;}public String getPublicKey() {return publicKey;}public void setPublicKey(String publicKey) {this.publicKey = publicKey;}public String getPrivateKey() {return privateKey;}public void setPrivateKey(String privateKey) {this.privateKey = privateKey;}@Overridepublic String toString() {return "SM2KeyPairs{" +"publicKey='" + publicKey + '\'' +", privateKey='" + privateKey + '\'' +'}';}}
SM2Util
package com.sm.hutoolsm2;import cn.hutool.core.util.HexUtil;import cn.hutool.crypto.BCUtil;import cn.hutool.crypto.SmUtil;import cn.hutool.crypto.asymmetric.KeyType;import cn.hutool.crypto.asymmetric.SM2;import com.sm.sm2.SM2KeyPairs;import org.bouncycastle.crypto.engines.SM2Engine;import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;import java.nio.charset.Charset;import java.util.Base64;/*** 描述: todo <br>* 时间: 2022-07-25 17:32 <br>* 作者:IT学习道场*/public class SM2Util {/*** 获取公钥私钥* @return SM2KeyPairs 公私钥对象*/public static SM2KeyPairs getKeyPairs(){SM2 sm2 = SmUtil.sm2();// sm2的加解密时有两种方式即 C1C2C3、 C1C3C2,sm2.setMode(SM2Engine.Mode.C1C2C3);// 生成私钥String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));// 生成公钥String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));SM2KeyPairs keyPairs = new SM2KeyPairs(publicKey, privateKey);return keyPairs;}/*** 公钥加密* @param publicKey 公钥* @param text 预加密文本* @return 加密后文本*/public static String encrypt(String publicKey, String text){// 通过密钥解密SM2 sm2 = SmUtil.sm2(null, publicKey);sm2.setMode(SM2Engine.Mode.C1C2C3);//1 先把明文转成base64text = Base64.getEncoder().encodeToString(text.getBytes());//2 把base64的文本用公钥加密后在转成密文为16进制,否则前端解密前需要先转换格式String encryptStr = sm2.encryptHex(text, Charset.forName("utf-8"), KeyType.PublicKey);return encryptStr;}/*** 私钥解密* @param privateKey 私钥* @param text 加密文本* @return 解密后文本*/public static String decrypt(String privateKey, String text){//创建sm2 对象SM2 sm2 = SmUtil.sm2(privateKey, null);sm2.setMode(SM2Engine.Mode.C1C2C3);// 私钥解密String decrypt = sm2.decryptStr(text, KeyType.PrivateKey);byte[] decode = Base64.getDecoder().decode(decrypt);String decryptStr = new String(decode);return decryptStr;}public static void main(String[] args) {//SM2KeyPairs keyPairs = getKeyPairs();//System.out.println(keyPairs.toString());String publicKey = "0407125a6dc1d73e41dc1b57xxxxxxxxxxxxxxxxxxxxxx";String privateKey = "0f3c459c2090eb5c35108xxxxxxxxxxxxx";String text = "你哦哈1232154 3654 {} ,俺可接受不符点";String encrypt = encrypt(publicKey, text);System.out.println("encrypt = " + encrypt);//String encrypt ="04ddb0f3622c51af847bbd528d9fb8cd264aa9341c817cb3077bb1464766b3b7e3a5ff523004d4f2259676267a080f66c4682844adef2e4b612e604071af16c6285fc48795e4ae1277e7d79b4bf420584dea2345eae0d5f2e12293013d25af09eaff4fabf5109a18fed74d07ed30a34b1623f161f7a70e2746accf9334b96cfc33f2aa6aae13c08b131604a9caa7d2c5453b8a021a6354ba27cd7d3f4ebcf93376efa9cf5d";String decrypt = decrypt(privateKey, encrypt);System.out.println("decrypt = " + decrypt);}}
hutool实现和上面的Android可用的版本一样,当然,后端也可以直接使用Android和java通用的版本
ios端必须和js和java和Android端一致,采用 C1C2C3模式
下面是ios的实现。采用国密 国密的 Objective-C 封装
查看具体实现过程,请至开源项目地址GitHub - muzipiao/GMObjC: SM2/SM3/SM4/ECDH library based on OpenSSL.。
在终端运行以下命令:
git clone https://github.com/muzipiao/GMObjC.gitcd GMObjCpod installopen GMObjC.xcworkspace
SM2 加解密
NSString *pubKey = @"0408E3FFF9505BCFAF9307E665E9229F4E1B3936437xxxxxxxxxxxxxxxxxxxxxxxxxxxx";NSString *priKey = @"90F3A42B9FE24AB196305FD92EC82E647616C3A369xxxxxxxxxx";NSString *plaintext = @"你哦哈1232154 3654 {} ,俺可接受不符点";//先对明文进行base64加密,再用GMSm2Utils 对其进行sm2加密,返回asn1编码格式的密文NSString *encode = [GMSm2Utils encryptText:[self base64:plaintext] publicKey:pubKey];//把asn1编码格式的密文的 encode 解码成C1C3C2的密文字符串 = c1c3c2NSString *c1c3c2 = [GMSm2Utils asn1DecodeToC1C3C2:encode];//再把c1c3c2这个字符串转成 C1C2C3 模式的密文字符串 = c1c2c3 ,这个可以直接传给java端,用上面的java端实现的sm2Util进行解密NSString *c1c2c3 = [GMSm2Utils convertC1C3C2ToC1C2C3:c1c3c2 hasPrefix:NO];NSLog(@"c1c2c3 : %@",c1c2c3);
- (NSString *)base64:(NSString *)string{NSString *target = string;NSData *data = [target dataUsingEncoding:NSUTF8StringEncoding];NSString *base64Str = [data base64EncodedStringWithOptions:nil];// NSString *base64DecodeStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];return base64Str;}
文章转载自IT学习道场,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




