参考:
github : gotoworld / hsd-cipher-sm
国密算法介绍
国密即国家密码局认定的国产密码算法,即商用密码。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
- SM1 为对称加密。
其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
- SM2为非对称加密,基于ECC。
该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
- SM3 消息摘要。
可以用MD5作为对比理解。该算法已公开。校验结果为256位。
- SM4 无线局域网标准的分组数据算法。
对称加密,密钥长度和分组长度均为128位。
由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
作为密码学算法,一定要公开接受行业的检验。
- 对称算法:
(DES 3DES AES) --迁移–> SM1 SM4
- 非对称密码算法:
(RSA) --迁移–> SM2(椭圆曲线密码)
- 散列算法:
(HASH MD4、MD5 SHA-1、SHA-256、SHA-384、SHA512) --迁移–> SM3
依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.7</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.64'
// https://mvnrepository.com/artifact/cn.hutool/hutool-all
implementation group: 'cn.hutool', name: 'hutool-all', version: '4.5.7'
maven 仓库 : Bouncy Castle Provider
demo1 :
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import java.io.*;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
public class Test {
public static void main(String[] args) throws IOException {
//生成私钥和公钥并保存文件
String privatekeyPath = "C:\\Users\\able\\Desktop\\privatekey.pem";
String publickeyPath = "C:\\Users\\able\\Desktop\\publickey.pem";
KeyPair pair = SecureUtil.generateKeyPair("SM2");
byte[] privateKeyArray = pair.getPrivate().getEncoded();
byte[] publicKeyArray = pair.getPublic().getEncoded();
writeBytesToFile(privateKeyArray, privatekeyPath);
writeBytesToFile(publicKeyArray, publickeyPath);
//从文件获取公钥/私钥生成对象
PrivateKey privateKey = SecureUtil.generatePrivateKey(
"SM2",
getBytesFromFile(new File(privatekeyPath))
);
PublicKey publicKey = SecureUtil.generatePublicKey(
"SM2",
getBytesFromFile(new File(publickeyPath))
);
SM2 sm2 = new SM2();
sm2.setPrivateKey(privateKey);
sm2.setPublicKey(publicKey);
System.out.println("======================================");
System.out.println("======================================");
System.out.println("======================================");
String text = "我是一段测试666666";
// 公钥加密字符串,
String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
System.out.println(encryptStr);
// 私钥解密字符串
String decryptStr = StrUtil.utf8Str(
sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
System.out.println(decryptStr);
System.out.println("======================================");
System.out.println("======================================");
System.out.println("======================================");
// 公钥加密文件,
String sourcePath =
"D:\\Users\\able\\IdeaProjects\\java-sm2\\src\\main\\java" +
"\\org\\pzone\\crypto\\JZYJ.zip";
File sourceFile = new File(sourcePath);
byte[] bytes = getBytesFromFile(sourceFile);
byte[] encryptBytes = sm2.encrypt(bytes, KeyType.PublicKey);
String encryptPath =
"D:\\Users\\able\\IdeaProjects\\java-sm2\\src\\main\\java" +
"\\org\\pzone\\crypto\\JZYJ_encrypt.zip";
writeBytesToFile(encryptBytes, encryptPath);
System.out.println("------------------------------");
// 私钥解密文件
File encryptFile = new File(encryptPath);
if (encryptFile.exists()) {
byte[] bytesFromFile = getBytesFromFile(encryptFile);
byte[] decryptBytes = sm2.decrypt(bytesFromFile, KeyType.PrivateKey);
String decryptPath =
"D:\\Users\\able\\IdeaProjects\\java-sm2\\src\\main\\java" +
"\\org\\pzone\\crypto\\JZYJ_decrypt.zip";
writeBytesToFile(decryptBytes, decryptPath);
}
}
public static void writeBytesToFile(byte[] bs, String path) throws IOException {
OutputStream out = new FileOutputStream(path);
InputStream is = new ByteArrayInputStream(bs);
byte[] buff = new byte[1024];
int len = 0;
while ((len = is.read(buff)) != -1) {
out.write(buff, 0, len);
}
is.close();
out.close();
}
// 返回一个byte数组
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);// 获取文件大小
long lengths = file.length();
System.out.println("lengths = " + lengths);
if (lengths > Integer.MAX_VALUE) {
// 文件太大,无法读取
throw new IOException("File is to large " + file.getName());
}
// 创建一个数据来保存文件数据
byte[] bytes = new byte[(int) lengths];// 读取数据到byte数组中
int offset = 0;
int numRead = 0;
while (offset < bytes.length &&
(numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
// 确保所有数据均被读取
if (offset < bytes.length) {
throw new IOException("Could not completely read file " + file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
}
demo2
//自定义密钥对:签名和验签
private static void test3() {
String content = "我是Hanley.";
KeyPair pair = SecureUtil.generateKeyPair("SM2");
final SM2 sm2 = new SM2(pair.getPrivate(), pair.getPublic());
byte[] sign = sm2.sign(content.getBytes());
// true
boolean verify = sm2.verify(content.getBytes(), sign);
System.out.println("verify === " + verify);
}
//使用随机生成的密钥对加密或解密
private static void test1() {
SM2 sm2 = SmUtil.sm2();
// 公钥加密,私钥解密
String text = "我是一段测试aaaa";
String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
System.out.println("text === " + text);
System.out.println("encryptStr === " + encryptStr);
System.out.println("decryptStr === " + decryptStr);
}
//使用自定义密钥对加密或解密
private static void test2() {
KeyPair pair = SecureUtil.generateKeyPair("SM2");
byte[] privateKey = pair.getPrivate().getEncoded();
byte[] publicKey = pair.getPublic().getEncoded();
SM2 sm2 = SmUtil.sm2(privateKey, publicKey);
// 公钥加密,私钥解密
String text = "我是一段测试bbb";
String encryptStr = sm2.encryptBcd(text, KeyType.PublicKey);
String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));
System.out.println("text === " + text);
System.out.println("encryptStr === " + encryptStr);
System.out.println("decryptStr === " + decryptStr);
//打印当前的公私秘钥,保存下来
String privateKeyStr = HexUtil.encodeHexStr(privateKey);
String publicKeyStr = HexUtil.encodeHexStr(publicKey);
System.out.println("私钥: " + privateKeyStr);
System.out.println("公钥: " + publicKeyStr);
// byte[] privateKeyBytes = HexUtil.decodeHex(privateKeyStr);
// byte[] publicKeyBytes = HexUtil.decodeHex(publicKeyStr);
}