国密:生成SM2秘钥、加解密及加验签
国密改造已经持续了很长时间了,相信很多从事金融科技类的程序猿都遇到过这个需求。这篇文章就为大家带来笔者对于国密改造的一些经验,主要是代码层面,有兴趣的同学可以研究下国密的算法模型!
注:本文所用到的工具类并非笔者所写!
目录
一、国密简述
国密——国家密码局制定的国家密码算法。主要包含SM1、SM2、SM3、SM4几种方式。
SM1:对称加密,且算法不公开,使用硬件加密,本文不做叙述;
SM2:非对称加密,签名以及生成秘钥速度优于RSA,基于ECC算法,运算效率更高,且更安全;
SM3:摘要,国产杂凑算法,生成长度为256比特,优于MD5以及SHA-1算法;
SM4: 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位;
注意
生成SM2 公钥是130 位 前面多了04两个标识符,注意区分!
二、依赖准备
国密主要用到下面的包
org.bouncycastle bcpkix-jdk15on 1.57
一定注意版本。实际项目中笔者发现项目其他子工程用到1.56版本的包,所以选择了低版本。
三、SM2算法应用
1、生成SM2公私钥
工具类
package cn.test.encrypt.utils.sm2;import cn.test.encrypt.utils.Util;import org.bouncycastle.crypto.AsymmetricCipherKeyPair;import org.bouncycastle.crypto.digests.SM3Digest;import org.bouncycastle.crypto.params.ECPrivateKeyParameters;import org.bouncycastle.crypto.params.ECPublicKeyParameters;import org.bouncycastle.math.ec.ECPoint;import java.math.BigInteger;public class Cipher { private int ct; private ECPoint p2; private SM3Digest sm3keybase; private SM3Digest sm3c3; private byte key[]; private byte keyOff; public Cipher() { this.ct = 1; this.key = new byte[32]; this.keyOff = 0; } private void Reset() { this.sm3keybase = new SM3Digest(); this.sm3c3 = new SM3Digest(); byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger()); this.sm3keybase.update(p, 0, p.length); this.sm3c3.update(p, 0, p.length); p = Util.byteConvert32Bytes(p2.getY().toBigInteger()); this.sm3keybase.update(p, 0, p.length); this.ct = 1; NextKey(); } private void NextKey() { SM3Digest sm3keycur = new SM3Digest(this.sm3keybase); sm3keycur.update((byte) (ct >> 24 & 0xff)); sm3keycur.update((byte) (ct >> 16 & 0xff)); sm3keycur.update((byte) (ct >> 8 & 0xff)); sm3keycur.update((byte) (ct & 0xff)); sm3keycur.doFinal(key, 0); this.keyOff = 0; this.ct++; } public ECPoint Init_enc(SM2 sm2, ECPoint userKey) { AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair(); ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); BigInteger k = ecpriv.getD(); ECPoint c1 = ecpub.getQ(); this.p2 = userKey.multiply(k); Reset(); return c1; } public void Encrypt(byte data[]) { this.sm3c3.update(data, 0, data.length); for (int i = 0; i < data.length; i++) { if (keyOff == key.length) { NextKey(); } data[i] ^= key[keyOff++]; } } public void Init_dec(BigInteger userD, ECPoint c1) { this.p2 = c1.multiply(userD); Reset(); } public void Decrypt(byte data[]) { for (int i = 0; i < data.length; i++) { if (keyOff == key.length) { NextKey(); } data[i] ^= key[keyOff++]; } this.sm3c3.update(data, 0, data.length); } public void Dofinal(byte c3[]) { byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger()); this.sm3c3.update(p, 0, p.length); this.sm3c3.doFinal(c3, 0); Reset(); }}
package cn.test.encrypt.utils.sm2;import org.bouncycastle.crypto.generators.ECKeyPairGenerator;import org.bouncycastle.crypto.params.ECDomainParameters;import org.bouncycastle.crypto.params.ECKeyGenerationParameters;import org.bouncycastle.math.ec.ECCurve;import org.bouncycastle.math.ec.ECFieldElement;import org.bouncycastle.math.ec.ECFieldElement.Fp;import org.bouncycastle.math.ec.ECPoint;import java.math.BigInteger;import java.security.SecureRandom;public class SM2 { //国密参数 public static String[] ecc_param = { "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" }; public static SM2 Instance() { return new SM2(); } public final BigInteger ecc_p; public final BigInteger ecc_a; public final BigInteger ecc_b; public final BigInteger ecc_n; public final BigInteger ecc_gx; public final BigInteger ecc_gy; public final ECCurve ecc_curve; public final ECPoint ecc_point_g; public final ECDomainParameters ecc_bc_spec; public final ECKeyPairGenerator ecc_key_pair_generator; public final ECFieldElement ecc_gx_fieldelement; public final ECFieldElement ecc_gy_fieldelement; public SM2() { this.ecc_p = new BigInteger(ecc_param[0], 16); this.ecc_a = new BigInteger(ecc_param[1], 16); this.ecc_b = new BigInteger(ecc_param[2], 16); this.ecc_n = new BigInteger(ecc_param[3], 16); this.ecc_gx = new BigInteger(ecc_param[4], 16); this.ecc_gy = new BigInteger(ecc_param[5], 16); this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx); this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy); this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b); this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement); this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n); ECKeyGenerationParameters ecc_ecgenparam; ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom()); this.ecc_key_pair_generator = new ECKeyPairGenerator(); this.ecc_key_pair_generator.init(ecc_ecgenparam); }}
生成随机秘钥工具类
package cn.test.encrypt.utils.sm2;import cn.test.encrypt.utils.Util;import org.bouncycastle.crypto.AsymmetricCipherKeyPair;import org.bouncycastle.crypto.params.ECPrivateKeyParameters;import org.bouncycastle.crypto.params.ECPublicKeyParameters;import org.bouncycastle.math.ec.ECPoint;import java.io.IOException;import java.math.BigInteger;public class SM2EncDecUtils { //生成随机秘钥对 public static SM2KeyVO generateKeyPair(){ SM2 sm2 = SM2.Instance(); AsymmetricCipherKeyPair key = null; while (true){ key=sm2.ecc_key_pair_generator.generateKeyPair(); if(((ECPrivateKeyParameters) key.getPrivate()).getD().toByteArray().length==32){ break; } } ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); BigInteger privateKey = ecpriv.getD(); ECPoint publicKey = ecpub.getQ(); SM2KeyVO sm2KeyVO = new SM2KeyVO(); sm2KeyVO.setPublicKey(publicKey); sm2KeyVO.setPrivateKey(privateKey); //System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded())); //System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray())); return sm2KeyVO; } //数据加密 public static String encrypt(byte[] publicKey, byte[] data) throws IOException { if (publicKey == null || publicKey.length == 0) { return null; } if (data == null || data.length == 0) { return null; } byte[] source = new byte[data.length]; //将数组data复制到source System.arraycopy(data, 0, source, 0, data.length); Cipher cipher = new Cipher(); SM2 sm2 = SM2.Instance();//new自建类,, SM2 sm2 = new SM2(); ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey); ECPoint c1 = cipher.Init_enc(sm2, userKey); cipher.Encrypt(source); byte[] c3 = new byte[32]; cipher.Dofinal(c3); // System.out.println("C1 " + Util.byteToHex(c1.getEncoded())); // System.out.println("C2 " + Util.byteToHex(source)); //System.out.println("C3 " + Util.byteToHex(c3)); //C1 C2 C3拼装成加密字串 // C1 | C2 | C3 //return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3); // C1 | C3 | C2 return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(c3) + Util.byteToHex(source); } //数据解密 public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException { if (privateKey == null || privateKey.length == 0) { return null; } if (encryptedData == null || encryptedData.length == 0) { return null; } //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2 String data = Util.byteToHex(encryptedData); byte[] c1Bytes = Util.hexToByte(data.substring(0,130)); int c2Len = encryptedData.length - 97; byte[] c3 = Util.hexToByte(data.substring(130,130 + 64)); byte[] c2 = Util.hexToByte(data.substring(194,194 + 2 * c2Len)); SM2 sm2 = SM2.Instance(); BigInteger userD = new BigInteger(1, privateKey); //通过C1实体字节来生成ECPoint ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes); Cipher cipher = new Cipher(); cipher.Init_dec(userD, c1); cipher.Decrypt(c2); cipher.Dofinal(c3); //返回解密结果 return c2; }}
SM2曲线算法工具类
package cn.test.encrypt.utils.sm2;import cn.test.encrypt.utils.Util;import org.bouncycastle.crypto.AsymmetricCipherKeyPair;import org.bouncycastle.crypto.digests.SM3Digest;import org.bouncycastle.crypto.generators.ECKeyPairGenerator;import org.bouncycastle.crypto.params.ECDomainParameters;import org.bouncycastle.crypto.params.ECKeyGenerationParameters;import org.bouncycastle.crypto.params.ECPrivateKeyParameters;import org.bouncycastle.crypto.params.ECPublicKeyParameters;import org.bouncycastle.math.ec.ECCurve;import org.bouncycastle.math.ec.ECFieldElement;import org.bouncycastle.math.ec.ECFieldElement.Fp;import org.bouncycastle.math.ec.ECPoint;import java.math.BigInteger;import java.security.SecureRandom;public class SM2Factory {//A 第一系数private static final BigInteger a = new BigInteger("fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc",16);//B 第二系数private static final BigInteger b = new BigInteger("28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93",16);//曲线X系数private static final BigInteger gx = new BigInteger("32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7",16);//曲线Y系数private static final BigInteger gy = new BigInteger("bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0",16);//生产者顺序系数private static final BigInteger n = new BigInteger("fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123",16);//素数private static final BigInteger p = new BigInteger("fffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff",16);//因子系数 1private static final int h = 1;//一些必要类public final ECFieldElement ecc_gx_fieldelement;public final ECFieldElement ecc_gy_fieldelement;public final ECCurve ecc_curve;public final ECPoint ecc_point_g;public final ECDomainParameters ecc_bc_spec;public final ECKeyPairGenerator ecc_key_pair_generator;public static SM2Factory getInstance(){return new SM2Factory();}public SM2Factory() {this.ecc_gx_fieldelement = new Fp(this.p,this.gx);this.ecc_gy_fieldelement = new Fp(this.p, this.gy);this.ecc_curve = new ECCurve.Fp(this.p, this.a, this.b);this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement,this.ecc_gy_fieldelement);this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.n);ECKeyGenerationParameters ecc_ecgenparam;ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());this.ecc_key_pair_generator = new ECKeyPairGenerator();this.ecc_key_pair_generator.init(ecc_ecgenparam);}public byte[] sm2GetZ(byte[] userId, ECPoint userKey){SM3Digest sm3 = new SM3Digest();int len = userId.length * 8;sm3.update((byte) (len >> 8 & 0xFF));sm3.update((byte) (len & 0xFF));sm3.update(userId, 0, userId.length);byte[] p = Util.byteConvert32Bytes(this.a);sm3.update(p, 0, p.length);p = Util.byteConvert32Bytes(this.b);sm3.update(p, 0, p.length);p = Util.byteConvert32Bytes(this.gx);sm3.update(p, 0, p.length);p = Util.byteConvert32Bytes(this.gy);sm3.update(p, 0, p.length);p = Util.byteConvert32Bytes(userKey.normalize().getXCoord().toBigInteger());sm3.update(p, 0, p.length);p = Util.byteConvert32Bytes(userKey.normalize().getYCoord().toBigInteger());sm3.update(p, 0, p.length);byte[] md = new byte[sm3.getDigestSize()];sm3.doFinal(md, 0);return md;}public void sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Result) {BigInteger e = new BigInteger(1, md);BigInteger k = null;ECPoint kp = null;BigInteger r = null;BigInteger s = null;do {do {// 正式环境AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.generateKeyPair();ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate();ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();k = ecpriv.getD();kp = ecpub.getQ();//System.out.println("BigInteger:" + k + "\nECPoint:" + kp);//System.out.println("计算曲线点X1: "+ kp.getXCoord().toBigInteger().toString(16));//System.out.println("计算曲线点Y1: "+ kp.getYCoord().toBigInteger().toString(16));//System.out.println("");// rr = e.add(kp.getXCoord().toBigInteger());r = r.mod(this.n);} while (r.equals(BigInteger.ZERO) || r.add(k).equals(this.n)||r.toString(16).length()!=64);// (1 + dA)~-1BigInteger da_1 = userD.add(BigInteger.ONE);da_1 = da_1.modInverse(this.n);// ss = r.multiply(userD);s = k.subtract(s).mod(this.n);s = da_1.multiply(s).mod(this.n);} while (s.equals(BigInteger.ZERO)||(s.toString(16).length()!=64));sm2Result.r = r;sm2Result.s = s;}public void sm2Verify(byte md[], ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Result) {sm2Result.R = null;BigInteger e = new BigInteger(1, md);BigInteger t = r.add(s).mod(this.n);if (t.equals(BigInteger.ZERO)) {return;} else {ECPoint x1y1 = ecc_point_g.multiply(sm2Result.s);//System.out.println("计算曲线点X0: "+ x1y1.normalize().getXCoord().toBigInteger().toString(16));//System.out.println("计算曲线点Y0: "+ x1y1.normalize().getYCoord().toBigInteger().toString(16));//System.out.println("");x1y1 = x1y1.add(userKey.multiply(t));//System.out.println("计算曲线点X1: "+ x1y1.normalize().getXCoord().toBigInteger().toString(16));//System.out.println("计算曲线点Y1: "+ x1y1.normalize().getYCoord().toBigInteger().toString(16));//System.out.println("");sm2Result.R = e.add(x1y1.normalize().getXCoord().toBigInteger()).mod(this.n);//System.out.println("R: " + sm2Result.R.toString(16));return;}}}
工具类
package cn.test.encrypt.utils;import java.math.BigInteger;public class Util { public static byte[] intToBytes(int num) { byte[] bytes = new byte[4]; bytes[0] = (byte) (0xff & (num >> 0)); bytes[1] = (byte) (0xff & (num >> 8)); bytes[2] = (byte) (0xff & (num >> 16)); bytes[3] = (byte) (0xff & (num >> 24)); return bytes; } public static int byteToInt(byte[] bytes) { int num = 0; int temp; temp = (0x000000ff & (bytes[0])) << 0; num = num | temp; temp = (0x000000ff & (bytes[1])) << 8; num = num | temp; temp = (0x000000ff & (bytes[2])) << 16; num = num | temp; temp = (0x000000ff & (bytes[3])) << 24; num = num | temp; return num; } public static byte[] longToBytes(long num) { byte[] bytes = new byte[8]; for (int i = 0; i < 8; i++) { bytes[i] = (byte) (0xff & (num >> (i * 8))); } return bytes; } public static byte[] byteConvert32Bytes(BigInteger n) { byte tmpd[] = (byte[]) null; if (n == null) { return null; } if (n.toByteArray().length == 33) { tmpd = new byte[32]; System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32); } else if (n.toByteArray().length == 32) { tmpd = n.toByteArray(); } else { tmpd = new byte[32]; for (int i = 0; i < 32 - n.toByteArray().length; i++) { tmpd[i] = 0; } System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length); } return tmpd; } public static BigInteger byteConvertInteger(byte[] b) { if (b[0] < 0) { byte[] temp = new byte[b.length + 1]; temp[0] = 0; System.arraycopy(b, 0, temp, 1, b.length); return new BigInteger(temp); } return new BigInteger(b); } public static String getHexString(byte[] bytes) { return getHexString(bytes, true); } public static String getHexString(byte[] bytes, boolean upperCase) { String ret = ""; for (int i = 0; i < bytes.length; i++) { ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1); } return upperCase ? ret.toUpperCase() : ret; } public static void printHexString(byte[] bytes) { for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } System.out.print("0x" + hex.toUpperCase() + ","); } System.out.println(""); } public static byte[] hexStringToBytes(String hexString) { if (hexString == null || hexString.equals("")) { return null; } hexString = hexString.toUpperCase(); int length = hexString.length() / 2; char[] hexChars = hexString.toCharArray(); byte[] d = new byte[length]; for (int i = 0; i < length; i++) { int pos = i * 2; d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); } return d; } public static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; public static char[] encodeHex(byte[] data) { return encodeHex(data, true); } public static char[] encodeHex(byte[] data, boolean toLowerCase) { return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } protected static char[] encodeHex(byte[] data, char[] toDigits) { int l = data.length; char[] out = new char[l << 1]; // two characters form the hex value. for (int i = 0, j = 0; i < l; i++) { out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; out[j++] = toDigits[0x0F & data[i]]; } return out; } public static String encodeHexString(byte[] data) { return encodeHexString(data, true); } public static String encodeHexString(byte[] data, boolean toLowerCase) { return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } protected static String encodeHexString(byte[] data, char[] toDigits) { return new String(encodeHex(data, toDigits)); } public static byte[] decodeHex(char[] data) { int len = data.length; if ((len & 0x01) != 0) { throw new RuntimeException("Odd number of characters."); } byte[] out = new byte[len >> 1]; // two characters form the hex value. for (int i = 0, j = 0; j < len; i++) { int f = toDigit(data[j], j) << 4; j++; f = f | toDigit(data[j], j); j++; out[i] = (byte) (f & 0xFF); } return out; } protected static int toDigit(char ch, int index) { int digit = Character.digit(ch, 16); if (digit == -1) { throw new RuntimeException("Illegal hexadecimal character " + ch + " at index " + index); } return digit; } public static String StringToAsciiString(String content) { String result = ""; int max = content.length(); for (int i = 0; i < max; i++) { char c = content.charAt(i); String b = Integer.toHexString(c); result = result + b; } return result; } public static String hexStringToString(String hexString, int encodeType) { String result = ""; int max = hexString.length() / encodeType; for (int i = 0; i < max; i++) { char c = (char) hexStringToAlgorism(hexString .substring(i * encodeType, (i + 1) * encodeType)); result += c; } return result; } public static int hexStringToAlgorism(String hex) { hex = hex.toUpperCase(); int max = hex.length(); int result = 0; for (int i = max; i > 0; i--) { char c = hex.charAt(i - 1); int algorism = 0; if (c >= '0' && c <= '9') { algorism = c - '0'; } else { algorism = c - 55; } result += Math.pow(16, max - i) * algorism; } return result; } public static String hexStringToBinary(String hex) { hex = hex.toUpperCase(); String result = ""; int max = hex.length(); for (int i = 0; i < max; i++) { char c = hex.charAt(i); switch (c) { case '0': result += "0000"; break; case '1': result += "0001"; break; case '2': result += "0010"; break; case '3': result += "0011"; break; case '4': result += "0100"; break; case '5': result += "0101"; break; case '6': result += "0110"; break; case '7': result += "0111"; break; case '8': result += "1000"; break; case '9': result += "1001"; break; case 'A': result += "1010"; break; case 'B': result += "1011"; break; case 'C': result += "1100"; break; case 'D': result += "1101"; break; case 'E': result += "1110"; break; case 'F': result += "1111"; break; } } return result; } public static String AsciiStringToString(String content) { String result = ""; int length = content.length() / 2; for (int i = 0; i < length; i++) { String c = content.substring(i * 2, i * 2 + 2); int a = hexStringToAlgorism(c); char b = (char) a; String d = String.valueOf(b); result += d; } return result; } public static String algorismToHexString(int algorism, int maxLength) { String result = ""; result = Integer.toHexString(algorism); if (result.length() % 2 == 1) { result = "0" + result; } return patchHexString(result.toUpperCase(), maxLength); } public static String byteToString(byte[] bytearray) { String result = ""; char temp; int length = bytearray.length; for (int i = 0; i < length; i++) { temp = (char) bytearray[i]; result += temp; } return result; } public static int binaryToAlgorism(String binary) { int max = binary.length(); int result = 0; for (int i = max; i > 0; i--) { char c = binary.charAt(i - 1); int algorism = c - '0'; result += Math.pow(2, max - i) * algorism; } return result; } public static String algorismToHEXString(int algorism) { String result = ""; result = Integer.toHexString(algorism); if (result.length() % 2 == 1) { result = "0" + result; } result = result.toUpperCase(); return result; } static public String patchHexString(String str, int maxLength) { String temp = ""; for (int i = 0; i < maxLength - str.length(); i++) { temp = "0" + temp; } str = (temp + str).substring(0, maxLength); return str; } public static int parseToInt(String s, int defaultInt, int radix) { int i = 0; try { i = Integer.parseInt(s, radix); } catch (NumberFormatException ex) { i = defaultInt; } return i; } public static int parseToInt(String s, int defaultInt) { int i = 0; try { i = Integer.parseInt(s); } catch (NumberFormatException ex) { i = defaultInt; } return i; } public static byte[] hexToByte(String hex) throws IllegalArgumentException { if (hex.length() % 2 != 0) { throw new IllegalArgumentException(); } char[] arr = hex.toCharArray(); byte[] b = new byte[hex.length() / 2]; for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) { String swap = "" + arr[i++] + arr[i]; int byteint = Integer.parseInt(swap, 16) & 0xFF; b[j] = new Integer(byteint).byteValue(); } return b; } public static String byteToHex(byte b[]) { if (b == null) { throw new IllegalArgumentException( "Argument b ( byte array ) is null! "); } String hs = ""; String stmp = ""; for (int n = 0; n < b.length; n++) { stmp = Integer.toHexString(b[n] & 0xff); if (stmp.length() == 1) { hs = hs + "0" + stmp; } else { hs = hs + stmp; } } return hs.toLowerCase(); //return hs.toUpperCase(); } public static byte[] subByte(byte[] input, int startIndex, int length) { byte[] bt = new byte[length]; for (int i = 0; i < length; i++) { bt[i] = input[i + startIndex]; } return bt; }}
SM2对象
package cn.test.encrypt.utils.sm2;import cn.test.encrypt.utils.Util;import cn.test.encrypt.test.SecurityTestAll;import org.bouncycastle.math.ec.ECPoint;import java.math.BigInteger;public class SM2KeyVO { BigInteger privateKey ; ECPoint publicKey ; public BigInteger getPrivateKey() { return privateKey; } public void setPrivateKey(BigInteger privateKey) { this.privateKey = privateKey; } public ECPoint getPublicKey() { return publicKey; } public void setPublicKey(ECPoint publicKey) { this.publicKey = publicKey; } //HardPubKey:3059301306072A8648CE3D020106082A811CCF5501822D03420004+X+Y //SoftPubKey:04+X+Y public String getPubHexInSoft(){ return Util.byteToHex(publicKey.getEncoded(true)); //System.out.println("公钥: " + ); } public String getPubHexInHard(){ return SecurityTestAll.SM2PubHardKeyHead +Util.byteToHex(publicKey.getEncoded(true)); } public String getPriHexInSoft(){ return Util.byteToHex(privateKey.toByteArray()); }}
测试Demo
public static void main(String[] args) { SM2KeyVO initKeyVO = SM2EncDecUtils.generateKeyPair(); System.out.println("初始公钥为: "+initKeyVO.getPubHexInSoft()); System.out.println("初始私钥为: "+initKeyVO.getPriHexInSoft()); }
输出结果:
2、数据加解密
简单业务描述:使用初始公钥加密工作公钥,使用初始私钥解密加密后公钥;
Demo
public static void main(String[] args) throws IOException { //生成初始秘钥 SM2KeyVO initKeyVO = SM2EncDecUtils.generateKeyPair(); String initPubKey = initKeyVO.getPubHexInSoft(); String initPriKey = initKeyVO.getPriHexInSoft(); System.out.println("初始公钥为: " + initPubKey); System.out.println("初始私钥为: " + initPriKey); //生成工作秘钥 SM2KeyVO serverKey = SM2EncDecUtils.generateKeyPair(); String serverPubKey = serverKey.getPubHexInSoft(); String serverPriKey = serverKey.getPriHexInSoft(); System.out.println("服务端公钥为: " + serverPubKey); System.out.println("服务端私钥为: " + serverPriKey); //使用初始公钥加密服务端公钥 注意格式字节数组 String encryptServerPubKey = SM2EncDecUtils.encrypt(Convert.hexToBytes(initPubKey), serverPubKey.getBytes()); System.out.println("加密后公钥:"+encryptServerPubKey); //使用初始私钥解密服务端公钥 注意格式 byte[] decrypt = SM2EncDecUtils.decrypt(Convert.hexToBytes(initPriKey), Convert.hexToBytes(encryptServerPubKey)); System.out.println("解密后服务端公钥:"+new String(decrypt)); if (serverPubKey.equals(new String(decrypt))) System.out.println("——————————解密成功——————————"); }
结果:
至此,SM2的公私钥生成以及加解密就完成了,下一期内容为生成Sign以及验证。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341