SM2为非对称加密

参考:

github : gotoworld / hsd-cipher-sm

SM2 加密解密 公式密匙 导出

国密算法工具-SmUtil

国密算法工具文档-SmUtil

国密算法介绍

国密即国家密码局认定的国产密码算法,即商用密码。主要有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,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。

作为密码学算法,一定要公开接受行业的检验。

  1. 对称算法:

(DES 3DES AES) --迁移–> SM1 SM4

  1. 非对称密码算法:

(RSA) --迁移–> SM2(椭圆曲线密码)

  1. 散列算法:

(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

maven 仓库 : Hutool All

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);
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Java实现SM2非对称加密的示例代码: ```java import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import java.security.Security; public class SM2Demo { public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); // 生成密钥对 ECKeyPairGenerator gen = new ECKeyPairGenerator(); ECDomainParameters ecSpec = ECDomainParametersUtil.getSM2Parameters(); ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecSpec, null); gen.init(keyGenParam); AsymmetricCipherKeyPair keyPair = gen.generateKeyPair(); ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); // 明文 String plainText = "Hello, SM2!"; // 加密 SM2Engine engine = new SM2Engine(); engine.init(true, new ParametersWithRandom(publicKey, new SecureRandom())); byte[] cipherText = engine.processBlock(plainText.getBytes(), 0, plainText.getBytes().length); // 解密 engine.init(false, privateKey); byte[] decryptedText = engine.processBlock(cipherText, 0, cipherText.length); // 验证解密结果 if (plainText.equals(new String(decryptedText))) { System.out.println("SM2 decryption succeeded!"); } else { System.out.println("SM2 decryption failed!"); } // 签名 SM2Signer signer = new SM2Signer(); signer.init(true, privateKey); signer.update(plainText.getBytes(), 0, plainText.getBytes().length); byte[] signature = signer.generateSignature(); // 验证签名 signer.init(false, publicKey); signer.update(plainText.getBytes(), 0, plainText.getBytes().length); if (signer.verifySignature(signature)) { System.out.println("SM2 signature verification succeeded!"); } else { System.out.println("SM2 signature verification failed!"); } } } ``` 需要注意的是,上述代码中使用了Bouncy Castle作为SM2算法的实现库。在使用前需要先引入Bouncy Castle的相关依赖。此外,代码中还使用了ECDomainParametersUtil类,该类用于获取SM2算法所需的椭圆曲线参数,需要自行实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值