一、概述

国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。目前主要使用公开的SM2、SM3、SM4三类算法,分别是非对称算法、哈希算法和对称算法。

SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。不讨论

SM2 为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。

  SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,包括SM2-1椭圆曲线数字签名算法,SM2-2椭圆曲线密钥交换协议,SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。

SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。

  SM3杂凑算法是我国自主设计的密码杂凑算法,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。为了保证杂凑算法的安全性,其产生的杂凑值的长度不应太短,例如MD5输出128比特杂凑值,输出长度太短,影响其安全性SHA-1算法的输出长度为160比特,SM3算法的输出长度为256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。

SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

  SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。

由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。

代码地址:https://github.com/bjlhx15/algorithm-sign.git

工具类

package com.github.bjlhx15.security.sm;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64; /**
* @author lihongxu6
* @version 1.0
* @className KeyUtils
* @description TODO
* @date 2021-01-13 23:27
*/
public class KeyUtils {
/**
* 生成国密公私钥对
* <p>
* <code>String[0]</code> 公钥
* <p>
* <code>String[1]</code> 私钥
*
* @return
* @throws Exception
*/
public static String[] generateSmKey() throws Exception {
KeyPairGenerator keyPairGenerator = null;
SecureRandom secureRandom = new SecureRandom();
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
keyPairGenerator.initialize(sm2Spec);
keyPairGenerator.initialize(sm2Spec, secureRandom);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String[] result = {
new String(Base64.getEncoder().encode(publicKey.getEncoded()))
, new String(Base64.getEncoder().encode(privateKey.getEncoded()))
};
return result;
}
/**
* 将Base64转码的公钥串,转化为公钥对象
*
* @param publicKey
* @return
*/
public static PublicKey createPublicKey(String publicKey) {
PublicKey publickey = null;
try{
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
publickey = keyFactory.generatePublic(publicKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return publickey;
} /**
* 将Base64转码的私钥串,转化为私钥对象
*
* @param privateKey
* @return
*/
public static PrivateKey createPrivateKey(String privateKey) {
PrivateKey publickey = null;
try{
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return publickey;
}
}

1.1、SM2

代码:

public class BcSm2Util {
static {
Security.addProvider(new BouncyCastleProvider());
} /**
* 根据publicKey对原始数据data,使用SM2加密
*/
public static byte[] encrypt(byte[] data, PublicKey publicKey) {
ECPublicKeyParameters localECPublicKeyParameters = null; if (publicKey instanceof BCECPublicKey) {
BCECPublicKey localECPublicKey = (BCECPublicKey) publicKey;
ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
localECParameterSpec.getG(), localECParameterSpec.getN());
localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), localECDomainParameters);
}
SM2Engine localSM2Engine = new SM2Engine();
localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters, new SecureRandom()));
byte[] arrayOfByte2;
try {
arrayOfByte2 = localSM2Engine.processBlock(data, 0, data.length);
return arrayOfByte2;
} catch (InvalidCipherTextException e) { e.printStackTrace();
return null;
}
} /**
* 根据privateKey对加密数据encodedata,使用SM2解密
*/
public static byte[] decrypt(byte[] encodedata, PrivateKey privateKey) {
SM2Engine localSM2Engine = new SM2Engine();
BCECPrivateKey sm2PriK = (BCECPrivateKey) privateKey;
ECParameterSpec localECParameterSpec = sm2PriK.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
localECParameterSpec.getG(), localECParameterSpec.getN());
ECPrivateKeyParameters localECPrivateKeyParameters = new ECPrivateKeyParameters(sm2PriK.getD(),
localECDomainParameters);
localSM2Engine.init(false, localECPrivateKeyParameters);
try {
byte[] arrayOfByte3 = localSM2Engine.processBlock(encodedata, 0, encodedata.length);
return arrayOfByte3;
} catch (InvalidCipherTextException e) {
e.printStackTrace();
return null;
}
} /**
* 私钥签名
*/
public static byte[] signByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {
Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(privateKey);
sig.update(data);
byte[] ret = sig.sign();
return ret;
} /**
* 公钥验签
*/
public static boolean verifyByPublicKey(byte[] data, PublicKey publicKey, byte[] signature) throws Exception {
Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
sig.initVerify(publicKey);
sig.update(data);
boolean ret = sig.verify(signature);
return ret;
}
}

测试

