bcprov-jdk15on实现例子
Maven依赖:
1 2 3 4 5 |
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.54</version> </dependency> |
Java实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
import java.math.BigInteger; import java.security.SecureRandom; import java.util.Arrays; import org.bouncycastle.crypto.DerivationFunction; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.ShortenedDigest; import org.bouncycastle.crypto.generators.KDF1BytesGenerator; import org.bouncycastle.crypto.params.ISO18033KDFParameters; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; /** * <B>说 明<B/>:SM2的非对称加解密工具类,椭圆曲线方程为:y^2=x^3+ax+b 使用Fp-256 */ public class SM2Util { /** 素数p */ private static final BigInteger p = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFF", 16); /** 系数a */ private static final BigInteger a = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFC", 16); /** 系数b */ private static final BigInteger b = new BigInteger("28E9FA9E" + "9D9F5E34" + "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41" + "4D940E93", 16); /** 坐标x */ private static final BigInteger xg = new BigInteger("32C4AE2C" + "1F198119" + "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589" + "334C74C7", 16); /** 坐标y */ private static final BigInteger yg = new BigInteger("BC3736A2" + "F4F6779C" + "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5" + "2139F0A0", 16); /** 基点G, G=(xg,yg),其介记为n */ private static final BigInteger n = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409" + "39D54123", 16); private static SecureRandom random = new SecureRandom(); private ECCurve.Fp curve; private ECPoint G; public static String printHexString(byte[] b) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < b.length; i++) { String hex = Integer.toHexString(b[i] & 0xFF); if (hex.length() == 1) { builder.append('0'+hex); hex = '0' + hex; } // System.out.print(hex.toUpperCase()); System.out.print(hex.toUpperCase()); builder.append(hex); } System.out.println(); return builder.toString(); } public BigInteger random(BigInteger max) { BigInteger r = new BigInteger(256, random); // int count = 1; while (r.compareTo(max) >= 0) { r = new BigInteger(128, random); // count++; } // System.out.println("count: " + count); return r; } private boolean allZero(byte[] buffer) { for (int i = 0; i < buffer.length; i++) { if (buffer[i] != 0) return false; } return true; } /** * 加密 * @param input 待加密消息M * @param publicKey 公钥 * @return byte[] 加密后的字节数组 */ public byte[] encrypt(String input, ECPoint publicKey) { System.out.println("publicKey is: "+publicKey); byte[] inputBuffer = input.getBytes(); printHexString(inputBuffer); /* 1 产生随机数k,k属于[1, n-1] */ BigInteger k = random(n); System.out.print("k: "); printHexString(k.toByteArray()); /* 2 计算椭圆曲线点C1 = [k]G = (x1, y1) */ ECPoint C1 = G.multiply(k); byte[] C1Buffer = C1.getEncoded(false); System.out.print("C1: "); printHexString(C1Buffer); // 3 计算椭圆曲线点 S = [h]Pb * curve没有指定余因子,h为空 // BigInteger h = curve.getCofactor(); System.out.print("h: "); // printHexString(h.toByteArray()); if (publicKey != null) { ECPoint // result = publicKey.multiply(h); if (!result.isInfinity()) { // System.out.println("pass"); } else { // System.err.println("计算椭圆曲线点 S = [h]Pb失败"); return null; } } /* 4 计算 [k]PB = (x2, y2) */ ECPoint kpb = publicKey.multiply(k).normalize(); /* 5 计算 t = KDF(x2||y2, klen) */ byte[] kpbBytes = kpb.getEncoded(false); DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest( new SHA256Digest(), 20)); byte[] t = new byte[inputBuffer.length]; kdf.init(new ISO18033KDFParameters(kpbBytes)); kdf.generateBytes(t, 0, t.length); if (allZero(t)) { System.err.println("all zero"); } /* 6 计算C2=M^t */ byte[] C2 = new byte[inputBuffer.length]; for (int i = 0; i < inputBuffer.length; i++) { C2[i] = (byte) (inputBuffer[i] ^ t[i]); } /* 7 计算C3 = Hash(x2 || M || y2) */ byte[] C3 = calculateHash(kpb.getXCoord().toBigInteger(), inputBuffer, kpb.getYCoord().toBigInteger()); /* 8 输出密文 C=C1 || C2 || C3 */ byte[] encryptResult = new byte[C1Buffer.length + C2.length + C3.length]; System.arraycopy(C1Buffer, 0, encryptResult, 0, C1Buffer.length); System.arraycopy(C2, 0, encryptResult, C1Buffer.length, C2.length); System.arraycopy(C3, 0, encryptResult, C1Buffer.length + C2.length, C3.length); System.out.print("密文: "); printHexString(encryptResult); return encryptResult; } public void decrypt(byte[] encryptData, BigInteger privateKey) { System.out.println("privateKey is: "+privateKey); System.out.println("encryptData length: " + encryptData.length); byte[] C1Byte = new byte[65]; System.arraycopy(encryptData, 0, C1Byte, 0, C1Byte.length); ECPoint C1 = curve.decodePoint(C1Byte).normalize(); /* 计算[dB]C1 = (x2, y2) */ ECPoint dBC1 = C1.multiply(privateKey).normalize(); /* 计算t = KDF(x2 || y2, klen) */ byte[] dBC1Bytes = dBC1.getEncoded(false); DerivationFunction kdf = new KDF1BytesGenerator(new ShortenedDigest( new SHA256Digest(), 20)); int klen = encryptData.length - 65 - 20; System.out.println("klen = " + klen); byte[] t = new byte[klen]; kdf.init(new ISO18033KDFParameters(dBC1Bytes)); kdf.generateBytes(t, 0, t.length); if (allZero(t)) { System.err.println("all zero"); } /* 5 计算M'=C2^t */ byte[] M = new byte[klen]; for (int i = 0; i < M.length; i++) { M[i] = (byte) (encryptData[C1Byte.length + i] ^ t[i]); } /* 6 计算 u = Hash(x2 || M' || y2) 判断 u == C3是否成立 */ byte[] C3 = new byte[20]; System.arraycopy(encryptData, encryptData.length - 20, C3, 0, 20); byte[] u = calculateHash(dBC1.getXCoord().toBigInteger(), M, dBC1 .getYCoord().toBigInteger()); if (Arrays.equals(u, C3)) { System.out.println("解密成功"); System.out.println("M' = " + new String(M)); } else { System.out.print("u = "); printHexString(u); System.out.print("C3 = "); printHexString(C3); System.err.println("解密验证失败"); } } private byte[] calculateHash(BigInteger x2, byte[] M, BigInteger y2) { ShortenedDigest digest = new ShortenedDigest(new SHA256Digest(), 20); byte[] buf = x2.toByteArray(); digest.update(buf, 0, buf.length); digest.update(M, 0, M.length); buf = y2.toByteArray(); digest.update(buf, 0, buf.length); buf = new byte[20]; digest.doFinal(buf, 0); return buf; } private boolean between(BigInteger param, BigInteger min, BigInteger max) { if (param.compareTo(min) >= 0 && param.compareTo(max) < 0) { return true; } else { return false; } } /** * 公钥校验 * @param publicKey 公钥 * @return boolean true或false */ private boolean checkPublicKey(ECPoint publicKey) { if (!publicKey.isInfinity()) { BigInteger x = publicKey.getXCoord().toBigInteger(); BigInteger y = publicKey.getYCoord().toBigInteger(); if (between(x, new BigInteger("0"), p) && between(y, new BigInteger("0"), p)) { BigInteger xResult = x.pow(3).add(a.multiply(x)).add(b).mod(p); System.out.println("xResult: " + xResult.toString()); BigInteger yResult = y.pow(2).mod(p); System.out.println("yResult: " + yResult.toString()); if (yResult.equals(xResult) && publicKey.multiply(n).isInfinity()) { return true; } } return false; } else { return false; } } /** * 获得公私钥对 * @return */ public SM2KeyPair generateKeyPair() { BigInteger d = random(n.subtract(new BigInteger("1"))); SM2KeyPair keyPair = new SM2KeyPair(G.multiply(d).normalize(), d); if (checkPublicKey(keyPair.getPublicKey())) { System.out.println("generate key successfully"); return keyPair; } else { System.err.println("generate key failed"); return null; } } public SM2Util() { curve = new ECCurve.Fp(p, // q a, // a b); // b G = curve.createPoint(xg, yg); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import java.math.BigInteger; import org.bouncycastle.math.ec.ECPoint; /** * <B>说 明<B/>:SM2公私钥实体类 */ public class SM2KeyPair { /** 公钥 */ private ECPoint publicKey; /** 私钥 */ private BigInteger privateKey; SM2KeyPair(ECPoint publicKey, BigInteger privateKey) { this.publicKey = publicKey; this.privateKey = privateKey; } public ECPoint getPublicKey() { return publicKey; } public BigInteger getPrivateKey() { return privateKey; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import java.util.Arrays; /** * <B>说 明<B/>:SM2非对称加解密工具类测试 */ public class SM2UtilTest { /** 元消息串 */ private static String M = "哈哈哈,&*&…………&、、//\\!@#$%^&*()物品woyebuzhidaowozijiqiaodesha!@#$%^&*())))))ooooooooppppppppppppppppppplllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkffffffffffffffffffffffffffffffffffffff"; public static void main(String[] args) { SM2Util sm2 = new SM2Util(); SM2KeyPair keyPair = sm2.generateKeyPair(); byte[] data = sm2.encrypt(M,keyPair.getPublicKey()); System.out.println("data is:"+Arrays.toString(data)); sm2.decrypt(data, keyPair.getPrivateKey());//71017045908707391874054405929626258767106914144911649587813342322113806533034 } } |
bcprov-jdk16实现例子
1 2 3 4 5 |
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
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.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(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
public class SM3 { public static final byte[] iv = {0x73, (byte) 0x80, 0x16, 0x6f, 0x49, 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7, (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30, (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3, (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e, 0x4e}; public static int[] Tj = new int[64]; static { for (int i = 0; i < 16; i++) { Tj[i] = 0x79cc4519; } for (int i = 16; i < 64; i++) { Tj[i] = 0x7a879d8a; } } public static byte[] CF(byte[] V, byte[] B) { int[] v, b; v = convert(V); b = convert(B); return convert(CF(v, b)); } private static int[] convert(byte[] arr) { int[] out = new int[arr.length / 4]; byte[] tmp = new byte[4]; for (int i = 0; i < arr.length; i += 4) { System.arraycopy(arr, i, tmp, 0, 4); out[i / 4] = bigEndianByteToInt(tmp); } return out; } private static byte[] convert(int[] arr) { byte[] out = new byte[arr.length * 4]; byte[] tmp = null; for (int i = 0; i < arr.length; i++) { tmp = bigEndianIntToByte(arr[i]); System.arraycopy(tmp, 0, out, i * 4, 4); } return out; } public static int[] CF(int[] V, int[] B) { int a, b, c, d, e, f, g, h; int ss1, ss2, tt1, tt2; a = V[0]; b = V[1]; c = V[2]; d = V[3]; e = V[4]; f = V[5]; g = V[6]; h = V[7]; int[][] arr = expand(B); int[] w = arr[0]; int[] w1 = arr[1]; for (int j = 0; j < 64; j++) { ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j)); ss1 = bitCycleLeft(ss1, 7); ss2 = ss1 ^ bitCycleLeft(a, 12); tt1 = FFj(a, b, c, j) + d + ss2 + w1[j]; tt2 = GGj(e, f, g, j) + h + ss1 + w[j]; d = c; c = bitCycleLeft(b, 9); b = a; a = tt1; h = g; g = bitCycleLeft(f, 19); f = e; e = P0(tt2); /*System.out.print(j+" "); System.out.print(Integer.toHexString(a)+" "); System.out.print(Integer.toHexString(b)+" "); System.out.print(Integer.toHexString(c)+" "); System.out.print(Integer.toHexString(d)+" "); System.out.print(Integer.toHexString(e)+" "); System.out.print(Integer.toHexString(f)+" "); System.out.print(Integer.toHexString(g)+" "); System.out.print(Integer.toHexString(h)+" "); System.out.println("");*/ } // System.out.println(""); int[] out = new int[8]; out[0] = a ^ V[0]; out[1] = b ^ V[1]; out[2] = c ^ V[2]; out[3] = d ^ V[3]; out[4] = e ^ V[4]; out[5] = f ^ V[5]; out[6] = g ^ V[6]; out[7] = h ^ V[7]; return out; } private static int[][] expand(int[] B) { int[] W = new int[68]; int[] W1 = new int[64]; for (int i = 0; i < B.length; i++) { W[i] = B[i]; } for (int i = 16; i < 68; i++) { W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15)) ^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6]; } for (int i = 0; i < 64; i++) { W1[i] = W[i] ^ W[i + 4]; } int[][] arr = new int[][]{W, W1}; return arr; } private static byte[] bigEndianIntToByte(int num) { return back(Util.intToBytes(num)); } private static int bigEndianByteToInt(byte[] bytes) { return Util.byteToInt(back(bytes)); } private static int FFj(int X, int Y, int Z, int j) { if (j >= 0 && j <= 15) { return FF1j(X, Y, Z); } else { return FF2j(X, Y, Z); } } private static int GGj(int X, int Y, int Z, int j) { if (j >= 0 && j <= 15) { return GG1j(X, Y, Z); } else { return GG2j(X, Y, Z); } } // 逻辑位运算函数 private static int FF1j(int X, int Y, int Z) { int tmp = X ^ Y ^ Z; return tmp; } private static int FF2j(int X, int Y, int Z) { int tmp = ((X & Y) | (X & Z) | (Y & Z)); return tmp; } private static int GG1j(int X, int Y, int Z) { int tmp = X ^ Y ^ Z; return tmp; } private static int GG2j(int X, int Y, int Z) { int tmp = (X & Y) | (~X & Z); return tmp; } private static int P0(int X) { int y = rotateLeft(X, 9); y = bitCycleLeft(X, 9); int z = rotateLeft(X, 17); z = bitCycleLeft(X, 17); int t = X ^ y ^ z; return t; } private static int P1(int X) { int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23); return t; } /** * 对最后一个分组字节数据padding * * @param in * @param bLen 分组个数 * @return */ public static byte[] padding(byte[] in, int bLen) { int k = 448 - (8 * in.length + 1) % 512; if (k < 0) { k = 960 - (8 * in.length + 1) % 512; } k += 1; byte[] padd = new byte[k / 8]; padd[0] = (byte) 0x80; long n = in.length * 8 + bLen * 512; byte[] out = new byte[in.length + k / 8 + 64 / 8]; int pos = 0; System.arraycopy(in, 0, out, 0, in.length); pos += in.length; System.arraycopy(padd, 0, out, pos, padd.length); pos += padd.length; byte[] tmp = back(Util.longToBytes(n)); System.arraycopy(tmp, 0, out, pos, tmp.length); return out; } /** * 字节数组逆序 * * @param in * @return */ private static byte[] back(byte[] in) { byte[] out = new byte[in.length]; for (int i = 0; i < out.length; i++) { out[i] = in[out.length - i - 1]; } return out; } public static int rotateLeft(int x, int n) { return (x << n) | (x >> (32 - n)); } private static int bitCycleLeft(int n, int bitLen) { bitLen %= 32; byte[] tmp = bigEndianIntToByte(n); int byteLen = bitLen / 8; int len = bitLen % 8; if (byteLen > 0) { tmp = byteCycleLeft(tmp, byteLen); } if (len > 0) { tmp = bitSmall8CycleLeft(tmp, len); } return bigEndianByteToInt(tmp); } private static byte[] bitSmall8CycleLeft(byte[] in, int len) { byte[] tmp = new byte[in.length]; int t1, t2, t3; for (int i = 0; i < tmp.length; i++) { t1 = (byte) ((in[i] & 0x000000ff) << len); t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len)); t3 = (byte) (t1 | t2); tmp[i] = (byte) t3; } return tmp; } private static byte[] byteCycleLeft(byte[] in, int byteLen) { byte[] tmp = new byte[in.length]; System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen); System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen); return tmp; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
import org.bouncycastle.util.encoders.Hex; public class SM3Digest { /** * SM3值的长度 */ private static final int BYTE_LENGTH = 32; /** * SM3分组长度 */ private static final int BLOCK_LENGTH = 64; /** * 缓冲区长度 */ private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1; /** * 缓冲区 */ private byte[] xBuf = new byte[BUFFER_LENGTH]; /** * 缓冲区偏移量 */ private int xBufOff; /** * 初始向量 */ private byte[] V = SM3.iv.clone(); private int cntBlock = 0; public SM3Digest() { } public SM3Digest(SM3Digest t) { System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length); this.xBufOff = t.xBufOff; System.arraycopy(t.V, 0, this.V, 0, t.V.length); } public static void main(String[] args) { byte[] md = new byte[32]; byte[] msg1 = "ererfeiisgod".getBytes(); SM3Digest sm3 = new SM3Digest(); sm3.update(msg1, 0, msg1.length); sm3.doFinal(md, 0); String s = new String(Hex.encode(md)); System.out.println(s.toUpperCase()); } /** * SM3结果输出 * * @param out 保存SM3结构的缓冲区 * @param outOff 缓冲区偏移量 * @return */ public int doFinal(byte[] out, int outOff) { byte[] tmp = doFinal(); System.arraycopy(tmp, 0, out, 0, tmp.length); return BYTE_LENGTH; } public void reset() { xBufOff = 0; cntBlock = 0; V = SM3.iv.clone(); } /** * 明文输入 * * @param in 明文输入缓冲区 * @param inOff 缓冲区偏移量 * @param len 明文长度 */ public void update(byte[] in, int inOff, int len) { int partLen = BUFFER_LENGTH - xBufOff; int inputLen = len; int dPos = inOff; if (partLen < inputLen) { System.arraycopy(in, dPos, xBuf, xBufOff, partLen); inputLen -= partLen; dPos += partLen; doUpdate(); while (inputLen > BUFFER_LENGTH) { System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH); inputLen -= BUFFER_LENGTH; dPos += BUFFER_LENGTH; doUpdate(); } } System.arraycopy(in, dPos, xBuf, xBufOff, inputLen); xBufOff += inputLen; } private void doUpdate() { byte[] B = new byte[BLOCK_LENGTH]; for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH) { System.arraycopy(xBuf, i, B, 0, B.length); doHash(B); } xBufOff = 0; } private void doHash(byte[] B) { byte[] tmp = SM3.CF(V, B); System.arraycopy(tmp, 0, V, 0, V.length); cntBlock++; } private byte[] doFinal() { byte[] B = new byte[BLOCK_LENGTH]; byte[] buffer = new byte[xBufOff]; System.arraycopy(xBuf, 0, buffer, 0, buffer.length); byte[] tmp = SM3.padding(buffer, cntBlock); for (int i = 0; i < tmp.length; i += BLOCK_LENGTH) { System.arraycopy(tmp, i, B, 0, B.length); doHash(B); } return V; } public void update(byte in) { byte[] buffer = new byte[]{in}; update(buffer, 0, 1); } public int getDigestSize() { return BYTE_LENGTH; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
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 final String[] ecc_param = { // "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", // "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", // "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", // "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", // "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", // "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" // }; //正式参数 public static String[] ecc_param = { "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" }; 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); } public static SM2 Instance() { return new SM2(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
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 SM2Utils { //生成随机秘钥对 public static void generateKeyPair() { SM2 sm2 = SM2.Instance(); AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair(); ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate(); ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic(); BigInteger privateKey = ecpriv.getD(); ECPoint publicKey = ecpub.getQ(); System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded())); System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray())); } //数据加密 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]; System.arraycopy(data, 0, source, 0, data.length); Cipher cipher = new Cipher(); SM2 sm2 = SM2.Instance(); 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拼装成加密字串 return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3); } //数据解密 //c3InFront 硬件为了方便加解密数据,把定长的C3放在变长的C2前面,由默认的C1C2C3调整成C1C3C2的格式 public static byte[] decrypt(byte[] privateKey, byte[] encryptedData, boolean c3InFront) 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); /***分解加密字串 * (C1 = C1标志位2位 + C1实体部分128位 = 130) * (C3 = C3实体部分64位 = 64) * (C2 = encryptedData.length * 2 - C1长度 - C2长度) */ byte[] c1Bytes = Util.hexToByte(data.substring(0, 130)); byte[] c2; byte[] c3; if (c3InFront) { c3 = Util.hexToByte(data.substring(130, 64)); c2 = Util.hexToByte(data.substring(130 + 64)); } else { /***C1 || C2 || C3 的意思就是拼在一起,而不是做什么或运算 * * 根据国密推荐的SM2椭圆曲线公钥密码算法,首先产生随机数计算出曲线点C1, * 2个32byte的BIGNUM大数,即为SM2加密结果的第1部分(C1)。 * 第2部分则是真正的密文,是对明文的加密结果,长度和明文一样(C2)。 * 第3部分是杂凑值,用来效验数据(C3)。按国密推荐的256位椭圆曲线, * 明文加密结果比原长度会大97byte(C1使用EC_POINT_point2oct转换)。 * */ int c2Len = encryptedData.length - 97; c2 = Util.hexToByte(data.substring(130, 130 + 2 * c2Len)); c3 = Util.hexToByte(data.substring(130 + 2 * c2Len, 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; } public static void main(String[] args) throws Exception { //生成密钥对 generateKeyPair(); String plainText = "ererfeiisgod"; byte[] sourceData = plainText.getBytes(); //下面的秘钥可以使用generateKeyPair()生成的秘钥内容 // 国密规范正式私钥 String prik = "3690655E33D5EA3D9A4AE1A1ADD766FDEA045CDEAA43A9206FB8C430CEFE0D94"; // 国密规范正式公钥 String pubk = "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A"; System.out.println("加密: "); String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData); System.out.println(cipherText); System.out.println("解密: "); plainText = new String(SM2Utils.decrypt(Util.hexToByte(prik), Util.hexToByte(cipherText), false)); System.out.println(plainText); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
import java.math.BigInteger; public class Util { /** * 用于建立十六进制字符的输出的小写字符数组 */ 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'}; /** * 整形转换成网络传输的字节流(字节数组)型数据 * * @param num 一个整型数据 * @return 4个字节的自己数组 */ 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; } /** * 四个字节的字节数据转换成一个整形数据 * * @param bytes 4个字节的字节数组 * @return 一个整型数据 */ 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; } /** * 长整形转换成网络传输的字节流(字节数组)型数据 * * @param num 一个长整型数据 * @return 4个字节的自己数组 */ 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; } /** * 大数字转换字节流(字节数组)型数据 * * @param n * @return */ public static byte[] byteConvert32Bytes(BigInteger n) { byte[] tmpd = 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; } /** * 换字节流(字节数组)型数据转大数字 * * @param b * @return */ 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); } /** * 根据字节数组获得值(十六进制数字) * * @param bytes * @return */ public static String getHexString(byte[] bytes) { return getHexString(bytes, true); } /** * 根据字节数组获得值(十六进制数字) * * @param bytes * @param upperCase * @return */ 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; } /** * 打印十六进制字符串 * * @param bytes */ 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(); } /** * Convert hex string to byte[] * * @param hexString the hex string * @return byte[] */ 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; } /** * Convert char to byte * * @param c char * @return byte */ public static byte charToByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } /** * 将字节数组转换为十六进制字符数组 * * @param data byte[] * @return 十六进制char[] */ public static char[] encodeHex(byte[] data) { return encodeHex(data, true); } /** * 将字节数组转换为十六进制字符数组 * * @param data byte[] * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 * @return 十六进制char[] */ public static char[] encodeHex(byte[] data, boolean toLowerCase) { return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } /** * 将字节数组转换为十六进制字符数组 * * @param data byte[] * @param toDigits 用于控制输出的char[] * @return 十六进制char[] */ 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; } /** * 将字节数组转换为十六进制字符串 * * @param data byte[] * @return 十六进制String */ public static String encodeHexString(byte[] data) { return encodeHexString(data, true); } /** * 将字节数组转换为十六进制字符串 * * @param data byte[] * @param toLowerCase <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式 * @return 十六进制String */ public static String encodeHexString(byte[] data, boolean toLowerCase) { return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); } /** * 将字节数组转换为十六进制字符串 * * @param data byte[] * @param toDigits 用于控制输出的char[] * @return 十六进制String */ protected static String encodeHexString(byte[] data, char[] toDigits) { return new String(encodeHex(data, toDigits)); } /** * 将十六进制字符数组转换为字节数组 * * @param data 十六进制char[] * @return byte[] * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常 */ 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; } /** * 将十六进制字符转换成一个整数 * * @param ch 十六进制char * @param index 十六进制字符在字符数组中的位置 * @return 一个整数 * @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常 */ 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; } /** * 数字字符串转ASCII码字符串 * * @param content 字符串 * @return ASCII字符串 */ 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; } /** * 十六进制转字符串 * * @param hexString 十六进制字符串 * @param encodeType 编码类型4:Unicode,2:普通编码 * @return 字符串 */ 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; } /** * 十六进制字符串装十进制 * * @param hex 十六进制字符串 * @return 十进制数值 */ 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; } /** * 十六转二进制 * * @param hex 十六进制字符串 * @return 二进制字符串 */ 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; } /** * ASCII码字符串转数字字符串 * * @param content ASCII字符串 * @return 字符串 */ 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; } /** * 将十进制转换为指定长度的十六进制字符串 * * @param algorism int 十进制数字 * @param maxLength int 转换后的十六进制字符串长度 * @return String 转换后的十六进制字符串 */ 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); } /** * 字节数组转为普通字符串(ASCII对应的字符) * * @param bytearray byte[] * @return String */ 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; } /** * 二进制字符串转十进制 * * @param binary 二进制字符串 * @return 十进制数值 */ 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; } /** * 十进制转换为十六进制字符串 * * @param algorism int 十进制的数字 * @return String 对应的十六进制字符串 */ 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; } /** * HEX字符串前补0,主要用于长度位数不足。 * * @param str String 需要补充长度的十六进制字符串 * @param maxLength int 补充后十六进制字符串的长度 * @return 补充结果 */ 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; } /** * 将一个字符串转换为int * * @param s String 要转换的字符串 * @param defaultInt int 如果出现异常,默认返回的数字 * @param radix int 要转换的字符串是什么进制的,如16 8 10. * @return int 转换后的数字 */ 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; } /** * 将一个十进制形式的数字字符串转换为int * * @param s String 要转换的字符串 * @param defaultInt int 如果出现异常,默认返回的数字 * @return int 转换后的数字 */ public static int parseToInt(String s, int defaultInt) { int i = 0; try { i = Integer.parseInt(s); } catch (NumberFormatException ex) { i = defaultInt; } return i; } /** * 十六进制串转化为byte数组 * * @return the array of byte */ 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; } /** * 字节数组转换为十六进制字符串 * * @param b byte[] 需要转换的字节数组 * @return String 十六进制字符串 */ 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.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椭圆曲线公钥密码算法,首先产生随机数计算出曲线点C1,2个32byte的BIGNUM大数,即为SM2加密结果的第1部分(C1)。第2部分则是真正的密文,是对明文的加密结果,长度和明文一样(C2)。第3部分是杂凑值,用来效验数据(C3)。按国密推荐的256位椭圆曲线,明文加密结果比原长度会大97byte(C1使用EC_POINT_point2oct转换)。
我们可以利用 密文,长度和明文一样(C2)这个原理,来跟踪现实中的调试问题,我们在没办法解密用户输入数据的内容的情况下,可以知道用户输入内容的长度,也能辅助我们解决很多调试问题。
上述的代码还可参考 Java—bouncycastle支持国密SM2的公钥加密算法