首页 > 编程语言 >java-信息安全(二十)国密算法 SM1,SM2,SM3,SM4

java-信息安全(二十)国密算法 SM1,SM2,SM3,SM4

时间:2023-04-09 12:44:07浏览次数:33  
标签:java String SM4 SM3 算法 new byte public

一、概述

国密即国家密码局认定的国产密码算法。主要有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,String,SM4,SM3,算法,new,byte,public
From: https://www.cnblogs.com/exmyth/p/17300145.html

相关文章

  • java基础-序列化和拷贝
    1.序列化1.1.定义如果我们需要持久化Java对象,或者在⽹络传输Java对象,这些场景都需要⽤到序列化,简单来说序列化就是将数据结构或对象转换成⼆进制字节流的过程,反序列化就是将在序列化过程中所⽣成的⼆进制字节流转换成数据结构或者对象的过程对于Java这种⾯向对象编程语⾔来说,......
  • Java生成PDF几种方式
    ##1、itextPDF直接填充<!--PDF工具类--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency>......
  • java基础-代理
    1.代理简介2.静态代理3.动态代理3.1.jdk使用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理,JDK创建代理对象效率较高,但是执行效率较低使用流程:实现InvocationHandler接口,重写invoke(),使用Proxy.newProxyInstance()产生代理对象,被代理的对象......
  • 剑指offer05(Java)-替换空格(简单)
    题目:请实现一个函数,把字符串s中的每个空格替换成"%20"。 示例1:输入:s="Wearehappy."输出:"We%20are%20happy." 限制:0<=s的长度<=10000来源:力扣(LeetCode)链接:https://leetcode.cn/problems/ti-huan-kong-ge-lcof著作权归领扣网络所有。商业转载请联系官方授权,......
  • java基础-反射
    1.反射定义反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java反射机制动态语言定义:动态语言是指程序在运行时可以改变其结构,新的函数可以引进,已有的......
  • java基础知识合集-io
    1.IO简介2.IO分类2.1.流分类按照流的流向分,可以分为输入流和输出流按照操作单元划分,可以划分为字节流和字符流按照流的角色划分为节点流和处理流JavalO流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在紧密的联系,JavalO流的40多个类都是从如下4个抽......
  • Java标准类
    Java标准类标准类的定义类的代码publicclassPerson{/*标准类:1.所有成员变量都用private修饰2.每个成员变量都有一个getter,setter方法3.一个无参构造方法4.一个全参构造方法这样的标准类也叫JavaBean*/privateStringn......
  • java中操作redis
             ......
  • Java SpringBoot Bean InitializingBean
    Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。Spring初始化bean有两种方式:实现InitializingBean接口,实现afterPropertiesSet方法。(比通过反射......
  • Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了
    如何阻止JavaSpringBootTest单元测试中包括多线程时,没跑完就结束了使用CountDownLatchCountDownLatch、CyclicBarrier使用区别多线程ThreadPoolTaskExecutor应用JavaBasePooledObjectFactory对象池化技术@SpringBootTestpublicclassPoolTest{@Testvoid......