public class BcSm2UtilTest {
private String test = "woshi测试数据。。.."; java.security.PublicKey publicKey = null;
java.security.PrivateKey privateKey = null; @Before
public void setup() throws Exception {//生成公私钥对
String[] keys = KeyUtils.generateSmKey(); System.out.println("原始数据:" + test);
System.out.println("公钥:" + new String(keys[0]));
System.out.println();
publicKey = KeyUtils.createPublicKey(keys[0]); System.out.println("私钥:" + new String(keys[1]));
System.out.println();
privateKey = KeyUtils.createPrivateKey(keys[1]);
} @Test
public void encrypt() throws Exception {
byte[] encrypt = BcSm2Util.encrypt(test.getBytes(), publicKey);
String encryptBase64Str = Base64.getEncoder().encodeToString(encrypt);
System.out.println("加密数据:" + encryptBase64Str); byte[] decrypt = BcSm2Util.decrypt(encrypt, privateKey); System.out.println("解密数据:"+new String(decrypt)); byte[] sign = BcSm2Util.signByPrivateKey(test.getBytes(), privateKey);
System.out.println("数据签名:"+ Base64.getEncoder().encodeToString(sign)); boolean b = BcSm2Util.verifyByPublicKey(test.getBytes(), publicKey,sign);
System.out.println("数据验签:"+ b);
}
}

1.2、SM3 hash及hmac

public class BcSm3Util {
static {
Security.addProvider(new BouncyCastleProvider());
} public static byte[] sm3(byte[] srcData) {
SM3Digest sm3Digest = new SM3Digest();
sm3Digest.update(srcData, 0, srcData.length);
byte[] hash = new byte[sm3Digest.getDigestSize()];
sm3Digest.doFinal(hash, 0);
return hash;
} public static String sm3Hex(byte[] srcData) {
byte[] hash = sm3(srcData);
String hexString = org.apache.commons.codec.binary.Hex.encodeHexString(hash);
return hexString;
} public static byte[] hmacSm3(byte[] key, byte[] srcData) {
KeyParameter keyParameter = new KeyParameter(key);
SM3Digest digest = new SM3Digest();
HMac mac = new HMac(digest);
mac.init(keyParameter);
mac.update(srcData, 0, srcData.length);
byte[] hash = new byte[mac.getMacSize()];
mac.doFinal(hash, 0);
return hash;
} public static String hmacSm3Hex(byte[] key, byte[] srcData) {
byte[] hash = hmacSm3(key, srcData);
String hexString = org.apache.commons.codec.binary.Hex.encodeHexString(hash);
return hexString;
} public static byte[] sm3bc(byte[] srcData) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
byte[] digest = messageDigest.digest(srcData);
return digest;
} public static String sm3bcHex(byte[] srcData) throws Exception {
byte[] hash = sm3bc(srcData);
String hexString = org.apache.commons.codec.binary.Hex.encodeHexString(hash);
return hexString;
}
}

测试

public class BcSm3UtilTest {
private String test="woshi测试数据。。.."; @Test
public void sm3() throws Exception {
String s = BcSm3Util.sm3Hex(test.getBytes());
System.out.println(s);
String s2 = BcSm3Util.sm3bcHex(test.getBytes());
System.out.println(s2);
Assert.assertEquals(s,s2);
} @Test
public void hmacSm3Hex() {
String s = BcSm3Util.hmacSm3Hex("AAAA".getBytes(),test.getBytes());
System.out.println(s);
}
}

1.4、SM4

public class BcSm4Util {
static {
Security.addProvider(new BouncyCastleProvider());
} public static final String ALGORITHM_NAME = "SM4";
public static final String DEFAULT_KEY = "random_seed";
// 128-32位16进制;256-64位16进制
public static final int DEFAULT_KEY_SIZE = 128; static {
Security.addProvider(new BouncyCastleProvider());
} public static byte[] generateKey() throws NoSuchAlgorithmException, NoSuchProviderException {
return generateKey(DEFAULT_KEY, DEFAULT_KEY_SIZE);
} public static byte[] generateKey(String seed) throws NoSuchAlgorithmException, NoSuchProviderException {
return generateKey(seed, DEFAULT_KEY_SIZE);
} public static byte[] generateKey(String seed, int keySize) throws NoSuchAlgorithmException, NoSuchProviderException {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
if (null != seed && !"".equals(seed)) {
random.setSeed(seed.getBytes());
}
kg.init(keySize, random);
return kg.generateKey().getEncoded();
} /**
* @description 加密
*/
public static byte[] encrypt(String algorithmName, byte[] key, byte[] iv, byte[] data) throws Exception {
return sm4core(algorithmName,Cipher.ENCRYPT_MODE, key, iv, data);
} /**
* @description 解密
*/
public static byte[] decrypt(String algorithmName, byte[] key, byte[] iv, byte[] data) throws Exception {
return sm4core(algorithmName, Cipher.DECRYPT_MODE, key, iv, data);
} private static byte[] sm4core(String algorithmName, int type, byte[] key, byte[] iv, byte[] data) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
if (algorithmName.contains("/ECB/")) {
cipher.init(type, sm4Key);
} else {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(type, sm4Key, ivParameterSpec);
} return cipher.doFinal(data);
}
}

