國(guó)密sm2,sm4(前臺(tái)vue,后臺(tái)java)加解密

項(xiàng)目背景

項(xiàng)目改造需要使用國(guó)密sm2,sm4加密

  • SM2
    SM2為非對(duì)稱加密,基于ECC。該算法已公開(kāi)。由于該算法基于ECC,故其簽名速度與秘鑰生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一種)安全強(qiáng)度比RSA 2048位高,但運(yùn)算速度快于RSA。
  • SM4
    SM4無(wú)線局域網(wǎng)標(biāo)準(zhǔn)的分組數(shù)據(jù)算法。對(duì)稱加密,密鑰長(zhǎng)度和分組長(zhǎng)度均為128位。

js端加密(使用sm-crypto)

  1. 引入依賴:
    const sm4 = require('sm-crypto').sm4
    const sm2 = require('sm-crypto').sm2
  1. sm2加密:

sm2加密類(lèi)似RSA,有公鑰和私鑰,這里前端使用公鑰加密,加密有兩種模式,適配后端這里改為C1C2C3模式。
需要注意的是,這里的加密結(jié)果不能直接返回后臺(tái),需要在前面加上04表示公鑰未壓縮

            const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默認(rèn)為1
            sm2Encrypt(data) {
                // sm2加密密鑰
                return '04' + sm2.doEncrypt(data, this.pubkeyHex, cipherMode);
            }
  1. sm4加密:
            sm4Encrypt(data, key) {
                // sm4加密數(shù)據(jù)
                return sm4.encrypt(data, key);
            }

java端解密(使用Hutool工具包,需引入Bouncy Castle庫(kù)的依賴)

  1. 引入依賴包
    <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.66</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.66</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.8</version>
        </dependency>
  1. sm2生成密鑰

由于js端sm2代碼實(shí)現(xiàn)使用公鑰的q值和私鑰的d值作為公私鑰,所以直接使用hutool生成密鑰是無(wú)法加解密的,必須做改寫(xiě)

    public static void generateKey() throws NoSuchAlgorithmException {
        // 1. bc庫(kù)原始寫(xiě)法
        X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
        ecKeyPairGenerator.init(new ECKeyGenerationParameters(ecDomainParameters, SecureRandom.getInstance("SHA1PRNG")));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = ecKeyPairGenerator.generateKeyPair();

        //16進(jìn)制格式的私鑰,后端使用
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privatekey.toString(16);

        //16進(jìn)制格式的公鑰,發(fā)給前端
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        byte[] encoded = ecPoint.getEncoded(false);
        String publicKeyHex = Hex.toHexString(encoded);

        System.out.println(privateKeyHex);
        System.out.println(publicKeyHex);

        // 2. hutool寫(xiě)法
        SM2 sm2 = SmUtil.sm2();
        String hutoolPrivateKeyHex = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
        String hutoolPublicKeyHex = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
        System.out.println(hutoolPrivateKeyHex);
        System.out.println(hutoolPublicKeyHex);
    }
  1. sm4生成密鑰

注意密鑰長(zhǎng)度必須為128位

        SM4 sm4 = new SM4();
        SecretKey secretKey = sm4.getSecretKey();
        byte[] encoded = secretKey.getEncoded();
        String encodeHexStr = HexUtil.encodeHexStr(encoded);
  1. sm2解密
        // JS加密產(chǎn)生的密文
        String cipherData = "0477109887984ca6250635e6e30a58d11efe71abd998271808ec611366197698106b128ef699fe7fa09449bb7ca9527d674cc865a93a4e3593770ecd3ab06291aee81f5459b8500c284e5391956a83ddb2a90f298968a97828b0802749d5e5bbaa1c519489d4a37215ae0d5f7ef0b3a9a2e8dc1ce485544397a66923811c2f44a0";
        byte[] cipherDataByte = Hex.decode(cipherData);
        // 私鑰
        String privateKey = "9fb1f241314168f56d0bc0a236c3a8d6f60ebf778e4104ce94a6cc27cdd4d178";
        // 1. 使用bc庫(kù)解密
        X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(privateKey, 16), ecDomainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, privateKeyParameters);
        byte[] bytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
        String data = new String(bytes, CharsetUtil.CHARSET_UTF_8);
        System.out.println(data);

        // 2. 使用hutool解密
        SM2 sm2 = new SM2(ECKeyUtil.toSm2PrivateParams(privateKey), null);
        sm2.setMode(SM2Engine.Mode.C1C2C3);
        sm2.setEncoding(new PlainDSAEncoding());

        String decryptStr = sm2.decryptStr(cipherData, KeyType.PrivateKey);
        System.out.println(decryptStr);
  1. sm4解密

這里的key與前端加密使用的key相同

        SM4 sm4 = new SM4(HexUtil.decodeHex(key));
        String decryptStr = sm4.decryptStr(data);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容