const sm4 = require('sm-crypto').sm4 const sm2 = require('sm-crypto').sm2sm2加密类似RSA,有公钥和私钥,这里前端使用公钥加密,加密有两种模式,适配后端这里改为C1C2C3模式。undefined 需要注意的是,这里的加密结果不能直接返回后台,需要在前面加上04表示公钥未压缩
const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默认为1 sm2Encrypt(data) { // sm2加密密钥 return '04' + sm2.doEncrypt(data, this.pubkeyHex, cipherMode); } sm4Encrypt(data, key) { // sm4加密数据 return sm4.encrypt(data, key); } <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.66</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.66</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.5.8</version> </dependency>由于js端sm2代码实现使用公钥的q值和私钥的d值作为公私钥,所以直接使用hutool生成密钥是无法加解密的,必须做改写
public static void generateKey() throws NoSuchAlgorithmException { // 1. bc库原始写法 X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1"); ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator(); ecKeyPairGenerator.init(new ECKeyGenerationParameters(ecDomainParameters, SecureRandom.getInstance("SHA1PRNG"))); AsymmetricCipherKeyPair asymmetricCipherKeyPair = ecKeyPairGenerator.generateKeyPair(); //16进制格式的私钥,后端使用 BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD(); String privateKeyHex = privatekey.toString(16); //16进制格式的公钥,发给前端 ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ(); byte[] encoded = ecPoint.getEncoded(false); String publicKeyHex = Hex.toHexString(encoded); System.out.println(privateKeyHex); System.out.println(publicKeyHex); // 2. hutool写法 SM2 sm2 = SmUtil.sm2(); String hutoolPrivateKeyHex = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey())); String hutoolPublicKeyHex = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false)); System.out.println(hutoolPrivateKeyHex); System.out.println(hutoolPublicKeyHex); }注意密钥长度必须为128位
SM4 sm4 = new SM4(); SecretKey secretKey = sm4.getSecretKey(); byte[] encoded = secretKey.getEncoded(); String encodeHexStr = HexUtil.encodeHexStr(encoded); // JS加密产生的密文 String cipherData = "0477109887984ca6250635e6e30a58d11efe71abd998271808ec611366197698106b128ef699fe7fa09449bb7ca9527d674cc865a93a4e3593770ecd3ab06291aee81f5459b8500c284e5391956a83ddb2a90f298968a97828b0802749d5e5bbaa1c519489d4a37215ae0d5f7ef0b3a9a2e8dc1ce485544397a66923811c2f44a0"; byte[] cipherDataByte = Hex.decode(cipherData); // 私钥 String privateKey = "9fb1f241314168f56d0bc0a236c3a8d6f60ebf778e4104ce94a6cc27cdd4d178"; // 1. 使用bc库解密 X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1"); ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(privateKey, 16), ecDomainParameters); SM2Engine sm2Engine = new SM2Engine(); sm2Engine.init(false, privateKeyParameters); byte[] bytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length); String data = new String(bytes, CharsetUtil.CHARSET_UTF_8); System.out.println(data); // 2. 使用hutool解密 SM2 sm2 = new SM2(ECKeyUtil.toSm2PrivateParams(privateKey), null); sm2.setMode(SM2Engine.Mode.C1C2C3); sm2.setEncoding(new PlainDSAEncoding()); String decryptStr = sm2.decryptStr(cipherData, KeyType.PrivateKey); System.out.println(decryptStr);这里的key与前端加密使用的key相同
SM4 sm4 = new SM4(HexUtil.decodeHex(key)); String decryptStr = sm4.decryptStr(data);原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。