测试

public class BcSm4UtilTest {
byte[] key = BcSm4Util.generateKey();
byte[] iv = null; String text = "我是加密数据,请测试。。8888"; public BcSm4UtilTest() throws NoSuchProviderException, NoSuchAlgorithmException {
} @Test
public void bcSm4UtilTest() throws Exception {
List<String> algorithm = new ArrayList<>();
algorithm.add(("SM4/ECB/NOPADDING"));
algorithm.add(("SM4/ECB/PKCS5PADDING"));
algorithm.add(("SM4/ECB/ISO10126PADDING"));
algorithm.add(("SM4/CBC/NOPADDING"));
algorithm.add(("SM4/CBC/PKCS5PADDING"));
algorithm.add(("SM4/CBC/ISO10126PADDING"));
algorithm.add(("SM4/PCBC/NOPADDING"));
algorithm.add(("SM4/PCBC/PKCS5PADDING"));
algorithm.add(("SM4/PCBC/ISO10126PADDING"));
algorithm.add(("SM4/CTR/NOPADDING"));
algorithm.add(("SM4/CTR/PKCS5PADDING"));
algorithm.add(("SM4/CTR/ISO10126PADDING"));
algorithm.add(("SM4/CTS/NOPADDING"));
algorithm.add(("SM4/CTS/PKCS5PADDING"));
algorithm.add(("SM4/CTS/ISO10126PADDING"));
if (iv == null)
iv = AbstractSymmetric.initIv(16); for (String s : algorithm) {
//SM4加密
try {
System.out.println("SM4加密算法: " + s);
System.out.println("SM4加密原始数据: " + text);
System.out.println("SM4加密key: " + Base64.getEncoder().encodeToString(key));
System.out.println("SM4加密iv: " + Base64.getEncoder().encodeToString(iv)); byte[] encrypt = BcSm4Util.encrypt(s, key, iv, text.getBytes());
System.out.println("SM4加密数据密文: " + Base64.getEncoder().encodeToString(encrypt)); //SM4解密
byte[] decrypt = BcSm4Util.decrypt(s, key, iv, encrypt);
System.out.println("SM4解密数据: " + new String(decrypt));
} catch (Exception e) {
if (e instanceof IllegalBlockSizeException) {
System.err.println("SM4解密数据:算法 " + s + "数据需自己手工对齐");
} else {
System.err.println("SM4解密数据:算法 " + s +"::"+ e.getMessage());
}
} finally {
System.err.println("---------------------------------------");
TimeUnit.SECONDS.sleep(1);
}
}
}
}

水电费

