├── src
├── main
│ └── java
│ │ └── com
│ │ └── heshidai
│ │ └── security
│ │ └── cipher
│ │ ├── tip.txt
│ │ ├── SM4_Context.java
│ │ ├── SM2Result.java
│ │ ├── SM3Digest.java
│ │ ├── Cipher.java
│ │ ├── SM4Utils.java
│ │ ├── SM2Utils.java
│ │ ├── SM2.java
│ │ ├── SM3.java
│ │ ├── SM4.java
│ │ └── Util.java
└── test
│ └── java
│ └── com
│ └── heshidai
│ └── security
│ └── cipher
│ ├── SM3Test.java
│ ├── SM4Test.java
│ └── SM2Test.java
├── doc
├── SM3密码杂凑算法.pdf
├── SM4分组密码算法.pdf
├── SM2椭圆曲线公钥密码算法.pdf
└── SM2椭圆曲线公钥密码算法推荐曲线参数.pdf
├── .github
└── workflows
│ └── maven.yml
├── .gitignore
├── pom.xml
└── README.md
/src/main/java/com/heshidai/security/cipher/tip.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/SM3密码杂凑算法.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gotoworld/hsd-cipher-sm/HEAD/doc/SM3密码杂凑算法.pdf
--------------------------------------------------------------------------------
/doc/SM4分组密码算法.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gotoworld/hsd-cipher-sm/HEAD/doc/SM4分组密码算法.pdf
--------------------------------------------------------------------------------
/doc/SM2椭圆曲线公钥密码算法.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gotoworld/hsd-cipher-sm/HEAD/doc/SM2椭圆曲线公钥密码算法.pdf
--------------------------------------------------------------------------------
/doc/SM2椭圆曲线公钥密码算法推荐曲线参数.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gotoworld/hsd-cipher-sm/HEAD/doc/SM2椭圆曲线公钥密码算法推荐曲线参数.pdf
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM4_Context.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | public class SM4_Context
4 | {
5 | public int mode;
6 |
7 | public long[] sk;
8 |
9 | public boolean isPadding;
10 |
11 | public SM4_Context()
12 | {
13 | this.mode = 1;
14 | this.isPadding = true;
15 | this.sk = new long[32];
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Set up JDK 1.8
13 | uses: actions/setup-java@v1
14 | with:
15 | java-version: 1.8
16 | - name: Build with Maven
17 | run: mvn -B package --file pom.xml
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .mymetadata
2 | .checkstyle
3 | .classpath
4 | .project
5 | .class
6 | .war
7 | .zip
8 | .rar
9 | .idea
10 | *.iml
11 | .settings/*
12 | .checkstyle/*
13 | /indexes/*
14 | /target/*
15 | /src/main/webapp/WEB-INF/classes/*
16 | /src/main/webapp/userfiles/*
17 | /target/
18 | CATALINA.LOGSDIR_IS_UNDEFINED/*
19 | CATALINA.LOGSDIR_IS_UNDEFINED*
20 | catalina.home_IS_UNDEFINED*
21 | catalina.home_IS_UNDEFINED/*
22 | /bin/
23 | /logs/*
24 | .factorypath
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM2Result.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.math.BigInteger;
4 |
5 | import org.bouncycastle.math.ec.ECPoint;
6 |
7 | public class SM2Result
8 | {
9 | public SM2Result() {
10 | }
11 |
12 | // 签名/验签
13 | public BigInteger r;
14 | public BigInteger s;
15 | public BigInteger R;
16 |
17 | // 密钥交换
18 | public byte[] sa;
19 | public byte[] sb;
20 | public byte[] s1;
21 | public byte[] s2;
22 |
23 | public ECPoint keyra;
24 | public ECPoint keyrb;
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/com/heshidai/security/cipher/SM3Test.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import org.bouncycastle.util.encoders.Hex;
4 | import org.junit.jupiter.api.Test;
5 |
6 | public class SM3Test {
7 |
8 | @Test
9 | public void testSM3()
10 | {
11 | byte[] md = new byte[32];
12 | byte[] msg1 = "abc".getBytes();
13 | SM3Digest sm3 = new SM3Digest();
14 | sm3.update(msg1, 0, msg1.length);
15 | sm3.doFinal(md, 0);
16 | String s = new String(Hex.encode(md));
17 | System.out.println(s);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/com/heshidai/security/cipher/SM4Test.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.IOException;
6 |
7 | public class SM4Test {
8 |
9 | @Test
10 | public void testSM4() throws IOException
11 | {
12 | String plainText = "abcd";
13 |
14 | SM4Utils sm4 = new SM4Utils();
15 | sm4.setSecretKey("JeF8U9wHFOMfs2Y8");
16 | sm4.setHexString(false);
17 |
18 | System.out.println("ECB模式");
19 | String cipherText = sm4.encryptData_ECB(plainText);
20 | System.out.println("密文: " + cipherText);
21 | System.out.println("");
22 |
23 | plainText = sm4.decryptData_ECB(cipherText);
24 | System.out.println("明文: " + plainText);
25 | System.out.println("");
26 |
27 | System.out.println("CBC模式");
28 | sm4.setIv("UISwD9fW6cFh9SNS");
29 | cipherText = sm4.encryptData_CBC(plainText);
30 | System.out.println("密文: " + cipherText);
31 | System.out.println("");
32 |
33 | plainText = sm4.decryptData_CBC(cipherText);
34 | System.out.println("明文: " + plainText);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.heshidai.security
8 | hsd-cipher-sm
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.bouncycastle
15 | bcprov-jdk16
16 | 1.46
17 |
18 |
19 | org.junit.jupiter
20 | junit-jupiter-api
21 | RELEASE
22 | test
23 |
24 |
25 |
26 |
27 |
28 |
29 | nexus3
30 | http://192.168.254.204:8081/repository/releases/
31 |
32 |
33 | nexus3
34 | http://192.168.254.204:8081/repository/snapshots/
35 |
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HSD-CIPHER-SM
2 | Chinese Cipher Algorithm
3 |
4 |
5 | ## 国密算法介绍
6 |
7 | 国密即国家密码局认定的国产密码算法,即商用密码。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
8 |
9 | * SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
10 | * SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
11 | * SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。
12 | * SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。
13 |
14 | 由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
15 |
16 | 作为密码学算法,一定要公开接受行业的检验。
17 |
18 | * 1. 对称算法: (DES 3DES AES) --迁移--> SM1 SM4
19 |
20 | * 2. 非对称密码算法: (RSA) --迁移--> SM2(椭圆曲线密码)
21 |
22 | * 3. 散列算法: (HASH MD4、MD5 SHA-1、SHA-256、SHA-384、SHA512) --迁移--> SM3
23 |
24 |
25 | ## 国密算法的面临的机遇和挑战
26 |
27 | ### 1、推广情况说明
28 | 国家在金融领域启动国产密码算法试点工作以来,国家发改委启动了金融领域安全IC卡及密码关键产品专项支持工作,积极推动产业链发展。目前支持国密算法的软硬件密码产品共699项,包括SSL网关、数字证书认证系统、密钥管理系统、金融数据加密机、签名验签服务器、智能密码钥匙、智能IC卡、PCI密码卡等多种类型,目前已初步形成形式多样、功能互补的产品链,并保持着持续增长的势头。
29 |
30 |
31 | ### 2、数字认证系统(CA)的升级改造情况
32 |
33 | 2015年2月国家商业密码管理办公室发布公告称:根据要求全国第三方电子认证服务机构针对电子认证服务系统和密钥管理系统公钥算法进行了升级改造完毕已经全面支持国产算法,同时各认证服务机构正在积极推动国产算法的应用服务改造,淘汰有安全风险以及低强度的密码算法和产品。北京天威诚信作为最早成立的第三方电子认证服务机构也最早按照国密的要求完成了电子认证服务系统的升级改造,并且同步开始对服务类型的证书应用进行升级改造,目前已经累计完成150余个企业的应用升级工作,使得企业信息系统的安全性得到了极大的提升,也为我们带来了相应的经济效益。
34 |
35 | ### 3、挑战和机遇
36 |
37 | 虽然在SSL VPN、数字证书认证系统、密钥管理系统、金融数据加密机、签名验签服务器、智能密码钥匙、智能IC卡、PCI密码卡等产品上改造完毕,但是目前的信息系统整体架构中还有操作系统、数据库、中间件、浏览器、网络设备、负载均衡设备、芯片等软硬件,由于复杂的原因无法完全把密码模块升级为国产密码模块,导致整个信息系统还存在安全薄弱环节。
38 |
39 | 作为电子认证机构这个国产密码算法排头兵来说,由于密码服务是信息化安全建设的基础服务,密码的国产化改造和推广就成为我们重要的历史使命。为了普及和推广国产密码我们可以:一方面是产品升级改造,对于国外的产品,通过国产算法的标准出海战略,让国产算法成为国际标准从而国外的产品也就能够支持;对于国产的产品,加快国产算法模块的改造和应用,真正让国产算法为信息系统的安全自主可控;另一方面是应用的宣传和推广,国产算法虽然在安全圈里面是众所周知的事情,但是在其它领域根本就没有听说。所以对于从业者来说,就要不断对用户灌输使用国产密码算法以及尽快升级到国产算法的思想。只有从以上这两个方面入手并且持之以恒,相信国家提出的信息安全领域的自主可控战略最终就会实现。
40 |
41 |
42 | FISCO BCOS 支持国产密码算法
43 |
44 | ### Refer
45 |
46 | * 标准规范_国家密码管理局 http://www.oscca.gov.cn/sca/xxgk/bzgf.shtml
47 | * 国密加密算法有多安全呢 https://www.zhihu.com/question/48777504/answer/133988880
48 | * 科普一下SM系列国密算法(从零开始学区块链)http://www.qukuaiwang.com.cn/news/2271.html
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/test/java/com/heshidai/security/cipher/SM2Test.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import org.bouncycastle.asn1.*;
4 | import org.bouncycastle.math.ec.ECPoint;
5 | import org.bouncycastle.util.encoders.Base64;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import java.io.ByteArrayInputStream;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.IOException;
11 | import java.math.BigInteger;
12 | import java.util.Enumeration;
13 |
14 |
15 | public class SM2Test {
16 |
17 | @Test
18 | public void testSM2() throws Exception {
19 | String plainText = "message digest";
20 | byte[] sourceData = plainText.getBytes();
21 |
22 | // 国密规范测试私钥
23 | String prik = "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263";
24 | String prikS = new String(Base64.encode(Util.hexToByte(prik)));
25 | System.out.println("prikS: " + prikS);
26 | System.out.println("");
27 |
28 | // 国密规范测试用户ID
29 | String userId = "ALICE123@YAHOO.COM";
30 |
31 | System.out.println("ID: " + Util.getHexString(userId.getBytes()));
32 | System.out.println("");
33 |
34 | System.out.println("签名: ");
35 | byte[] c = SM2Utils.sign(userId.getBytes(), Base64.decode(prikS.getBytes()), sourceData);
36 | System.out.println("sign: " + Util.getHexString(c));
37 | System.out.println("");
38 |
39 | // 国密规范测试公钥
40 | String pubk = "040AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857";
41 | String pubkS = new String(Base64.encode(Util.hexToByte(pubk)));
42 | System.out.println("pubkS: " + pubkS);
43 | System.out.println("");
44 |
45 |
46 | System.out.println("验签: ");
47 | boolean vs = SM2Utils.verifySign(userId.getBytes(), Base64.decode(pubkS.getBytes()), sourceData, c);
48 | System.out.println("验签结果: " + vs);
49 | System.out.println("");
50 |
51 | System.out.println("加密: ");
52 | byte[] cipherText = SM2Utils.encrypt(Base64.decode(pubkS.getBytes()), sourceData);
53 | System.out.println(new String(Base64.encode(cipherText)));
54 | System.out.println("");
55 |
56 | System.out.println("解密: ");
57 | plainText = new String(SM2Utils.decrypt(Base64.decode(prikS.getBytes()), cipherText));
58 | System.out.println(plainText);
59 | }
60 |
61 |
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM3Digest.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import org.bouncycastle.util.encoders.Hex;
4 |
5 | public class SM3Digest
6 | {
7 | /** SM3值的长度 */
8 | private static final int BYTE_LENGTH = 32;
9 |
10 | /** SM3分组长度 */
11 | private static final int BLOCK_LENGTH = 64;
12 |
13 | /** 缓冲区长度 */
14 | private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1;
15 |
16 | /** 缓冲区 */
17 | private byte[] xBuf = new byte[BUFFER_LENGTH];
18 |
19 | /** 缓冲区偏移量 */
20 | private int xBufOff;
21 |
22 | /** 初始向量 */
23 | private byte[] V = SM3.iv.clone();
24 |
25 | private int cntBlock = 0;
26 |
27 | public SM3Digest() {
28 | }
29 |
30 | public SM3Digest(SM3Digest t)
31 | {
32 | System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
33 | this.xBufOff = t.xBufOff;
34 | System.arraycopy(t.V, 0, this.V, 0, t.V.length);
35 | }
36 |
37 | /**
38 | * SM3结果输出
39 | *
40 | * @param out 保存SM3结构的缓冲区
41 | * @param outOff 缓冲区偏移量
42 | * @return
43 | */
44 | public int doFinal(byte[] out, int outOff)
45 | {
46 | byte[] tmp = doFinal();
47 | System.arraycopy(tmp, 0, out, 0, tmp.length);
48 | return BYTE_LENGTH;
49 | }
50 |
51 | public void reset()
52 | {
53 | xBufOff = 0;
54 | cntBlock = 0;
55 | V = SM3.iv.clone();
56 | }
57 |
58 | /**
59 | * 明文输入
60 | *
61 | * @param in
62 | * 明文输入缓冲区
63 | * @param inOff
64 | * 缓冲区偏移量
65 | * @param len
66 | * 明文长度
67 | */
68 | public void update(byte[] in, int inOff, int len)
69 | {
70 | int partLen = BUFFER_LENGTH - xBufOff;
71 | int inputLen = len;
72 | int dPos = inOff;
73 | if (partLen < inputLen)
74 | {
75 | System.arraycopy(in, dPos, xBuf, xBufOff, partLen);
76 | inputLen -= partLen;
77 | dPos += partLen;
78 | doUpdate();
79 | while (inputLen > BUFFER_LENGTH)
80 | {
81 | System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH);
82 | inputLen -= BUFFER_LENGTH;
83 | dPos += BUFFER_LENGTH;
84 | doUpdate();
85 | }
86 | }
87 |
88 | System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);
89 | xBufOff += inputLen;
90 | }
91 |
92 | private void doUpdate()
93 | {
94 | byte[] B = new byte[BLOCK_LENGTH];
95 | for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH)
96 | {
97 | System.arraycopy(xBuf, i, B, 0, B.length);
98 | doHash(B);
99 | }
100 | xBufOff = 0;
101 | }
102 |
103 | private void doHash(byte[] B)
104 | {
105 | byte[] tmp = SM3.CF(V, B);
106 | System.arraycopy(tmp, 0, V, 0, V.length);
107 | cntBlock++;
108 | }
109 |
110 | private byte[] doFinal()
111 | {
112 | byte[] B = new byte[BLOCK_LENGTH];
113 | byte[] buffer = new byte[xBufOff];
114 | System.arraycopy(xBuf, 0, buffer, 0, buffer.length);
115 | byte[] tmp = SM3.padding(buffer, cntBlock);
116 | for (int i = 0; i < tmp.length; i += BLOCK_LENGTH)
117 | {
118 | System.arraycopy(tmp, i, B, 0, B.length);
119 | doHash(B);
120 | }
121 | return V;
122 | }
123 |
124 | public void update(byte in)
125 | {
126 | byte[] buffer = new byte[] { in };
127 | update(buffer, 0, 1);
128 | }
129 |
130 | public int getDigestSize()
131 | {
132 | return BYTE_LENGTH;
133 | }
134 |
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/Cipher.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.math.BigInteger;
4 |
5 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
6 | import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
7 | import org.bouncycastle.crypto.params.ECPublicKeyParameters;
8 | import org.bouncycastle.math.ec.ECPoint;
9 |
10 |
11 | public class Cipher
12 | {
13 | private int ct;
14 | private ECPoint p2;
15 | private SM3Digest sm3keybase;
16 | private SM3Digest sm3c3;
17 | private byte key[];
18 | private byte keyOff;
19 |
20 | public Cipher()
21 | {
22 | this.ct = 1;
23 | this.key = new byte[32];
24 | this.keyOff = 0;
25 | }
26 |
27 | private void Reset()
28 | {
29 | this.sm3keybase = new SM3Digest();
30 | this.sm3c3 = new SM3Digest();
31 |
32 | byte p[] = Util.byteConvert32Bytes(p2.getX().toBigInteger());
33 | this.sm3keybase.update(p, 0, p.length);
34 | this.sm3c3.update(p, 0, p.length);
35 |
36 | p = Util.byteConvert32Bytes(p2.getY().toBigInteger());
37 | this.sm3keybase.update(p, 0, p.length);
38 | this.ct = 1;
39 | NextKey();
40 | }
41 |
42 | private void NextKey()
43 | {
44 | SM3Digest sm3keycur = new SM3Digest(this.sm3keybase);
45 | sm3keycur.update((byte) (ct >> 24 & 0xff));
46 | sm3keycur.update((byte) (ct >> 16 & 0xff));
47 | sm3keycur.update((byte) (ct >> 8 & 0xff));
48 | sm3keycur.update((byte) (ct & 0xff));
49 | sm3keycur.doFinal(key, 0);
50 | this.keyOff = 0;
51 | this.ct++;
52 | }
53 |
54 | public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
55 | {
56 | AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
57 | ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
58 | ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
59 | BigInteger k = ecpriv.getD();
60 | ECPoint c1 = ecpub.getQ();
61 | this.p2 = userKey.multiply(k);
62 | Reset();
63 | return c1;
64 | }
65 |
66 | public void Encrypt(byte data[])
67 | {
68 | this.sm3c3.update(data, 0, data.length);
69 | for (int i = 0; i < data.length; i++)
70 | {
71 | if (keyOff == key.length)
72 | {
73 | NextKey();
74 | }
75 | data[i] ^= key[keyOff++];
76 | }
77 | }
78 |
79 | public void Init_dec(BigInteger userD, ECPoint c1)
80 | {
81 | this.p2 = c1.multiply(userD);
82 | Reset();
83 | }
84 |
85 | public void Decrypt(byte data[])
86 | {
87 | for (int i = 0; i < data.length; i++)
88 | {
89 | if (keyOff == key.length)
90 | {
91 | NextKey();
92 | }
93 | data[i] ^= key[keyOff++];
94 | }
95 |
96 | this.sm3c3.update(data, 0, data.length);
97 | }
98 |
99 | public void Dofinal(byte c3[])
100 | {
101 | byte p[] = Util.byteConvert32Bytes(p2.getY().toBigInteger());
102 | this.sm3c3.update(p, 0, p.length);
103 | this.sm3c3.doFinal(c3, 0);
104 | Reset();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM4Utils.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.io.IOException;
4 | import java.util.regex.Matcher;
5 | import java.util.regex.Pattern;
6 |
7 | import sun.misc.BASE64Decoder;
8 | import sun.misc.BASE64Encoder;
9 |
10 | public class SM4Utils
11 | {
12 | public String getSecretKey() {
13 | return secretKey;
14 | }
15 |
16 | public void setSecretKey(String secretKey) {
17 | this.secretKey = secretKey;
18 | }
19 |
20 | public boolean isHexString() {
21 | return hexString;
22 | }
23 |
24 | public void setHexString(boolean hexString) {
25 | this.hexString = hexString;
26 | }
27 |
28 | private String secretKey = "";
29 |
30 | public String getIv() {
31 | return iv;
32 | }
33 |
34 | public void setIv(String iv) {
35 | this.iv = iv;
36 | }
37 |
38 | private String iv = "";
39 |
40 | private boolean hexString = false;
41 |
42 | public SM4Utils()
43 | {
44 | }
45 |
46 | public String encryptData_ECB(String plainText)
47 | {
48 | try
49 | {
50 | SM4_Context ctx = new SM4_Context();
51 | ctx.isPadding = true;
52 | ctx.mode = SM4.SM4_ENCRYPT;
53 |
54 | byte[] keyBytes;
55 | if (hexString)
56 | {
57 | keyBytes = Util.hexStringToBytes(secretKey);
58 | }
59 | else
60 | {
61 | keyBytes = secretKey.getBytes();
62 | }
63 |
64 | SM4 sm4 = new SM4();
65 | sm4.sm4_setkey_enc(ctx, keyBytes);
66 | byte[] encrypted = sm4.sm4_crypt_ecb(ctx, plainText.getBytes("GBK"));
67 | String cipherText = new BASE64Encoder().encode(encrypted);
68 | if (cipherText != null && cipherText.trim().length() > 0)
69 | {
70 | Pattern p = Pattern.compile("\\s*|\t|\r|\n");
71 | Matcher m = p.matcher(cipherText);
72 | cipherText = m.replaceAll("");
73 | }
74 | return cipherText;
75 | }
76 | catch (Exception e)
77 | {
78 | e.printStackTrace();
79 | return null;
80 | }
81 | }
82 |
83 | public String decryptData_ECB(String cipherText)
84 | {
85 | try
86 | {
87 | SM4_Context ctx = new SM4_Context();
88 | ctx.isPadding = true;
89 | ctx.mode = SM4.SM4_DECRYPT;
90 |
91 | byte[] keyBytes;
92 | if (hexString)
93 | {
94 | keyBytes = Util.hexStringToBytes(secretKey);
95 | }
96 | else
97 | {
98 | keyBytes = secretKey.getBytes();
99 | }
100 |
101 | SM4 sm4 = new SM4();
102 | sm4.sm4_setkey_dec(ctx, keyBytes);
103 | byte[] decrypted = sm4.sm4_crypt_ecb(ctx, new BASE64Decoder().decodeBuffer(cipherText));
104 | return new String(decrypted, "GBK");
105 | }
106 | catch (Exception e)
107 | {
108 | e.printStackTrace();
109 | return null;
110 | }
111 | }
112 |
113 | public String encryptData_CBC(String plainText)
114 | {
115 | try
116 | {
117 | SM4_Context ctx = new SM4_Context();
118 | ctx.isPadding = true;
119 | ctx.mode = SM4.SM4_ENCRYPT;
120 |
121 | byte[] keyBytes;
122 | byte[] ivBytes;
123 | if (hexString)
124 | {
125 | keyBytes = Util.hexStringToBytes(secretKey);
126 | ivBytes = Util.hexStringToBytes(iv);
127 | }
128 | else
129 | {
130 | keyBytes = secretKey.getBytes();
131 | ivBytes = iv.getBytes();
132 | }
133 |
134 | SM4 sm4 = new SM4();
135 | sm4.sm4_setkey_enc(ctx, keyBytes);
136 | byte[] encrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, plainText.getBytes("GBK"));
137 | String cipherText = new BASE64Encoder().encode(encrypted);
138 | if (cipherText != null && cipherText.trim().length() > 0)
139 | {
140 | Pattern p = Pattern.compile("\\s*|\t|\r|\n");
141 | Matcher m = p.matcher(cipherText);
142 | cipherText = m.replaceAll("");
143 | }
144 | return cipherText;
145 | }
146 | catch (Exception e)
147 | {
148 | e.printStackTrace();
149 | return null;
150 | }
151 | }
152 |
153 | public String decryptData_CBC(String cipherText)
154 | {
155 | try
156 | {
157 | SM4_Context ctx = new SM4_Context();
158 | ctx.isPadding = true;
159 | ctx.mode = SM4.SM4_DECRYPT;
160 |
161 | byte[] keyBytes;
162 | byte[] ivBytes;
163 | if (hexString)
164 | {
165 | keyBytes = Util.hexStringToBytes(secretKey);
166 | ivBytes = Util.hexStringToBytes(iv);
167 | }
168 | else
169 | {
170 | keyBytes = secretKey.getBytes();
171 | ivBytes = iv.getBytes();
172 | }
173 |
174 | SM4 sm4 = new SM4();
175 | sm4.sm4_setkey_dec(ctx, keyBytes);
176 | byte[] decrypted = sm4.sm4_crypt_cbc(ctx, ivBytes, new BASE64Decoder().decodeBuffer(cipherText));
177 | return new String(decrypted, "GBK");
178 | }
179 | catch (Exception e)
180 | {
181 | e.printStackTrace();
182 | return null;
183 | }
184 | }
185 |
186 |
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM2Utils.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.IOException;
6 | import java.math.BigInteger;
7 | import java.util.Enumeration;
8 |
9 | import com.heshidai.security.cipher.Cipher;
10 | import org.bouncycastle.asn1.ASN1EncodableVector;
11 | import org.bouncycastle.asn1.ASN1InputStream;
12 | import org.bouncycastle.asn1.ASN1Sequence;
13 | import org.bouncycastle.asn1.DERInteger;
14 | import org.bouncycastle.asn1.DERObject;
15 | import org.bouncycastle.asn1.DEROctetString;
16 | import org.bouncycastle.asn1.DEROutputStream;
17 | import org.bouncycastle.asn1.DERSequence;
18 | import org.bouncycastle.math.ec.ECPoint;
19 | import org.bouncycastle.util.encoders.Base64;
20 |
21 | public class SM2Utils
22 | {
23 | public static byte[] encrypt(byte[] publicKey, byte[] data) throws IOException
24 | {
25 | if (publicKey == null || publicKey.length == 0)
26 | {
27 | return null;
28 | }
29 |
30 | if (data == null || data.length == 0)
31 | {
32 | return null;
33 | }
34 |
35 | byte[] source = new byte[data.length];
36 | System.arraycopy(data, 0, source, 0, data.length);
37 |
38 | Cipher cipher = new Cipher();
39 | SM2 sm2 = SM2.Instance();
40 | ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
41 |
42 | ECPoint c1 = cipher.Init_enc(sm2, userKey);
43 | cipher.Encrypt(source);
44 | byte[] c3 = new byte[32];
45 | cipher.Dofinal(c3);
46 |
47 | DERInteger x = new DERInteger(c1.getX().toBigInteger());
48 | DERInteger y = new DERInteger(c1.getY().toBigInteger());
49 | DEROctetString derDig = new DEROctetString(c3);
50 | DEROctetString derEnc = new DEROctetString(source);
51 | ASN1EncodableVector v = new ASN1EncodableVector();
52 | v.add(x);
53 | v.add(y);
54 | v.add(derDig);
55 | v.add(derEnc);
56 | DERSequence seq = new DERSequence(v);
57 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
58 | DEROutputStream dos = new DEROutputStream(bos);
59 | dos.writeObject(seq);
60 | return bos.toByteArray();
61 | }
62 |
63 | public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
64 | {
65 | if (privateKey == null || privateKey.length == 0)
66 | {
67 | return null;
68 | }
69 |
70 | if (encryptedData == null || encryptedData.length == 0)
71 | {
72 | return null;
73 | }
74 |
75 | byte[] enc = new byte[encryptedData.length];
76 | System.arraycopy(encryptedData, 0, enc, 0, encryptedData.length);
77 |
78 | SM2 sm2 = SM2.Instance();
79 | BigInteger userD = new BigInteger(1, privateKey);
80 |
81 | ByteArrayInputStream bis = new ByteArrayInputStream(enc);
82 | ASN1InputStream dis = new ASN1InputStream(bis);
83 | DERObject derObj = dis.readObject();
84 | ASN1Sequence asn1 = (ASN1Sequence) derObj;
85 | DERInteger x = (DERInteger) asn1.getObjectAt(0);
86 | DERInteger y = (DERInteger) asn1.getObjectAt(1);
87 | ECPoint c1 = sm2.ecc_curve.createPoint(x.getValue(), y.getValue(), true);
88 |
89 | Cipher cipher = new Cipher();
90 | cipher.Init_dec(userD, c1);
91 | DEROctetString data = (DEROctetString) asn1.getObjectAt(3);
92 | enc = data.getOctets();
93 | cipher.Decrypt(enc);
94 | byte[] c3 = new byte[32];
95 | cipher.Dofinal(c3);
96 | return enc;
97 | }
98 |
99 | public static byte[] sign(byte[] userId, byte[] privateKey, byte[] sourceData) throws IOException
100 | {
101 | if (privateKey == null || privateKey.length == 0)
102 | {
103 | return null;
104 | }
105 |
106 | if (sourceData == null || sourceData.length == 0)
107 | {
108 | return null;
109 | }
110 |
111 | SM2 sm2 = SM2.Instance();
112 | BigInteger userD = new BigInteger(privateKey);
113 | System.out.println("userD: " + userD.toString(16));
114 | System.out.println("");
115 |
116 | ECPoint userKey = sm2.ecc_point_g.multiply(userD);
117 | System.out.println("椭圆曲线点X: " + userKey.getX().toBigInteger().toString(16));
118 | System.out.println("椭圆曲线点Y: " + userKey.getY().toBigInteger().toString(16));
119 | System.out.println("");
120 |
121 | SM3Digest sm3 = new SM3Digest();
122 | byte[] z = sm2.sm2GetZ(userId, userKey);
123 | System.out.println("SM3摘要Z: " + Util.getHexString(z));
124 | System.out.println("");
125 |
126 | System.out.println("M: " + Util.getHexString(sourceData));
127 | System.out.println("");
128 |
129 | sm3.update(z, 0, z.length);
130 | sm3.update(sourceData, 0, sourceData.length);
131 | byte[] md = new byte[32];
132 | sm3.doFinal(md, 0);
133 |
134 | System.out.println("SM3摘要值: " + Util.getHexString(md));
135 | System.out.println("");
136 |
137 | SM2Result sm2Result = new SM2Result();
138 | sm2.sm2Sign(md, userD, userKey, sm2Result);
139 | System.out.println("r: " + sm2Result.r.toString(16));
140 | System.out.println("s: " + sm2Result.s.toString(16));
141 | System.out.println("");
142 |
143 | DERInteger d_r = new DERInteger(sm2Result.r);
144 | DERInteger d_s = new DERInteger(sm2Result.s);
145 | ASN1EncodableVector v2 = new ASN1EncodableVector();
146 | v2.add(d_r);
147 | v2.add(d_s);
148 | DERObject sign = new DERSequence(v2);
149 | byte[] signdata = sign.getDEREncoded();
150 | return signdata;
151 | }
152 |
153 | @SuppressWarnings("unchecked")
154 | public static boolean verifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData) throws IOException
155 | {
156 | if (publicKey == null || publicKey.length == 0)
157 | {
158 | return false;
159 | }
160 |
161 | if (sourceData == null || sourceData.length == 0)
162 | {
163 | return false;
164 | }
165 |
166 | SM2 sm2 = SM2.Instance();
167 | ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
168 |
169 | SM3Digest sm3 = new SM3Digest();
170 | byte[] z = sm2.sm2GetZ(userId, userKey);
171 | sm3.update(z, 0, z.length);
172 | sm3.update(sourceData, 0, sourceData.length);
173 | byte[] md = new byte[32];
174 | sm3.doFinal(md, 0);
175 | System.out.println("SM3摘要值: " + Util.getHexString(md));
176 | System.out.println("");
177 |
178 | ByteArrayInputStream bis = new ByteArrayInputStream(signData);
179 | ASN1InputStream dis = new ASN1InputStream(bis);
180 | DERObject derObj = dis.readObject();
181 | Enumeration e = ((ASN1Sequence) derObj).getObjects();
182 | BigInteger r = ((DERInteger)e.nextElement()).getValue();
183 | BigInteger s = ((DERInteger)e.nextElement()).getValue();
184 | SM2Result sm2Result = new SM2Result();
185 | sm2Result.r = r;
186 | sm2Result.s = s;
187 | System.out.println("r: " + sm2Result.r.toString(16));
188 | System.out.println("s: " + sm2Result.s.toString(16));
189 | System.out.println("");
190 |
191 |
192 | sm2.sm2Verify(md, userKey, sm2Result.r, sm2Result.s, sm2Result);
193 | return sm2Result.r.equals(sm2Result.R);
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM2.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.math.BigInteger;
4 | import java.security.SecureRandom;
5 |
6 | import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
7 | import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
8 | import org.bouncycastle.crypto.params.ECDomainParameters;
9 | import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
10 | import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
11 | import org.bouncycastle.crypto.params.ECPublicKeyParameters;
12 | import org.bouncycastle.math.ec.ECCurve;
13 | import org.bouncycastle.math.ec.ECFieldElement;
14 | import org.bouncycastle.math.ec.ECPoint;
15 | import org.bouncycastle.math.ec.ECFieldElement.Fp;
16 |
17 | public class SM2
18 | {
19 | // 测试参数
20 | public static final String[] ecc_param = {
21 | "8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3",
22 | "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498",
23 | "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A",
24 | "8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7",
25 | "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D",
26 | "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2"
27 | };
28 |
29 | // 正式参数
30 | /* public static String[] ecc_param = {
31 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
32 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
33 | "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
34 | "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
35 | "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
36 | "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
37 | };*/
38 |
39 | public static SM2 Instance()
40 | {
41 | return new SM2();
42 | }
43 |
44 | public final BigInteger ecc_p;
45 | public final BigInteger ecc_a;
46 | public final BigInteger ecc_b;
47 | public final BigInteger ecc_n;
48 | public final BigInteger ecc_gx;
49 | public final BigInteger ecc_gy;
50 | public final ECCurve ecc_curve;
51 | public final ECPoint ecc_point_g;
52 | public final ECDomainParameters ecc_bc_spec;
53 | public final ECKeyPairGenerator ecc_key_pair_generator;
54 | public final ECFieldElement ecc_gx_fieldelement;
55 | public final ECFieldElement ecc_gy_fieldelement;
56 |
57 | public SM2()
58 | {
59 | this.ecc_p = new BigInteger(ecc_param[0], 16);
60 | this.ecc_a = new BigInteger(ecc_param[1], 16);
61 | this.ecc_b = new BigInteger(ecc_param[2], 16);
62 | this.ecc_n = new BigInteger(ecc_param[3], 16);
63 | this.ecc_gx = new BigInteger(ecc_param[4], 16);
64 | this.ecc_gy = new BigInteger(ecc_param[5], 16);
65 |
66 | this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx);
67 | this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy);
68 |
69 | this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
70 | this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement);
71 |
72 | this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);
73 |
74 | ECKeyGenerationParameters ecc_ecgenparam;
75 | ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());
76 |
77 | this.ecc_key_pair_generator = new ECKeyPairGenerator();
78 | this.ecc_key_pair_generator.init(ecc_ecgenparam);
79 | }
80 |
81 | public byte[] sm2GetZ(byte[] userId, ECPoint userKey)
82 | {
83 | SM3Digest sm3 = new SM3Digest();
84 |
85 | int len = userId.length * 8;
86 | sm3.update((byte) (len >> 8 & 0xFF));
87 | sm3.update((byte) (len & 0xFF));
88 | sm3.update(userId, 0, userId.length);
89 |
90 | byte[] p = Util.byteConvert32Bytes(ecc_a);
91 | sm3.update(p, 0, p.length);
92 |
93 | p = Util.byteConvert32Bytes(ecc_b);
94 | sm3.update(p, 0, p.length);
95 |
96 | p = Util.byteConvert32Bytes(ecc_gx);
97 | sm3.update(p, 0, p.length);
98 |
99 | p = Util.byteConvert32Bytes(ecc_gy);
100 | sm3.update(p, 0, p.length);
101 |
102 | p = Util.byteConvert32Bytes(userKey.getX().toBigInteger());
103 | sm3.update(p, 0, p.length);
104 |
105 | p = Util.byteConvert32Bytes(userKey.getY().toBigInteger());
106 | sm3.update(p, 0, p.length);
107 |
108 | byte[] md = new byte[sm3.getDigestSize()];
109 | sm3.doFinal(md, 0);
110 | return md;
111 | }
112 |
113 | public void sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Result)
114 | {
115 | BigInteger e = new BigInteger(1, md);
116 | BigInteger k = null;
117 | ECPoint kp = null;
118 | BigInteger r = null;
119 | BigInteger s = null;
120 | do
121 | {
122 | do
123 | {
124 | // 正式环境
125 | AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.generateKeyPair();
126 | ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate();
127 | ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();
128 | k = ecpriv.getD();
129 | kp = ecpub.getQ();
130 |
131 | // 国密规范测试 随机数k
132 | String kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F";
133 | k = new BigInteger(kS, 16);
134 | kp = this.ecc_point_g.multiply(k);
135 |
136 | System.out.println("计算曲线点X1: " + kp.getX().toBigInteger().toString(16));
137 | System.out.println("计算曲线点Y1: " + kp.getY().toBigInteger().toString(16));
138 | System.out.println("");
139 |
140 | // r
141 | r = e.add(kp.getX().toBigInteger());
142 | r = r.mod(ecc_n);
143 | } while (r.equals(BigInteger.ZERO) || r.add(k).equals(ecc_n));
144 |
145 | // (1 + dA)~-1
146 | BigInteger da_1 = userD.add(BigInteger.ONE);
147 | da_1 = da_1.modInverse(ecc_n);
148 |
149 | // s
150 | s = r.multiply(userD);
151 | s = k.subtract(s).mod(ecc_n);
152 | s = da_1.multiply(s).mod(ecc_n);
153 | } while (s.equals(BigInteger.ZERO));
154 |
155 | sm2Result.r = r;
156 | sm2Result.s = s;
157 | }
158 |
159 | public void sm2Verify(byte md[], ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Result)
160 | {
161 | sm2Result.R = null;
162 | BigInteger e = new BigInteger(1, md);
163 | BigInteger t = r.add(s).mod(ecc_n);
164 | if(t.equals(BigInteger.ZERO))
165 | {
166 | return;
167 | }
168 | else
169 | {
170 | ECPoint x1y1 = ecc_point_g.multiply(sm2Result.s);
171 | System.out.println("计算曲线点X0: " + x1y1.getX().toBigInteger().toString(16));
172 | System.out.println("计算曲线点Y0: " + x1y1.getY().toBigInteger().toString(16));
173 | System.out.println("");
174 |
175 | x1y1 = x1y1.add(userKey.multiply(t));
176 | System.out.println("计算曲线点X1: " + x1y1.getX().toBigInteger().toString(16));
177 | System.out.println("计算曲线点Y1: " + x1y1.getY().toBigInteger().toString(16));
178 | System.out.println("");
179 | sm2Result.R = e.add(x1y1.getX().toBigInteger()).mod(ecc_n);
180 | System.out.println("R: " + sm2Result.R.toString(16));
181 | return;
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM3.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 |
4 | public class SM3
5 | {
6 | /*public static final byte[] iv = { 0x2C, (byte) 0x91, (byte) 0xB4, 0x01,
7 | (byte) 0xFC, 0x64, (byte) 0xB2, (byte) 0xCE, 0x7C, 0x4E,
8 | (byte) 0xAE, (byte) 0xFB, (byte) 0xB1, 0x3B, (byte) 0xB6,
9 | (byte) 0xD3, 0x17, 0x60, (byte) 0xB6, 0x35, (byte) 0xF3, 0x6F,
10 | 0x13, (byte) 0xEB, (byte) 0xC8, 0x77, (byte) 0xE9, (byte) 0xA0,
11 | (byte) 0xC2, 0x76, (byte) 0xA8, 0x17 };*/
12 |
13 | public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
14 | 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
15 | (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
16 | (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
17 | (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
18 | 0x4e };
19 |
20 | public static int[] Tj = new int[64];
21 |
22 | static
23 | {
24 | for (int i = 0; i < 16; i++)
25 | {
26 | Tj[i] = 0x79cc4519;
27 | }
28 |
29 | for (int i = 16; i < 64; i++)
30 | {
31 | Tj[i] = 0x7a879d8a;
32 | }
33 | }
34 |
35 | public static byte[] CF(byte[] V, byte[] B)
36 | {
37 | int[] v, b;
38 | v = convert(V);
39 | b = convert(B);
40 | return convert(CF(v, b));
41 | }
42 |
43 | private static int[] convert(byte[] arr)
44 | {
45 | int[] out = new int[arr.length / 4];
46 | byte[] tmp = new byte[4];
47 | for (int i = 0; i < arr.length; i += 4)
48 | {
49 | System.arraycopy(arr, i, tmp, 0, 4);
50 | out[i / 4] = bigEndianByteToInt(tmp);
51 | }
52 | return out;
53 | }
54 |
55 | private static byte[] convert(int[] arr)
56 | {
57 | byte[] out = new byte[arr.length * 4];
58 | byte[] tmp = null;
59 | for (int i = 0; i < arr.length; i++)
60 | {
61 | tmp = bigEndianIntToByte(arr[i]);
62 | System.arraycopy(tmp, 0, out, i * 4, 4);
63 | }
64 | return out;
65 | }
66 |
67 | public static int[] CF(int[] V, int[] B)
68 | {
69 | int a, b, c, d, e, f, g, h;
70 | int ss1, ss2, tt1, tt2;
71 | a = V[0];
72 | b = V[1];
73 | c = V[2];
74 | d = V[3];
75 | e = V[4];
76 | f = V[5];
77 | g = V[6];
78 | h = V[7];
79 |
80 | /*System.out.println("IV: ");
81 | System.out.print(Integer.toHexString(a)+" ");
82 | System.out.print(Integer.toHexString(b)+" ");
83 | System.out.print(Integer.toHexString(c)+" ");
84 | System.out.print(Integer.toHexString(d)+" ");
85 | System.out.print(Integer.toHexString(e)+" ");
86 | System.out.print(Integer.toHexString(f)+" ");
87 | System.out.print(Integer.toHexString(g)+" ");
88 | System.out.print(Integer.toHexString(h)+" ");
89 | System.out.println("");
90 | System.out.println("");
91 |
92 | System.out.println("填充后的消息: ");
93 | for(int i=0; i= 0 && j <= 15)
191 | {
192 | return FF1j(X, Y, Z);
193 | }
194 | else
195 | {
196 | return FF2j(X, Y, Z);
197 | }
198 | }
199 |
200 | private static int GGj(int X, int Y, int Z, int j)
201 | {
202 | if (j >= 0 && j <= 15)
203 | {
204 | return GG1j(X, Y, Z);
205 | }
206 | else
207 | {
208 | return GG2j(X, Y, Z);
209 | }
210 | }
211 |
212 | // 逻辑位运算函数
213 | private static int FF1j(int X, int Y, int Z)
214 | {
215 | int tmp = X ^ Y ^ Z;
216 | return tmp;
217 | }
218 |
219 | private static int FF2j(int X, int Y, int Z)
220 | {
221 | int tmp = ((X & Y) | (X & Z) | (Y & Z));
222 | return tmp;
223 | }
224 |
225 | private static int GG1j(int X, int Y, int Z)
226 | {
227 | int tmp = X ^ Y ^ Z;
228 | return tmp;
229 | }
230 |
231 | private static int GG2j(int X, int Y, int Z)
232 | {
233 | int tmp = (X & Y) | (~X & Z);
234 | return tmp;
235 | }
236 |
237 | private static int P0(int X)
238 | {
239 | int y = rotateLeft(X, 9);
240 | y = bitCycleLeft(X, 9);
241 | int z = rotateLeft(X, 17);
242 | z = bitCycleLeft(X, 17);
243 | int t = X ^ y ^ z;
244 | return t;
245 | }
246 |
247 | private static int P1(int X)
248 | {
249 | int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);
250 | return t;
251 | }
252 |
253 | /**
254 | * 对最后一个分组字节数据padding
255 | *
256 | * @param in
257 | * @param bLen
258 | * 分组个数
259 | * @return
260 | */
261 | public static byte[] padding(byte[] in, int bLen)
262 | {
263 | int k = 448 - (8 * in.length + 1) % 512;
264 | if (k < 0)
265 | {
266 | k = 960 - (8 * in.length + 1) % 512;
267 | }
268 | k += 1;
269 | byte[] padd = new byte[k / 8];
270 | padd[0] = (byte) 0x80;
271 | long n = in.length * 8 + bLen * 512;
272 | byte[] out = new byte[in.length + k / 8 + 64 / 8];
273 | int pos = 0;
274 | System.arraycopy(in, 0, out, 0, in.length);
275 | pos += in.length;
276 | System.arraycopy(padd, 0, out, pos, padd.length);
277 | pos += padd.length;
278 | byte[] tmp = back(Util.longToBytes(n));
279 | System.arraycopy(tmp, 0, out, pos, tmp.length);
280 | return out;
281 | }
282 |
283 | /**
284 | * 字节数组逆序
285 | *
286 | * @param in
287 | * @return
288 | */
289 | private static byte[] back(byte[] in)
290 | {
291 | byte[] out = new byte[in.length];
292 | for (int i = 0; i < out.length; i++)
293 | {
294 | out[i] = in[out.length - i - 1];
295 | }
296 |
297 | return out;
298 | }
299 |
300 | public static int rotateLeft(int x, int n)
301 | {
302 | return (x << n) | (x >> (32 - n));
303 | }
304 |
305 | private static int bitCycleLeft(int n, int bitLen)
306 | {
307 | bitLen %= 32;
308 | byte[] tmp = bigEndianIntToByte(n);
309 | int byteLen = bitLen / 8;
310 | int len = bitLen % 8;
311 | if (byteLen > 0)
312 | {
313 | tmp = byteCycleLeft(tmp, byteLen);
314 | }
315 |
316 | if (len > 0)
317 | {
318 | tmp = bitSmall8CycleLeft(tmp, len);
319 | }
320 |
321 | return bigEndianByteToInt(tmp);
322 | }
323 |
324 | private static byte[] bitSmall8CycleLeft(byte[] in, int len)
325 | {
326 | byte[] tmp = new byte[in.length];
327 | int t1, t2, t3;
328 | for (int i = 0; i < tmp.length; i++)
329 | {
330 | t1 = (byte) ((in[i] & 0x000000ff) << len);
331 | t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));
332 | t3 = (byte) (t1 | t2);
333 | tmp[i] = (byte) t3;
334 | }
335 |
336 | return tmp;
337 | }
338 |
339 | private static byte[] byteCycleLeft(byte[] in, int byteLen)
340 | {
341 | byte[] tmp = new byte[in.length];
342 | System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);
343 | System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);
344 | return tmp;
345 | }
346 |
347 | /*private static void print(int[] arr)
348 | {
349 | for (int i = 0; i < arr.length; i++)
350 | {
351 | System.out.print(Integer.toHexString(arr[i]) + " ");
352 | if ((i + 1) % 16 == 0)
353 | {
354 | System.out.println();
355 | }
356 | }
357 | System.out.println();
358 | }*/
359 | }
360 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/SM4.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 |
6 | public class SM4
7 | {
8 | public static final int SM4_ENCRYPT = 1;
9 |
10 | public static final int SM4_DECRYPT = 0;
11 |
12 | private long GET_ULONG_BE(byte[] b, int i)
13 | {
14 | long n = (long)(b[i] & 0xff) << 24 | (long)((b[i + 1] & 0xff) << 16) | (long)((b[i + 2] & 0xff) << 8) | (long)(b[i + 3] & 0xff) & 0xffffffffL;
15 | return n;
16 | }
17 |
18 | private void PUT_ULONG_BE(long n, byte[] b, int i)
19 | {
20 | b[i] = (byte)(int)(0xFF & n >> 24);
21 | b[i + 1] = (byte)(int)(0xFF & n >> 16);
22 | b[i + 2] = (byte)(int)(0xFF & n >> 8);
23 | b[i + 3] = (byte)(int)(0xFF & n);
24 | }
25 |
26 | private long SHL(long x, int n)
27 | {
28 | return (x & 0xFFFFFFFF) << n;
29 | }
30 |
31 | private long ROTL(long x, int n)
32 | {
33 | return SHL(x, n) | x >> (32 - n);
34 | }
35 |
36 | private void SWAP(long[] sk, int i)
37 | {
38 | long t = sk[i];
39 | sk[i] = sk[(31 - i)];
40 | sk[(31 - i)] = t;
41 | }
42 |
43 | public static final byte[] SboxTable = { (byte) 0xd6, (byte) 0x90, (byte) 0xe9, (byte) 0xfe,
44 | (byte) 0xcc, (byte) 0xe1, 0x3d, (byte) 0xb7, 0x16, (byte) 0xb6,
45 | 0x14, (byte) 0xc2, 0x28, (byte) 0xfb, 0x2c, 0x05, 0x2b, 0x67,
46 | (byte) 0x9a, 0x76, 0x2a, (byte) 0xbe, 0x04, (byte) 0xc3,
47 | (byte) 0xaa, 0x44, 0x13, 0x26, 0x49, (byte) 0x86, 0x06,
48 | (byte) 0x99, (byte) 0x9c, 0x42, 0x50, (byte) 0xf4, (byte) 0x91,
49 | (byte) 0xef, (byte) 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43,
50 | (byte) 0xed, (byte) 0xcf, (byte) 0xac, 0x62, (byte) 0xe4,
51 | (byte) 0xb3, 0x1c, (byte) 0xa9, (byte) 0xc9, 0x08, (byte) 0xe8,
52 | (byte) 0x95, (byte) 0x80, (byte) 0xdf, (byte) 0x94, (byte) 0xfa,
53 | 0x75, (byte) 0x8f, 0x3f, (byte) 0xa6, 0x47, 0x07, (byte) 0xa7,
54 | (byte) 0xfc, (byte) 0xf3, 0x73, 0x17, (byte) 0xba, (byte) 0x83,
55 | 0x59, 0x3c, 0x19, (byte) 0xe6, (byte) 0x85, 0x4f, (byte) 0xa8,
56 | 0x68, 0x6b, (byte) 0x81, (byte) 0xb2, 0x71, 0x64, (byte) 0xda,
57 | (byte) 0x8b, (byte) 0xf8, (byte) 0xeb, 0x0f, 0x4b, 0x70, 0x56,
58 | (byte) 0x9d, 0x35, 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, (byte) 0xd1,
59 | (byte) 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, (byte) 0x87,
60 | (byte) 0xd4, 0x00, 0x46, 0x57, (byte) 0x9f, (byte) 0xd3, 0x27,
61 | 0x52, 0x4c, 0x36, 0x02, (byte) 0xe7, (byte) 0xa0, (byte) 0xc4,
62 | (byte) 0xc8, (byte) 0x9e, (byte) 0xea, (byte) 0xbf, (byte) 0x8a,
63 | (byte) 0xd2, 0x40, (byte) 0xc7, 0x38, (byte) 0xb5, (byte) 0xa3,
64 | (byte) 0xf7, (byte) 0xf2, (byte) 0xce, (byte) 0xf9, 0x61, 0x15,
65 | (byte) 0xa1, (byte) 0xe0, (byte) 0xae, 0x5d, (byte) 0xa4,
66 | (byte) 0x9b, 0x34, 0x1a, 0x55, (byte) 0xad, (byte) 0x93, 0x32,
67 | 0x30, (byte) 0xf5, (byte) 0x8c, (byte) 0xb1, (byte) 0xe3, 0x1d,
68 | (byte) 0xf6, (byte) 0xe2, 0x2e, (byte) 0x82, 0x66, (byte) 0xca,
69 | 0x60, (byte) 0xc0, 0x29, 0x23, (byte) 0xab, 0x0d, 0x53, 0x4e, 0x6f,
70 | (byte) 0xd5, (byte) 0xdb, 0x37, 0x45, (byte) 0xde, (byte) 0xfd,
71 | (byte) 0x8e, 0x2f, 0x03, (byte) 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b,
72 | 0x51, (byte) 0x8d, 0x1b, (byte) 0xaf, (byte) 0x92, (byte) 0xbb,
73 | (byte) 0xdd, (byte) 0xbc, 0x7f, 0x11, (byte) 0xd9, 0x5c, 0x41,
74 | 0x1f, 0x10, 0x5a, (byte) 0xd8, 0x0a, (byte) 0xc1, 0x31,
75 | (byte) 0x88, (byte) 0xa5, (byte) 0xcd, 0x7b, (byte) 0xbd, 0x2d,
76 | 0x74, (byte) 0xd0, 0x12, (byte) 0xb8, (byte) 0xe5, (byte) 0xb4,
77 | (byte) 0xb0, (byte) 0x89, 0x69, (byte) 0x97, 0x4a, 0x0c,
78 | (byte) 0x96, 0x77, 0x7e, 0x65, (byte) 0xb9, (byte) 0xf1, 0x09,
79 | (byte) 0xc5, 0x6e, (byte) 0xc6, (byte) 0x84, 0x18, (byte) 0xf0,
80 | 0x7d, (byte) 0xec, 0x3a, (byte) 0xdc, 0x4d, 0x20, 0x79,
81 | (byte) 0xee, 0x5f, 0x3e, (byte) 0xd7, (byte) 0xcb, 0x39, 0x48 };
82 |
83 | public static final int[] FK = { 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc };
84 |
85 | public static final int[] CK = { 0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
86 | 0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
87 | 0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
88 | 0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
89 | 0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
90 | 0x30373e45,0x4c535a61,0x686f767d,0x848b9299,
91 | 0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
92 | 0x10171e25,0x2c333a41,0x484f565d,0x646b7279 };
93 |
94 | private byte sm4Sbox(byte inch)
95 | {
96 | int i = inch & 0xFF;
97 | byte retVal = SboxTable[i];
98 | return retVal;
99 | }
100 |
101 | private long sm4Lt(long ka)
102 | {
103 | long bb = 0L;
104 | long c = 0L;
105 | byte[] a = new byte[4];
106 | byte[] b = new byte[4];
107 | PUT_ULONG_BE(ka, a, 0);
108 | b[0] = sm4Sbox(a[0]);
109 | b[1] = sm4Sbox(a[1]);
110 | b[2] = sm4Sbox(a[2]);
111 | b[3] = sm4Sbox(a[3]);
112 | bb = GET_ULONG_BE(b, 0);
113 | c = bb ^ ROTL(bb, 2) ^ ROTL(bb, 10) ^ ROTL(bb, 18) ^ ROTL(bb, 24);
114 | return c;
115 | }
116 |
117 | private long sm4F(long x0, long x1, long x2, long x3, long rk)
118 | {
119 | return x0 ^ sm4Lt(x1 ^ x2 ^ x3 ^ rk);
120 | }
121 |
122 | private long sm4CalciRK(long ka)
123 | {
124 | long bb = 0L;
125 | long rk = 0L;
126 | byte[] a = new byte[4];
127 | byte[] b = new byte[4];
128 | PUT_ULONG_BE(ka, a, 0);
129 | b[0] = sm4Sbox(a[0]);
130 | b[1] = sm4Sbox(a[1]);
131 | b[2] = sm4Sbox(a[2]);
132 | b[3] = sm4Sbox(a[3]);
133 | bb = GET_ULONG_BE(b, 0);
134 | rk = bb ^ ROTL(bb, 13) ^ ROTL(bb, 23);
135 | return rk;
136 | }
137 |
138 | private void sm4_setkey(long[] SK, byte[] key)
139 | {
140 | long[] MK = new long[4];
141 | long[] k = new long[36];
142 | int i = 0;
143 | MK[0] = GET_ULONG_BE(key, 0);
144 | MK[1] = GET_ULONG_BE(key, 4);
145 | MK[2] = GET_ULONG_BE(key, 8);
146 | MK[3] = GET_ULONG_BE(key, 12);
147 | k[0] = MK[0] ^ (long) FK[0];
148 | k[1] = MK[1] ^ (long) FK[1];
149 | k[2] = MK[2] ^ (long) FK[2];
150 | k[3] = MK[3] ^ (long) FK[3];
151 | for (; i < 32; i++)
152 | {
153 | k[(i + 4)] = (k[i] ^ sm4CalciRK(k[(i + 1)] ^ k[(i + 2)] ^ k[(i + 3)] ^ (long) CK[i]));
154 | SK[i] = k[(i + 4)];
155 | }
156 | }
157 |
158 | private void sm4_one_round(long[] sk, byte[] input, byte[] output)
159 | {
160 | int i = 0;
161 | long[] ulbuf = new long[36];
162 | ulbuf[0] = GET_ULONG_BE(input, 0);
163 | ulbuf[1] = GET_ULONG_BE(input, 4);
164 | ulbuf[2] = GET_ULONG_BE(input, 8);
165 | ulbuf[3] = GET_ULONG_BE(input, 12);
166 | while (i < 32)
167 | {
168 | ulbuf[(i + 4)] = sm4F(ulbuf[i], ulbuf[(i + 1)], ulbuf[(i + 2)], ulbuf[(i + 3)], sk[i]);
169 | i++;
170 | }
171 | PUT_ULONG_BE(ulbuf[35], output, 0);
172 | PUT_ULONG_BE(ulbuf[34], output, 4);
173 | PUT_ULONG_BE(ulbuf[33], output, 8);
174 | PUT_ULONG_BE(ulbuf[32], output, 12);
175 | }
176 |
177 | private byte[] padding(byte[] input, int mode)
178 | {
179 | if (input == null)
180 | {
181 | return null;
182 | }
183 |
184 | byte[] ret = (byte[]) null;
185 | if (mode == SM4_ENCRYPT)
186 | {
187 | int p = 16 - input.length % 16;
188 | ret = new byte[input.length + p];
189 | System.arraycopy(input, 0, ret, 0, input.length);
190 | for (int i = 0; i < p; i++)
191 | {
192 | ret[input.length + i] = (byte) p;
193 | }
194 | }
195 | else
196 | {
197 | int p = input[input.length - 1];
198 | ret = new byte[input.length - p];
199 | System.arraycopy(input, 0, ret, 0, input.length - p);
200 | }
201 | return ret;
202 | }
203 |
204 | public void sm4_setkey_enc(SM4_Context ctx, byte[] key) throws Exception
205 | {
206 | if (ctx == null)
207 | {
208 | throw new Exception("ctx is null!");
209 | }
210 |
211 | if (key == null || key.length != 16)
212 | {
213 | throw new Exception("key error!");
214 | }
215 |
216 | ctx.mode = SM4_ENCRYPT;
217 | sm4_setkey(ctx.sk, key);
218 | }
219 |
220 | public void sm4_setkey_dec(SM4_Context ctx, byte[] key) throws Exception
221 | {
222 | if (ctx == null)
223 | {
224 | throw new Exception("ctx is null!");
225 | }
226 |
227 | if (key == null || key.length != 16)
228 | {
229 | throw new Exception("key error!");
230 | }
231 |
232 | int i = 0;
233 | ctx.mode = SM4_DECRYPT;
234 | sm4_setkey(ctx.sk, key);
235 | for (i = 0; i < 16; i++)
236 | {
237 | SWAP(ctx.sk, i);
238 | }
239 | }
240 |
241 | public byte[] sm4_crypt_ecb(SM4_Context ctx, byte[] input) throws Exception
242 | {
243 | if (input == null)
244 | {
245 | throw new Exception("input is null!");
246 | }
247 |
248 | if ((ctx.isPadding) && (ctx.mode == SM4_ENCRYPT))
249 | {
250 | input = padding(input, SM4_ENCRYPT);
251 | }
252 |
253 | int length = input.length;
254 | ByteArrayInputStream bins = new ByteArrayInputStream(input);
255 | ByteArrayOutputStream bous = new ByteArrayOutputStream();
256 | for(; length > 0; length -= 16)
257 | {
258 | byte[] in = new byte[16];
259 | byte[] out = new byte[16];
260 | bins.read(in);
261 | sm4_one_round(ctx.sk, in, out);
262 | bous.write(out);
263 | }
264 |
265 | byte[] output = bous.toByteArray();
266 | if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
267 | {
268 | output = padding(output, SM4_DECRYPT);
269 | }
270 | bins.close();
271 | bous.close();
272 | return output;
273 | }
274 |
275 | public byte[] sm4_crypt_cbc(SM4_Context ctx, byte[] iv, byte[] input) throws Exception
276 | {
277 | if (iv == null || iv.length != 16)
278 | {
279 | throw new Exception("iv error!");
280 | }
281 |
282 | if (input == null)
283 | {
284 | throw new Exception("input is null!");
285 | }
286 |
287 | if (ctx.isPadding && ctx.mode == SM4_ENCRYPT)
288 | {
289 | input = padding(input, SM4_ENCRYPT);
290 | }
291 |
292 | int i = 0;
293 | int length = input.length;
294 | ByteArrayInputStream bins = new ByteArrayInputStream(input);
295 | ByteArrayOutputStream bous = new ByteArrayOutputStream();
296 | if (ctx.mode == SM4_ENCRYPT)
297 | {
298 | for(; length > 0; length -= 16)
299 | {
300 | byte[] in = new byte[16];
301 | byte[] out = new byte[16];
302 | byte[] out1 = new byte[16];
303 |
304 | bins.read(in);
305 | for (i = 0; i < 16; i++)
306 | {
307 | out[i] = ((byte) (in[i] ^ iv[i]));
308 | }
309 | sm4_one_round(ctx.sk, out, out1);
310 | System.arraycopy(out1, 0, iv, 0, 16);
311 | bous.write(out1);
312 | }
313 | }
314 | else
315 | {
316 | byte[] temp = new byte[16];
317 | for(; length > 0; length -= 16)
318 | {
319 | byte[] in = new byte[16];
320 | byte[] out = new byte[16];
321 | byte[] out1 = new byte[16];
322 |
323 | bins.read(in);
324 | System.arraycopy(in, 0, temp, 0, 16);
325 | sm4_one_round(ctx.sk, in, out);
326 | for (i = 0; i < 16; i++)
327 | {
328 | out1[i] = ((byte) (out[i] ^ iv[i]));
329 | }
330 | System.arraycopy(temp, 0, iv, 0, 16);
331 | bous.write(out1);
332 | }
333 | }
334 |
335 | byte[] output = bous.toByteArray();
336 | if (ctx.isPadding && ctx.mode == SM4_DECRYPT)
337 | {
338 | output = padding(output, SM4_DECRYPT);
339 | }
340 | bins.close();
341 | bous.close();
342 | return output;
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/src/main/java/com/heshidai/security/cipher/Util.java:
--------------------------------------------------------------------------------
1 | package com.heshidai.security.cipher;
2 |
3 | import java.math.BigInteger;
4 |
5 | public class Util
6 | {
7 | /**
8 | * 整形转换成网络传输的字节流(字节数组)型数据
9 | *
10 | * @param num 一个整型数据
11 | * @return 4个字节的自己数组
12 | */
13 | public static byte[] intToBytes(int num)
14 | {
15 | byte[] bytes = new byte[4];
16 | bytes[0] = (byte) (0xff & (num >> 0));
17 | bytes[1] = (byte) (0xff & (num >> 8));
18 | bytes[2] = (byte) (0xff & (num >> 16));
19 | bytes[3] = (byte) (0xff & (num >> 24));
20 | return bytes;
21 | }
22 |
23 | /**
24 | * 四个字节的字节数据转换成一个整形数据
25 | *
26 | * @param bytes 4个字节的字节数组
27 | * @return 一个整型数据
28 | */
29 | public static int byteToInt(byte[] bytes)
30 | {
31 | int num = 0;
32 | int temp;
33 | temp = (0x000000ff & (bytes[0])) << 0;
34 | num = num | temp;
35 | temp = (0x000000ff & (bytes[1])) << 8;
36 | num = num | temp;
37 | temp = (0x000000ff & (bytes[2])) << 16;
38 | num = num | temp;
39 | temp = (0x000000ff & (bytes[3])) << 24;
40 | num = num | temp;
41 | return num;
42 | }
43 |
44 | /**
45 | * 长整形转换成网络传输的字节流(字节数组)型数据
46 | *
47 | * @param num 一个长整型数据
48 | * @return 4个字节的自己数组
49 | */
50 | public static byte[] longToBytes(long num)
51 | {
52 | byte[] bytes = new byte[8];
53 | for (int i = 0; i < 8; i++)
54 | {
55 | bytes[i] = (byte) (0xff & (num >> (i * 8)));
56 | }
57 |
58 | return bytes;
59 | }
60 |
61 | /**
62 | * 大数字转换字节流(字节数组)型数据
63 | *
64 | * @param n
65 | * @return
66 | */
67 | public static byte[] byteConvert32Bytes(BigInteger n)
68 | {
69 | byte tmpd[] = (byte[])null;
70 | if(n == null)
71 | {
72 | return null;
73 | }
74 |
75 | if(n.toByteArray().length == 33)
76 | {
77 | tmpd = new byte[32];
78 | System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
79 | }
80 | else if(n.toByteArray().length == 32)
81 | {
82 | tmpd = n.toByteArray();
83 | }
84 | else
85 | {
86 | tmpd = new byte[32];
87 | for(int i = 0; i < 32 - n.toByteArray().length; i++)
88 | {
89 | tmpd[i] = 0;
90 | }
91 | System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
92 | }
93 | return tmpd;
94 | }
95 |
96 | /**
97 | * 换字节流(字节数组)型数据转大数字
98 | *
99 | * @param b
100 | * @return
101 | */
102 | public static BigInteger byteConvertInteger(byte[] b)
103 | {
104 | if (b[0] < 0)
105 | {
106 | byte[] temp = new byte[b.length + 1];
107 | temp[0] = 0;
108 | System.arraycopy(b, 0, temp, 1, b.length);
109 | return new BigInteger(temp);
110 | }
111 | return new BigInteger(b);
112 | }
113 |
114 | /**
115 | * 根据字节数组获得值(十六进制数字)
116 | *
117 | * @param bytes
118 | * @return
119 | */
120 | public static String getHexString(byte[] bytes)
121 | {
122 | return getHexString(bytes, true);
123 | }
124 |
125 | /**
126 | * 根据字节数组获得值(十六进制数字)
127 | *
128 | * @param bytes
129 | * @param upperCase
130 | * @return
131 | */
132 | public static String getHexString(byte[] bytes, boolean upperCase)
133 | {
134 | String ret = "";
135 | for (int i = 0; i < bytes.length; i++)
136 | {
137 | ret += Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1);
138 | }
139 | return upperCase ? ret.toUpperCase() : ret;
140 | }
141 |
142 | /**
143 | * 打印十六进制字符串
144 | *
145 | * @param bytes
146 | */
147 | public static void printHexString(byte[] bytes)
148 | {
149 | for (int i = 0; i < bytes.length; i++)
150 | {
151 | String hex = Integer.toHexString(bytes[i] & 0xFF);
152 | if (hex.length() == 1)
153 | {
154 | hex = '0' + hex;
155 | }
156 | System.out.print("0x" + hex.toUpperCase() + ",");
157 | }
158 | System.out.println("");
159 | }
160 |
161 | /**
162 | * Convert hex string to byte[]
163 | *
164 | * @param hexString
165 | * the hex string
166 | * @return byte[]
167 | */
168 | public static byte[] hexStringToBytes(String hexString)
169 | {
170 | if (hexString == null || hexString.equals(""))
171 | {
172 | return null;
173 | }
174 |
175 | hexString = hexString.toUpperCase();
176 | int length = hexString.length() / 2;
177 | char[] hexChars = hexString.toCharArray();
178 | byte[] d = new byte[length];
179 | for (int i = 0; i < length; i++)
180 | {
181 | int pos = i * 2;
182 | d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
183 | }
184 | return d;
185 | }
186 |
187 | /**
188 | * Convert char to byte
189 | *
190 | * @param c
191 | * char
192 | * @return byte
193 | */
194 | public static byte charToByte(char c)
195 | {
196 | return (byte) "0123456789ABCDEF".indexOf(c);
197 | }
198 |
199 | /**
200 | * 用于建立十六进制字符的输出的小写字符数组
201 | */
202 | private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5',
203 | '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
204 |
205 | /**
206 | * 用于建立十六进制字符的输出的大写字符数组
207 | */
208 | private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5',
209 | '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
210 |
211 | /**
212 | * 将字节数组转换为十六进制字符数组
213 | *
214 | * @param data byte[]
215 | * @return 十六进制char[]
216 | */
217 | public static char[] encodeHex(byte[] data) {
218 | return encodeHex(data, true);
219 | }
220 |
221 | /**
222 | * 将字节数组转换为十六进制字符数组
223 | *
224 | * @param data byte[]
225 | * @param toLowerCase true 传换成小写格式 , false 传换成大写格式
226 | * @return 十六进制char[]
227 | */
228 | public static char[] encodeHex(byte[] data, boolean toLowerCase) {
229 | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
230 | }
231 |
232 | /**
233 | * 将字节数组转换为十六进制字符数组
234 | *
235 | * @param data byte[]
236 | * @param toDigits 用于控制输出的char[]
237 | * @return 十六进制char[]
238 | */
239 | protected static char[] encodeHex(byte[] data, char[] toDigits) {
240 | int l = data.length;
241 | char[] out = new char[l << 1];
242 | // two characters form the hex value.
243 | for (int i = 0, j = 0; i < l; i++) {
244 | out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
245 | out[j++] = toDigits[0x0F & data[i]];
246 | }
247 | return out;
248 | }
249 |
250 | /**
251 | * 将字节数组转换为十六进制字符串
252 | *
253 | * @param data byte[]
254 | * @return 十六进制String
255 | */
256 | public static String encodeHexString(byte[] data) {
257 | return encodeHexString(data, true);
258 | }
259 |
260 | /**
261 | * 将字节数组转换为十六进制字符串
262 | *
263 | * @param data byte[]
264 | * @param toLowerCase true 传换成小写格式 , false 传换成大写格式
265 | * @return 十六进制String
266 | */
267 | public static String encodeHexString(byte[] data, boolean toLowerCase) {
268 | return encodeHexString(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
269 | }
270 |
271 | /**
272 | * 将字节数组转换为十六进制字符串
273 | *
274 | * @param data byte[]
275 | * @param toDigits 用于控制输出的char[]
276 | * @return 十六进制String
277 | */
278 | protected static String encodeHexString(byte[] data, char[] toDigits) {
279 | return new String(encodeHex(data, toDigits));
280 | }
281 |
282 | /**
283 | * 将十六进制字符数组转换为字节数组
284 | *
285 | * @param data 十六进制char[]
286 | * @return byte[]
287 | * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
288 | */
289 | public static byte[] decodeHex(char[] data) {
290 | int len = data.length;
291 |
292 | if ((len & 0x01) != 0) {
293 | throw new RuntimeException("Odd number of characters.");
294 | }
295 |
296 | byte[] out = new byte[len >> 1];
297 |
298 | // two characters form the hex value.
299 | for (int i = 0, j = 0; j < len; i++) {
300 | int f = toDigit(data[j], j) << 4;
301 | j++;
302 | f = f | toDigit(data[j], j);
303 | j++;
304 | out[i] = (byte) (f & 0xFF);
305 | }
306 |
307 | return out;
308 | }
309 |
310 | /**
311 | * 将十六进制字符转换成一个整数
312 | *
313 | * @param ch 十六进制char
314 | * @param index 十六进制字符在字符数组中的位置
315 | * @return 一个整数
316 | * @throws RuntimeException 当ch不是一个合法的十六进制字符时,抛出运行时异常
317 | */
318 | protected static int toDigit(char ch, int index) {
319 | int digit = Character.digit(ch, 16);
320 | if (digit == -1) {
321 | throw new RuntimeException("Illegal hexadecimal character " + ch
322 | + " at index " + index);
323 | }
324 | return digit;
325 | }
326 |
327 | /**
328 | * 数字字符串转ASCII码字符串
329 | *
330 | * @param String
331 | * 字符串
332 | * @return ASCII字符串
333 | */
334 | public static String StringToAsciiString(String content) {
335 | String result = "";
336 | int max = content.length();
337 | for (int i = 0; i < max; i++) {
338 | char c = content.charAt(i);
339 | String b = Integer.toHexString(c);
340 | result = result + b;
341 | }
342 | return result;
343 | }
344 |
345 | /**
346 | * 十六进制转字符串
347 | *
348 | * @param hexString
349 | * 十六进制字符串
350 | * @param encodeType
351 | * 编码类型4:Unicode,2:普通编码
352 | * @return 字符串
353 | */
354 | public static String hexStringToString(String hexString, int encodeType) {
355 | String result = "";
356 | int max = hexString.length() / encodeType;
357 | for (int i = 0; i < max; i++) {
358 | char c = (char) hexStringToAlgorism(hexString
359 | .substring(i * encodeType, (i + 1) * encodeType));
360 | result += c;
361 | }
362 | return result;
363 | }
364 |
365 | /**
366 | * 十六进制字符串装十进制
367 | *
368 | * @param hex
369 | * 十六进制字符串
370 | * @return 十进制数值
371 | */
372 | public static int hexStringToAlgorism(String hex) {
373 | hex = hex.toUpperCase();
374 | int max = hex.length();
375 | int result = 0;
376 | for (int i = max; i > 0; i--) {
377 | char c = hex.charAt(i - 1);
378 | int algorism = 0;
379 | if (c >= '0' && c <= '9') {
380 | algorism = c - '0';
381 | } else {
382 | algorism = c - 55;
383 | }
384 | result += Math.pow(16, max - i) * algorism;
385 | }
386 | return result;
387 | }
388 |
389 | /**
390 | * 十六转二进制
391 | *
392 | * @param hex
393 | * 十六进制字符串
394 | * @return 二进制字符串
395 | */
396 | public static String hexStringToBinary(String hex) {
397 | hex = hex.toUpperCase();
398 | String result = "";
399 | int max = hex.length();
400 | for (int i = 0; i < max; i++) {
401 | char c = hex.charAt(i);
402 | switch (c) {
403 | case '0':
404 | result += "0000";
405 | break;
406 | case '1':
407 | result += "0001";
408 | break;
409 | case '2':
410 | result += "0010";
411 | break;
412 | case '3':
413 | result += "0011";
414 | break;
415 | case '4':
416 | result += "0100";
417 | break;
418 | case '5':
419 | result += "0101";
420 | break;
421 | case '6':
422 | result += "0110";
423 | break;
424 | case '7':
425 | result += "0111";
426 | break;
427 | case '8':
428 | result += "1000";
429 | break;
430 | case '9':
431 | result += "1001";
432 | break;
433 | case 'A':
434 | result += "1010";
435 | break;
436 | case 'B':
437 | result += "1011";
438 | break;
439 | case 'C':
440 | result += "1100";
441 | break;
442 | case 'D':
443 | result += "1101";
444 | break;
445 | case 'E':
446 | result += "1110";
447 | break;
448 | case 'F':
449 | result += "1111";
450 | break;
451 | }
452 | }
453 | return result;
454 | }
455 |
456 | /**
457 | * ASCII码字符串转数字字符串
458 | *
459 | * @param String
460 | * ASCII字符串
461 | * @return 字符串
462 | */
463 | public static String AsciiStringToString(String content) {
464 | String result = "";
465 | int length = content.length() / 2;
466 | for (int i = 0; i < length; i++) {
467 | String c = content.substring(i * 2, i * 2 + 2);
468 | int a = hexStringToAlgorism(c);
469 | char b = (char) a;
470 | String d = String.valueOf(b);
471 | result += d;
472 | }
473 | return result;
474 | }
475 |
476 | /**
477 | * 将十进制转换为指定长度的十六进制字符串
478 | *
479 | * @param algorism
480 | * int 十进制数字
481 | * @param maxLength
482 | * int 转换后的十六进制字符串长度
483 | * @return String 转换后的十六进制字符串
484 | */
485 | public static String algorismToHexString(int algorism, int maxLength) {
486 | String result = "";
487 | result = Integer.toHexString(algorism);
488 |
489 | if (result.length() % 2 == 1) {
490 | result = "0" + result;
491 | }
492 | return patchHexString(result.toUpperCase(), maxLength);
493 | }
494 |
495 | /**
496 | * 字节数组转为普通字符串(ASCII对应的字符)
497 | *
498 | * @param bytearray
499 | * byte[]
500 | * @return String
501 | */
502 | public static String byteToString(byte[] bytearray) {
503 | String result = "";
504 | char temp;
505 |
506 | int length = bytearray.length;
507 | for (int i = 0; i < length; i++) {
508 | temp = (char) bytearray[i];
509 | result += temp;
510 | }
511 | return result;
512 | }
513 |
514 | /**
515 | * 二进制字符串转十进制
516 | *
517 | * @param binary
518 | * 二进制字符串
519 | * @return 十进制数值
520 | */
521 | public static int binaryToAlgorism(String binary) {
522 | int max = binary.length();
523 | int result = 0;
524 | for (int i = max; i > 0; i--) {
525 | char c = binary.charAt(i - 1);
526 | int algorism = c - '0';
527 | result += Math.pow(2, max - i) * algorism;
528 | }
529 | return result;
530 | }
531 |
532 | /**
533 | * 十进制转换为十六进制字符串
534 | *
535 | * @param algorism
536 | * int 十进制的数字
537 | * @return String 对应的十六进制字符串
538 | */
539 | public static String algorismToHEXString(int algorism) {
540 | String result = "";
541 | result = Integer.toHexString(algorism);
542 |
543 | if (result.length() % 2 == 1) {
544 | result = "0" + result;
545 |
546 | }
547 | result = result.toUpperCase();
548 |
549 | return result;
550 | }
551 |
552 | /**
553 | * HEX字符串前补0,主要用于长度位数不足。
554 | *
555 | * @param str
556 | * String 需要补充长度的十六进制字符串
557 | * @param maxLength
558 | * int 补充后十六进制字符串的长度
559 | * @return 补充结果
560 | */
561 | static public String patchHexString(String str, int maxLength) {
562 | String temp = "";
563 | for (int i = 0; i < maxLength - str.length(); i++) {
564 | temp = "0" + temp;
565 | }
566 | str = (temp + str).substring(0, maxLength);
567 | return str;
568 | }
569 |
570 | /**
571 | * 将一个字符串转换为int
572 | *
573 | * @param s
574 | * String 要转换的字符串
575 | * @param defaultInt
576 | * int 如果出现异常,默认返回的数字
577 | * @param radix
578 | * int 要转换的字符串是什么进制的,如16 8 10.
579 | * @return int 转换后的数字
580 | */
581 | public static int parseToInt(String s, int defaultInt, int radix) {
582 | int i = 0;
583 | try {
584 | i = Integer.parseInt(s, radix);
585 | } catch (NumberFormatException ex) {
586 | i = defaultInt;
587 | }
588 | return i;
589 | }
590 |
591 | /**
592 | * 将一个十进制形式的数字字符串转换为int
593 | *
594 | * @param s
595 | * String 要转换的字符串
596 | * @param defaultInt
597 | * int 如果出现异常,默认返回的数字
598 | * @return int 转换后的数字
599 | */
600 | public static int parseToInt(String s, int defaultInt) {
601 | int i = 0;
602 | try {
603 | i = Integer.parseInt(s);
604 | } catch (NumberFormatException ex) {
605 | i = defaultInt;
606 | }
607 | return i;
608 | }
609 |
610 | /**
611 | * 十六进制串转化为byte数组
612 | *
613 | * @return the array of byte
614 | */
615 | public static byte[] hexToByte(String hex)
616 | throws IllegalArgumentException {
617 | if (hex.length() % 2 != 0) {
618 | throw new IllegalArgumentException();
619 | }
620 | char[] arr = hex.toCharArray();
621 | byte[] b = new byte[hex.length() / 2];
622 | for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
623 | String swap = "" + arr[i++] + arr[i];
624 | int byteint = Integer.parseInt(swap, 16) & 0xFF;
625 | b[j] = new Integer(byteint).byteValue();
626 | }
627 | return b;
628 | }
629 |
630 | /**
631 | * 字节数组转换为十六进制字符串
632 | *
633 | * @param b
634 | * byte[] 需要转换的字节数组
635 | * @return String 十六进制字符串
636 | */
637 | public static String byteToHex(byte b[]) {
638 | if (b == null) {
639 | throw new IllegalArgumentException(
640 | "Argument b ( byte array ) is null! ");
641 | }
642 | String hs = "";
643 | String stmp = "";
644 | for (int n = 0; n < b.length; n++) {
645 | stmp = Integer.toHexString(b[n] & 0xff);
646 | if (stmp.length() == 1) {
647 | hs = hs + "0" + stmp;
648 | } else {
649 | hs = hs + stmp;
650 | }
651 | }
652 | return hs.toUpperCase();
653 | }
654 |
655 | public static byte[] subByte(byte[] input, int startIndex, int length) {
656 | byte[] bt = new byte[length];
657 | for (int i = 0; i < length; i++) {
658 | bt[i] = input[i + startIndex];
659 | }
660 | return bt;
661 | }
662 | }
663 |
--------------------------------------------------------------------------------