国密算法sm2、sm3和sm4的java版。基于js版本进行封装,无缝兼容js版公私钥加解密。

Related tags

Security sm-crypto
Overview

sm-crypto

国密算法sm2、sm3和sm4的java版。基于js版本进行封装,无缝兼容js版公私钥加解密。

PS: js版:https://github.com/JuneAndGreen/sm-crypto

PS: 小程序版:https://github.com/wechat-miniprogram/sm-crypto

如何使用

如何引入依赖

如果需要使用已发布的版本,在dependencies中添加如下依赖

<dependency>
    <groupId>com.antherd</groupId>
    <artifactId>sm-crypto</artifactId>
    <version>0.3.2</version>
</dependency>

sm2

获取密钥对

Keypair keypair = Sm2.generateKeyPairHex();
String privateKey = keypair.getPrivateKey(); // 公钥
String publicKey = keypair.getPublicKey(); // 私钥

加密解密

// cipherMode 1 - C1C3C2,0 - C1C2C3,默认为1
String encryptData = Sm2.doEncrypt(msg, publicKey); // 加密结果
String decryptData = Sm2.doDecrypt(encryptData, privateKey); // 解密结果

签名验签

ps:理论上来说,只做纯签名是最快的。

// 纯签名 + 生成椭圆曲线点
String sigValueHex = Sm2.doSignature(msg, privateKey); // 签名
boolean verifyResult = Sm2.doVerifySignature(msg, sigValueHex, publicKey); // 验签结果

// 纯签名
Queue<Point> pointPool = new LinkedList(Arrays.asList(Sm2.getPoint(), Sm2.getPoint(), Sm2.getPoint(), Sm2.getPoint()));
SignatureOptions signatureOptions2 = new SignatureOptions();
signatureOptions2.setPointPool(pointPool); // 传入事先已生成好的椭圆曲线点,可加快签名速度
String sigValueHex2 = Sm2.doSignature(msg, privateKey, signatureOptions2);
boolean verifyResult2 = Sm2.doVerifySignature(msg, sigValueHex2, publicKey); // 验签结果

// 纯签名 + 生成椭圆曲线点 + der编解码
SignatureOptions signatureOptions3 = new SignatureOptions();
signatureOptions3.setDer(true);
String sigValueHex3 = Sm2.doSignature(msg, privateKey, signatureOptions3); // 签名
boolean verifyResult3 = Sm2.doVerifySignature(msg, sigValueHex3, publicKey, signatureOptions3); // 验签结果

// 纯签名 + 生成椭圆曲线点 + sm3杂凑
SignatureOptions signatureOptions4 = new SignatureOptions();
signatureOptions4.setHash(true);
String sigValueHex4 = Sm2.doSignature(msg, privateKey, signatureOptions4); // 签名
boolean verifyResult4 = Sm2.doVerifySignature(msg, sigValueHex4, publicKey, signatureOptions4); // 验签结果

// 纯签名 + 生成椭圆曲线点 + sm3杂凑(不做公钥推导)
SignatureOptions signatureOptions5 = new SignatureOptions();
signatureOptions5.setHash(true);
signatureOptions5.setPublicKey(publicKey); // 传入公钥的话,可以去掉sm3杂凑中推导公钥的过程,速度会比纯签名 + 生成椭圆曲线点 + sm3杂凑快
String sigValueHex5 = Sm2.doSignature(msg, privateKey, signatureOptions5); // 签名
boolean verifyResult5 = Sm2.doVerifySignature(msg, sigValueHex5, publicKey, signatureOptions5); // 验签结果

// 纯签名 + 生成椭圆曲线点 + sm3杂凑 + 不做公钥推 + 添加 userId(长度小于 8192)
// 默认 userId 值为 1234567812345678
SignatureOptions signatureOptions6 = new SignatureOptions();
signatureOptions6.setHash(true);
signatureOptions6.setPublicKey(publicKey);
signatureOptions6.setUserId("testUserId");
String sigValueHex6 = Sm2.doSignature(msg, privateKey, signatureOptions6); // 签名
boolean verifyResult6 = Sm2.doVerifySignature(msg, sigValueHex6, publicKey, signatureOptions6); // 验签结果

获取椭圆曲线点