java-信息安全(二十)国密算法 SM1,SM2,SM3,SM4的更多相关文章

  1. 关于国密算法 SM1,SM2,SM3,SM4 的笔记

    国密即国家密码局认定的国产密码算法.主要有SM1,SM2,SM3,SM4.密钥长度和分组长度均为128位. SM1 为对称加密.其加密强度与AES相当.该算法不公开,调用该算法时,需要通过加密芯片的接 ...

  2. crypto-gmsm国密算法库

    crypto-gmsm国密算法库 一.开发背景 crypto-gmsm国密算法库是国密商密算法(SM2,SM3,SM4)工具类封装,国产密码算法(国密算法)是指国家密码局认定的国产商用密码算法,目前主 ...

  3. SM 国密算法踩坑指南

    各位,好久不见~ 最近接手网联的国密改造项目,由于对国密算法比较陌生,前期碰到了一系列国密算法加解密的问题. 所以这次总结一下,分享这个过程遇到的问题,希望帮到大家. 国密 什么是国密算法? 国密就是 ...

  4. java sm4国密算法加密、解密

      java sm4国密算法加密.解密 CreationTime--2018年7月5日09点20分 Author:Marydon 1.准备工作 所需jar包: bcprov-jdk15on-1.59. ...

  5. 20155206赵飞 基于《Arm试验箱的国密算法应用》课程设计个人报告

    20155206赵飞 基于<Arm试验箱的国密算法应用>课程设计个人报告 课程设计中承担的任务 完成试验箱测试功能1,2,3 . 1:LED闪烁实验 一.实验目的  学习GPIO原理  ...

  6. 国产芯片任重道远 国科微SSD主控芯片的“追赶之路”(不能只提供一颗芯片,而是要将芯片、国密算法、固件Firmware、BIOS和操作系统紧密联系在一起,变成完整解决方案交给行业用户,才能真正体现自身的价值)

    集微网消息,“中国芯”战略之路道阻且长,踏入这个赛道的攻坚者们需要十年如一日的技术突破,需要集合产业势能,共同协作,方能建立中国核心技术真正的竞争力. 国产化之路任重道远,SSD芯片初见成效 信息时代 ...

  7. 国密算法SM2证书制作

    国密算法sm2非对称算法椭圆曲线 原文:http://www.jonllen.cn/jonllen/work/162.aspx 前段时间将系统的RSA算法全部升级为SM2国密算法,密码机和UKey硬件 ...

  8. Hyperledger Fabric密码模块系列之BCCSP(五) - 国密算法实现

    Talk is cheap, show me your code. 代码也看了,蛋也扯了,之后总该做点什么.响应国家政策,把我们的国密算法融合进去吧--  先附两张bccsp下国密算法的设计实现图. ...

  9. 《基于Arm实验箱的国密算法应用》课程设计 结题报告

    <基于Arm实验箱的国密算法应用>课程设计 结题报告 小组成员姓名:20155206赵飞 20155220吴思其 20155234昝昕明 指导教师:娄嘉鹏 设计方案 题目要求:基于Arm实 ...

  10. 20155234 昝昕明《基于ARM实验箱的国密算法应用》课程设计个人报告

    20155234 昝昕明<基于ARM实验箱的国密算法应用>课程设计个人报告 个人贡献 参与课设题目讨论及完成全过程: 资料收集: SM1算法及和ARM之间通信 负责串口代码调试: 协调完成 ...

随机推荐

  1. module_softdep

    所谓的MODULE_SOFTDEP,就是两个两个模块之间本有依赖,但是一定要要加载顺序的要求. 用法很简单. #define MODULE_SOFTDEP(_softdep) MODULE_INFO( ...

  2. 关于Android Q平台上qssi的介绍

    QSSI 是 Qualcomm Single System Image 的缩写. Android Q上开始支持QSSI. QSSI 是用来编译system.img的3.1 QSSI编译注意事项 lun ...

  3. Blinn-Phong

    为什么出现Blinn-Phong 虽然Phong性能较高,但是在某些镜面反射条件下就会失效.比如下图,我们明显发现了一条明显的亮暗边界线,这在实际场景中是不应该发生的(实际场景中不会出现这种明显的过渡 ...

  4. Java日期时间API系列40-----中文语句中的时间语义识别(time NLP)代码实现分析

    从上篇 Java日期时间API系列39-----中文语句中的时间语义识别(time NLP 输入一句话,能识别出话里的时间)原理分析 中得知解析的主要步骤分为三步: (1)加载正则文件 (2)解析中文 ...

  5. 墨天轮国产数据库沙龙 | 许力:阿里云原生Lindorm TSDB数据库,驱动工业IT&OT超融合数字化系统升级

    分享嘉宾:许力 阿里云Lindorm 数据库产品经理 整理:墨天轮 导读 大家好,我是阿里云Lindorm 数据库产品经理许力,今天非常有荣幸给大家介绍阿里云 Lindorm 数据库面向工业场景的最佳 ...

  6. C# 的运算符和作用域

    // C# 运算符 // 表达式 表达式有操作数(operand)和运算符(operator)构成: // 常见的运算符 + - * / 和 new // x ?? y 如果x为null, 则计算机过 ...

  7. Android复习(三)清单文件中的元素——>application

    <application> 语法: <application android:allowTaskReparenting=["true" | "false ...

  8. 王树森Attention与Self-Attention学习笔记

    目录 Seq2Seq + Attention Attention的原理 方法一(Used in the original paper) 方法二(more popular,the same to Tra ...

  9. 基于Java+SpringBoot+Mysql实现的快递柜寄取快递系统功能实现一

    一.前言介绍: 1.1 项目摘要 随着电子商务的迅猛发展和城市化进程的加快,快递业务量呈现出爆炸式增长的趋势.传统的快递寄取方式,如人工配送和定点领取,已经无法满足现代社会的快速.便捷需求.这些问题不 ...

  10. 基于 Github 平台的 .NET 开源项目模板 - 项目及半自动脚本

    接上一篇模板的介绍文章, 我们接下来看看如何配置和使用这款模板. 项目配置 1. fork 咱这款模板. 2. 并将其设置为模板. 3. 在创建新仓库时使用这个模板. 4. 看使用说明,了解项目结构 ...