需求

前后端交互的加解密算法,要求使用国产的
1、SM1分组密码算法
SM1是由国家密码管理局编制的一种商用密码分组标准对称算法,分组长度和密钥长度均为128位,算法的安全保密强度及相关软硬件实现性能与AES算法相当,目前该算法尚未公开,仅以IP核的形式存在于芯片中,调用该算法时,需要通过加密芯片的接口进行调用。

2、*SM2公钥密码算法
SM2算法是国家密码据于2010年12月17日发布的国密标准椭圆曲线加密算法,是一种基于ECC算法的非对称加密算法,SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,包括SM2-1椭圆曲线数字签名算法,SM2-2椭圆曲线密钥交换协议,SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,对于一般椭圆曲线的离散对数问题,目前只存在指数级计算复杂度的求解方法。与大数分解问题及有限域上离散对数问题相比,椭圆曲线离散对数问题的求解难度要大得多。因此,在相同安全程度要求下,椭圆曲线密码较其他公钥密码所需的秘钥规模要小得多。相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。其加密强度为256位,密钥长度短,安全程度高,可用于数字签名、密钥交换、公钥加密。

3、*SM3密码杂凑算法
SM3是我国采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。据国家密码管理局表示,其安全性及效率与SHA-256相当,也叫密码杂凑算法,属于哈希(摘要)算法的一种,功能与MD5,SHA-1相同。对长度小于264比特的消息m,经过填充、压缩,生成256位杂凑值,和SM2算法一起被公布,该算法位不可逆的算法。在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,可满足多种密码应用的安全需求,算法已公开。

4、*SM4分组密码算法:
SM4是国家密码管理局发布的分组密码算法,于2012年3月正式公布。与DES和AES算法类似,SM4是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。SM4算法加/解密算法是对合运算,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。加密算法与密钥扩展算法均采用32轮非线性迭代结构(Feistel),以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。目前主要用于无线局域网产品。

方案

使用场景:前后端交互使用sm2,后端存储密码时使用sm3

1、pom依赖

<dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcprov-jdk15on</artifactId>
     <version>1.60</version>
</dependency>

2、demo示例

public static void main(String[] args) throws InvalidCipherTextException {
        System.out.println("sm2测试开始-----------");
        X9ECParameters sm2EcParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(sm2EcParameters.getCurve(),sm2EcParameters.getG(),sm2EcParameters.getN());
        ECKeyPairGenerator keyPairGenerator =new ECKeyPairGenerator();
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();

            //私钥
            BigInteger privateKey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
            String privateKeyHex = privateKey.toString(16);
            System.out.println("私钥:" + privateKeyHex);

            //公钥
            ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
            String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
            System.out.println("公钥:" + publicKeyHex);

            String str = SM2Util.encrypt("test",publicKeyHex);
            System.out.println("加密结果:"+str);

            try{
                String res = SM2Util.decrypt(str,privateKeyHex);
                System.out.println("解密结果:"+res);
            }catch (Exception e){
                e.printStackTrace();
            }
            System.out.println("sm2测试结束-----------");

            System.out.println("sm3测试开始-----------");
            String sm3 = SM3Util.sm3Sign("test");
            System.out.println("sm3加密结果"+sm3);
            if(SM3Util.sm3Verify("test",sm3)){
                System.out.println("sm3验证成功");
            }else {
                System.out.println("sm3验证失败");
            }

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

3、结果

sm2测试开始-----------
私钥:bdda9f26ae5884e3f5410902aec78cab6c3f4a7c9d9578e6a9c60ae977d6d645
公钥:041870142d71f518ce9bd6458b4b41b4d49e7fbfd9a14440eb49ed9bbb352e72739d2e2369722ba381db2a7add5093c7a976df49496cb5c08a56e87db877f4e866
加密结果:0445fd5bce247f30cd507314830f57d3278dfdfab3e8fdc6acb93c60a3a4b6bbc09150c065153389d7b0c3581a0a0fd5c3ffe59ed53855a289a98ce9705a5230b752aa8535980ba08db6319eef0f3c1140ccd3d0849f0c78a4478189c1736de07b27254794929c9de9
解密结果:test
sm2测试结束-----------
sm3测试开始-----------
sm3加密结果55e12e91650d2fec56ec74e1d3e4ddbfce2ef3a65890c2a19ecf88a307e76a23
sm3验证成功

4、前端加密

const sm2 = require('sm-crypto').sm2
const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默认为1,这里用0

加密

let base = Base64.encode(msgString);
let encryptData = sm2.doEncrypt(base, publicKey, cipherMode) // 加密结果
conso.log("加密结果:",encryptData);