Point point = Sm2.getPoint(); // 获取一个椭圆曲线点,可在sm2签名时传入

sm3

String hashData = Sm3.sm3("abc"); // 杂凑

sm4

加密

String msg = "hello world! 我是 antherd.";
String key = "0123456789abcdeffedcba9876543210"; // 16 进制字符串,要求为 128 比特

String encryptData1 = Sm4.encrypt(msg, key); // 加密,默认使用 pkcs#5 填充,输出16进制字符串

Sm4Options sm4Options2 = new Sm4Options();
sm4Options2.setPadding("none");
String encryptData2 = Sm4.encrypt(msg, key, sm4Options2); // 加密,不使用 padding,输出16进制字符串

Sm4Options sm4Options3 = new Sm4Options();
sm4Options3.setPadding("none");
byte[] encryptData3 = Sm4.hexToBytes(Sm4.encrypt(msg, key, sm4Options3)); // 加密,不使用 padding,输出转为字节数组

Sm4Options sm4Options4 = new Sm4Options();
sm4Options4.setMode("cbc");
sm4Options4.setIv("fedcba98765432100123456789abcdef");
String encryptData4 = Sm4.encrypt(msg, key, sm4Options4); // 加密,cbc 模式,输出16进制字符串

解密

String encryptData = "0e395deb10f6e8a17e17823e1fd9bd98a1bff1df508b5b8a1efb79ec633d1bb129432ac1b74972dbe97bab04f024e89c"; // 加密后的 16 进制字符串
String key = "0123456789abcdeffedcba9876543210"; // 16 进制字符串,要求为 128 比特

String decryptData5 = Sm4.decrypt(encryptData, key); // 解密,默认使用 pkcs#5 填充,输出 utf8 字符串

Sm4Options sm4Options6 = new Sm4Options();
sm4Options2.setPadding("none");
String decryptData6 = Sm4.decrypt(encryptData, key, sm4Options6); // 解密,不使用 padding,输出 utf8 字符串

Sm4Options sm4Options7 = new Sm4Options();
sm4Options2.setPadding("none");
byte[] decryptData7 = Sm4.utf8ToArray(Sm4.decrypt(encryptData, key, sm4Options7)); // 解密,不使用 padding,输出转为字节数组

Sm4Options sm4Options8 = new Sm4Options();
sm4Options4.setMode("cbc");
sm4Options4.setIv("fedcba98765432100123456789abcdef");
String decryptData8 = Sm4.decrypt(encryptData, key, sm4Options8); // 解密,cbc 模式,输出 utf8 字符串

协议

MIT

