您现在的位置是:首页 > 博文答疑 > SM4国密,加密解密测试记录博文答疑

SM4国密,加密解密测试记录

Leo2022-07-06【5】

简介

SM4是国密对称算法,该算法是公开的。这里测试使用的是SM4 CEB,也就是不使用iv。

 

前端JS测试代码:

安装依赖:
npm install --save sm-crypto

可到package.json中找到:
"sm-crypto": "^0.3.8",

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>源数据:{{data_source}} </p>
    <p>加密数据:{{data_encrypt}} </p>
    <p>解密数据:{{data_decrypt}} </p>
  </div>
</template>

<script>
export default {
  name: 'Test',
  props: {
    msg: String,
    data_source: String,
    data_encrypt: String,
    data_decrypt: String
  },mounted:function()
  {
    const sm4 = require('sm-crypto').sm4;
    const sm4Key = '51d95b1dc43a9faaad0570f81c755fcc';
    this.data_source = '{"test:" 1}';
    let sm4Encrypt = sm4.encrypt(this.data_source, sm4Key); //加密
    this.data_encrypt = sm4Encrypt;

    let sm4Decrypt = sm4.decrypt(sm4Encrypt, sm4Key); //解密
    this.data_decrypt = sm4Decrypt;
  }

}
</script>


 结果:

 

后端Springboot架构下的测试:

引入dependency :

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

测试代码:

package com.test.controller;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


/**
 * spring-boot-demo
 */
@RestController
@RequestMapping(value = "/test")
public class TestController {
	@RequestMapping
	public String index() throws Exception {

		String txt = "{\"test:\" 1}";
		byte[] key = hexTobytes("51d95b1dc43a9faaad0570f81c755fcc");
		byte[] output = encryptEcbPkcs5Padding(txt.getBytes(StandardCharsets.UTF_8), key);
		String hex = Hex.toHexString(output);
		System.out.println("加密后结果 ==>"+hex);
		// 解密
		byte[] input = Hex.decode(hex);
		output = decryptEcbPkcs5Padding(input, key);
		String s = new String(output, StandardCharsets.UTF_8);
		System.out.println("解密后结果 ==>"+s);
		System.out.println("key is ==>"+Hex.toHexString(key));

		return "hello world";

	}

	private static final String ALGORITHM_NAME = "SM4";
	private static final String ALGORITHM_ECB_PKCS5PADDING = "SM4/ECB/PKCS5Padding";

	/**
	 * SM4算法目前只支持128位(即密钥16字节)
	 */
	private static final int DEFAULT_KEY_SIZE = 128;

	static {
		// 防止内存中出现多次BouncyCastleProvider的实例
		if (null == Security.getProvider(BouncyCastleProvider.PROVIDER_NAME)) {
			Security.addProvider(new BouncyCastleProvider());
		}
	}


	/**
	 * 生成密钥
	 * <p>建议使用org.bouncycastle.util.encoders.Hex将二进制转成HEX字符串</p>
	 *
	 * @return 密钥16位
	 * @throws Exception 生成密钥异常
	 */
	public static byte[] generateKey() throws Exception {
		KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
		kg.init(DEFAULT_KEY_SIZE, new SecureRandom());
		return kg.generateKey().getEncoded();
	}
	/**
	 * 将二进制转成HEX字符串
	 */
	public static String encodersHex( byte[] bytes){
		return  org.bouncycastle.util.encoders.Hex.toHexString(bytes);
	}

	/**
	 * Hex转byte[],两种情况,Hex长度为奇数最后一个字符会被舍去
	 */
	public static byte[] hexTobytes(String hex) {
		if (hex.length() < 1) {
			return null;
		} else {
			byte[] result = new byte[hex.length() / 2];
			int j = 0;
			for(int i = 0; i < hex.length(); i+=2) {
				result[j++] = (byte)Integer.parseInt(hex.substring(i,i+2), 16);
			}
			return result;
		}
	}

	/**
	 * 加密,SM4-ECB-PKCS5Padding
	 *
	 * @param data 要加密的明文
	 * @param key  密钥16字节,使用Sm4Util.generateKey()生成
	 * @return 加密后的密文
	 * @throws Exception 加密异常
	 */
	public static byte[] encryptEcbPkcs5Padding(byte[] data, byte[] key) throws Exception {
		return sm4(data, key, ALGORITHM_ECB_PKCS5PADDING, null, Cipher.ENCRYPT_MODE);
	}

	/**
	 * 解密,SM4-ECB-PKCS5Padding
	 *
	 * @param data 要解密的密文
	 * @param key  密钥16字节,使用Sm4Util.generateKey()生成
	 * @return 解密后的明文
	 * @throws Exception 解密异常
	 */
	public static byte[] decryptEcbPkcs5Padding(byte[] data, byte[] key) throws Exception {
		return sm4(data, key, ALGORITHM_ECB_PKCS5PADDING, null, Cipher.DECRYPT_MODE);
	}

	/**
	 * SM4对称加解密
	 *
	 * @param input   明文(加密模式)或密文(解密模式)
	 * @param key     密钥
	 * @param sm4mode sm4加密模式
	 * @param iv      初始向量(ECB模式下传NULL)
	 * @param mode    Cipher.ENCRYPT_MODE - 加密;Cipher.DECRYPT_MODE - 解密
	 * @return 密文(加密模式)或明文(解密模式)
	 * @throws Exception 加解密异常
	 */
	private static byte[] sm4(byte[] input, byte[] key, String sm4mode, byte[] iv, int mode)
			throws Exception {
		IvParameterSpec ivParameterSpec = null;
		if (null != iv) {
			ivParameterSpec = new IvParameterSpec(iv);
		}
		SecretKeySpec sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
		Cipher cipher = Cipher.getInstance(sm4mode, BouncyCastleProvider.PROVIDER_NAME);
		if (null == ivParameterSpec) {
			cipher.init(mode, sm4Key);
		} else {
			cipher.init(mode, sm4Key, ivParameterSpec);
		}
		return cipher.doFinal(input);
	}




}

测试结果:

加密后结果 ==>c590677c45a775b46f9295008fdb440c
解密后结果 ==>{"test:" 1}
key is ==>51d95b1dc43a9faaad0570f81c755fcc