【Java】国密SM4分组密码算法(对称加密)的JS和JAVA类库

国密SM4分组密码算法(对称加密)的JS和JAVA类库

bluesbruce发布于 今天 02:51

前言

SM4分组密码算法,是由国家密码局发布的国产商用密码算法。该算法的分组长度为128 bit,密钥长度为128 bit。具体算法描述可以查阅GB/T 32907-2016 《信息安全技术 SM4分组密码算法》
本文SM4的java实现方法,在BC库(bouncycastle)的基础上做了简单的封装,JS方法在sm-crypto的基础上做的封装。

JAVA

加解密方法

<!-- 轻量级加密API -->

<dependency>

<groupId>org.bouncycastle</groupId>

<artifactId>bcprov-jdk15on</artifactId>

<version>1.68</version>

</dependency>

import java.security.SecureRandom;

import java.security.Security;

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**

* 国密SM4分组密码算法工具类(对称加密)

* <p>GB/T 32907-2016 信息安全技术 SM4分组密码算法</p>

*

* @author BBF

* @see <a href="http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A">GB/T

* 32907-2016</a>

*/

public class Sm4Util {

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());

}

}

private Sm4Util() {

}

/**

* 生成密钥

* <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();

}

/**

* 加密,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);

}

}

测试用例

import java.nio.charset.StandardCharsets;

import org.bouncycastle.util.encoders.Hex;

import org.junit.Assert;

import org.junit.Test;

public class Sm4UtilTest {

@Test

public void ecbPkcs5Padding() throws Exception {

String txt = "sm4对称加密<pkcs5>演示←←";

String key = "FA171555405706F73D7B973DB89F0B47";

byte[] output = Sm4Util.encryptEcbPkcs5Padding(txt.getBytes(StandardCharsets.UTF_8), key);

String hex = Hex.toHexString(output);

LOGGER.info("SM4-ECB-PKCS5Padding,加密输出HEX = {}", hex);

// 解密

byte[] input = Hex.decode(hex);

output = Sm4Util.decryptEcbPkcs5Padding(input, key);

String s = new String(output, StandardCharsets.UTF_8);

LOGGER.info("SM4-ECB-PKCS5Padding,解密输出 = {}", s);

LOGGER.info("SM4-ECB-PKCS5Padding,key = {}", Hex.toHexString(key));

Assert.assertEquals(txt, s);

}

}

JS

加解密方法

  /**

* SM4-ECB-PKCS5Padding对称加密

* @param text {string} 要加密的明文

* @param secretKey {string} 密钥,43位随机大小写与数字

* @returns {string} 加密后的密文,Base64格式

*/

function SM4_ECB_ENCRYPT(text, secretKey) {

return sm4.encrypt(text, secretKey).toUpperCase();

}

/**

* SM4-ECB-PKCS5Padding对称解密

* @param textBase64 {string} 要解密的密文,Base64格式

* @param secretKey {string} 密钥,43位随机大小写与数字

* @returns {string} 解密后的明文

*/

function SM4_ECB_DECRYPT(textBase64, secretKey) {

return sm4.decrypt(textBase64, secretKey);

}

测试用例

  var message = "sm4对称加密<pkcs5>演示←←";

var key = "FA171555405706F73D7B973DB89F0B47";

var ecbEncrypt = SM4_ECB_ENCRYPT(message, key);

console.log("ecb加密", ecbEncrypt);

var ecbDecrypt = SM4_ECB_DECRYPT(ecbEncrypt, key);

console.log("ecb结果比较---", message === ecbDecrypt)

附录

  • GB/T 32907-2016 http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A

  • sm-crypto https://github.com/JuneAndGreen/sm-crypto

  • sm4.js https://github.com/JuneAndGreen/sm-crypto/blob/master/dist/sm4.js

java加密算法" title="对称加密算法">对称加密算法

阅读 31更新于 50 分钟前

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议

avatar

bluesbruce