Comments
  • 加密解密速度太慢

    加密解密速度太慢

    简单加密一下居然要花接近4s

    @Test
    public void testSm2Encrypt() {
        String data = "{\"abc\":123}";
        String publicKey = "041130412b93ca6ba1b7143d821d363fa12a98bc093dd324e5f47ca7401a75cb8cd098851f40852b5193ca31203f34cc24548dc51ca409933e1d0cd30e4cea6e05";
        String privateKey = "16c8160303ed9cf0af3c8d61f93be5e091c2115276bc9152a9cfe2d7b6a903bc";
        Long before = System.currentTimeMillis();
        String encrypt = Sm2.doEncrypt(data, publicKey);
        Long after = System.currentTimeMillis();
        System.out.println("加密 " + (after - before) + " ms");
        System.out.println("encrypt = " + encrypt);
        before = System.currentTimeMillis();
        String decrypt = Sm2.doDecrypt(encrypt, privateKey);
        after = System.currentTimeMillis();
        System.out.println("解密 " + (after - before) + " ms");
        System.out.println("decrypt = " + decrypt);
    }
    

    这是输出结果 image

    使用其他第三方的库对相同数据进行加密只需要大约15ms左右

    循环10次测试发现也要大约100-300ms左右

    opened by Montaro2017 2
  • 异常吞并,导致不能处理加解密异常

    异常吞并,导致不能处理加解密异常

    不建议直接吞并异常,建议应该与原方法保持一致,吞并异常不知道加解密是否有问题

        public static String decrypt(String encryptData, String key, Sm4Options sm4Options) {
            if (encryptData == null || encryptData.trim().isEmpty()) return "";
            String decryptData = null;
            try {
                decryptData = (String) invocable.invokeFunction("decrypt", encryptData, key, getOptionsMap(sm4Options));
            } catch (ScriptException | NoSuchMethodException e) {
                e.printStackTrace();
            }
            return decryptData;
        }
    
    opened by aimilin6688 1
  • encrypt decrypt time very long

    encrypt decrypt time very long

    public static void main(String[] args) {
        String msg = "159";
        // 16 进制字符串,要求为 128 比特
        String key = "3124456789abcdeffedcba9876543210";
        // 加密,默认使用 pkcs#5 填充,输出16进制字符串
        long ens = System.currentTimeMillis();
        String encryptData1 = Sm4.encrypt(msg, key);
        long ene = System.currentTimeMillis();
        System.out.println("encrypt 1 : " + encryptData1);
        // 解密,默认使用 pkcs#5 填充,输出 utf8 字符串
        long des = System.currentTimeMillis();
        String decryptData1 = Sm4.decrypt(encryptData1, key);
        long dee = System.currentTimeMillis();
        System.out.println("decrypt 1 : " + decryptData1);
        System.out.println("encrypt time:" + (dee - des) + "ms" + ". decrypt time:" + (ene-ens) + "ms");
    }
    

    out result: encrypt 1 : a3121e371c1da5e7237d7b18305ce6fd decrypt 1 : 159 encrypt time:139ms. decrypt time:2582ms

    good first issue improvement 
    opened by PretendMask 1
  • SM4的使用Sm4Options的加密无效,加密结果与不使用Sm4Options的加密结果一样

    SM4的使用Sm4Options的加密无效,加密结果与不使用Sm4Options的加密结果一样

    String msg = "hello world! 我是 antherd."; String key = "0123456789abcdeffedcba9876543210"; // 16 进制字符串,要求为 128 比特

        String encryptData1 = Sm4.encrypt(msg, key); // 加密,默认使用 pkcs#5 填充,输出16进制字符串
        System.out.println(encryptData1);
    
        Sm4Options sm4Options2 = new Sm4Options();
        sm4Options2.setPadding("none");
        String encryptData2 = Sm4.encrypt(msg, key, sm4Options2); // 加密,不使用 padding,输出16进制字符串
        System.out.println(encryptData2);
    
        Sm4Options sm4Options3 = new Sm4Options();
        sm4Options3.setPadding("none");
        byte[] encryptData3 = Sm4.hexToBytes(Sm4.encrypt(msg, key, sm4Options3)); // 加密,不使用 padding,输出转为字节数组
        System.out.println(encryptData3);
    
        Sm4Options sm4Options4 = new Sm4Options();
        sm4Options4.setMode("cbc");
        sm4Options4.setIv("fedcba98765432100123456789abcdef");
        String encryptData4 = Sm4.encrypt(msg, key, sm4Options4); // 加密,cbc 模式,输出16进制字符串
        System.out.println(encryptData4);
    

    四种加密结果都等于 0e395deb10f6e8a17e17823e1fd9bd98ba9d414a1328bb62fd1a83cdedd7e4dd

    opened by wqh331589996 2
  • java版本的0.3.2版本,和js版本的0.3.8版本,无法互相签名验签

    java版本的0.3.2版本,和js版本的0.3.8版本,无法互相签名验签

    publickey: 044310f0521b99a95fcb0a44f21fb0a77e9bda35516eb42208fc3a576ebc8cae93fa94834e22060abd8528483bad0ee010bda0bb32ef111bd8773a91aeb517f8db privatekey: 00d243de79a2741a3b37cc978add7ff39d7ac0d7c7f24ebadd95f3c3c071d4d5cd

    原始串: 1234567890 java版本签名:3044022010ba478cbc88d381b9f9e645e6572ae50878f2ce46eccfcfff753ef7231b834502204511da8360a98384294c3e8893ea2276e18ccc0b954c50671ade8c613a2091b2 js版本验签不通过

    bc版本java签名:304602210089d4f88e39ddbd9308a815b9d02aa2190c21a836126f881458d140db486a32a9022100a01db5715825d050ffef9a42121c6ab72a46db0e43004cce5383f1b12a40bb72 js版本验签可以通过

    opened by xezBachelor 0
Releases(v0.3.2)
Owner
antherd
antherd