国密sm2,sm4(前台vue,后台java)加解密

项目背景

项目改造需要使用国密sm2,sm4加密

  • SM2
    SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
  • SM4
    SM4无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

js端加密(使用sm-crypto)

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

sm2加密类似RSA,有公钥和私钥,这里前端使用公钥加密,加密有两种模式,适配后端这里改为C1C2C3模式。
需要注意的是,这里的加密结果不能直接返回后台,需要在前面加上04表示公钥未压缩

            const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默认为1
            sm2Encrypt(data) {
                // sm2加密密钥
                return '04' + sm2.doEncrypt(data, this.pubkeyHex, cipherMode);
            }
  1. sm4加密:
            sm4Encrypt(data, key) {
                // sm4加密数据
                return sm4.encrypt(data, key);
            }

java端解密(使用Hutool工具包,需引入Bouncy Castle库的依赖)

  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代码实现使用公钥的q值和私钥的d值作为公私钥,所以直接使用hutool生成密钥是无法加解密的,必须做改写

    public static void generateKey() throws NoSuchAlgorithmException {
        // 1. bc库原始写法
        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进制格式的私钥,后端使用
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privatekey.toString(16);

        //16进制格式的公钥,发给前端
        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写法
        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生成密钥

注意密钥长度必须为128位

        SM4 sm4 = new SM4();
        SecretKey secretKey = sm4.getSecretKey();
        byte[] encoded = secretKey.getEncoded();
        String encodeHexStr = HexUtil.encodeHexStr(encoded);
  1. sm2解密
        // JS加密产生的密文
        String cipherData = "0477109887984ca6250635e6e30a58d11efe71abd998271808ec611366197698106b128ef699fe7fa09449bb7ca9527d674cc865a93a4e3593770ecd3ab06291aee81f5459b8500c284e5391956a83ddb2a90f298968a97828b0802749d5e5bbaa1c519489d4a37215ae0d5f7ef0b3a9a2e8dc1ce485544397a66923811c2f44a0";
        byte[] cipherDataByte = Hex.decode(cipherData);
        // 私钥
        String privateKey = "9fb1f241314168f56d0bc0a236c3a8d6f60ebf778e4104ce94a6cc27cdd4d178";
        // 1. 使用bc库解密
        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);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容