161 声望

10 粉丝

0 条评论

得票时间

avatar

bluesbruce

161 声望

10 粉丝

宣传栏

前言

SM4分组密码算法,是由国家密码局发布的国产商用密码算法。该算法的分组长度为128 bit,密钥长度为128 bit。具体算法描述可以查阅GB/T 32907-2016 《信息安全技术 SM4分组密码算法》
本文SM4的java实现方法,在BC库(bouncycastle)的基础上做了简单的封装,JS方法在sm-crypto的基础上做的封装。

JAVA

加解密方法

<!-- 轻量级加密API -->

<dependency>

<groupId>org.bouncycastle</groupId>

<artifactId>bcprov-jdk15on</artifactId>

<version>1.68</version>

</dependency>

import java.security.SecureRandom;

import java.security.Security;

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**

* 国密SM4分组密码算法工具类(对称加密)

* <p>GB/T 32907-2016 信息安全技术 SM4分组密码算法</p>

*

* @author BBF

* @see <a href="http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A">GB/T

* 32907-2016</a>

*/

public class Sm4Util {

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());

}

}

private Sm4Util() {

}

/**

* 生成密钥

* <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();

}

/**

* 加密,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);

}

}

测试用例

import java.nio.charset.StandardCharsets;

import org.bouncycastle.util.encoders.Hex;

import org.junit.Assert;

import org.junit.Test;

public class Sm4UtilTest {

@Test

public void ecbPkcs5Padding() throws Exception {

String txt = "sm4对称加密<pkcs5>演示←←";

String key = "FA171555405706F73D7B973DB89F0B47";

byte[] output = Sm4Util.encryptEcbPkcs5Padding(txt.getBytes(StandardCharsets.UTF_8), key);

String hex = Hex.toHexString(output);

LOGGER.info("SM4-ECB-PKCS5Padding,加密输出HEX = {}", hex);

// 解密

byte[] input = Hex.decode(hex);

output = Sm4Util.decryptEcbPkcs5Padding(input, key);

String s = new String(output, StandardCharsets.UTF_8);

LOGGER.info("SM4-ECB-PKCS5Padding,解密输出 = {}", s);

LOGGER.info("SM4-ECB-PKCS5Padding,key = {}", Hex.toHexString(key));

Assert.assertEquals(txt, s);

}

}

JS

加解密方法

  /**

* SM4-ECB-PKCS5Padding对称加密

* @param text {string} 要加密的明文

* @param secretKey {string} 密钥,43位随机大小写与数字

* @returns {string} 加密后的密文,Base64格式

*/

function SM4_ECB_ENCRYPT(text, secretKey) {

return sm4.encrypt(text, secretKey).toUpperCase();

}

/**

* SM4-ECB-PKCS5Padding对称解密

* @param textBase64 {string} 要解密的密文,Base64格式

* @param secretKey {string} 密钥,43位随机大小写与数字

* @returns {string} 解密后的明文

*/

function SM4_ECB_DECRYPT(textBase64, secretKey) {

return sm4.decrypt(textBase64, secretKey);

}

测试用例

  var message = "sm4对称加密<pkcs5>演示←←";

var key = "FA171555405706F73D7B973DB89F0B47";

var ecbEncrypt = SM4_ECB_ENCRYPT(message, key);

console.log("ecb加密", ecbEncrypt);

var ecbDecrypt = SM4_ECB_DECRYPT(ecbEncrypt, key);

console.log("ecb结果比较---", message === ecbDecrypt)

附录

  • GB/T 32907-2016 http://www.gb688.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A

  • sm-crypto https://github.com/JuneAndGreen/sm-crypto

  • sm4.js https://github.com/JuneAndGreen/sm-crypto/blob/master/dist/sm4.js

以上是 【Java】国密SM4分组密码算法(对称加密)的JS和JAVA类库 的全部内容, 来源链接: www.h5w3.com/114059.html

回到顶部