广告位联系
返回顶部
分享到

Java实现国产加密算法SM4的介绍

java 来源:互联网 作者:佚名 发布时间:2023-01-31 20:20:29 人浏览
摘要

国产SM4加密解密算法概念 SMS4算法是在国内广泛使用的WAPI无线网络标准中使用的加密算法,是一种32轮的迭代非平衡Feistel结构的分组加密算法,其密钥长度和分组长度均为128。SMS4算法的

国产SM4加密解密算法概念

SMS4算法是在国内广泛使用的WAPI无线网络标准中使用的加密算法,是一种32轮的迭代非平衡Feistel结构的分组加密算法,其密钥长度和分组长度均为128。SMS4算法的加解密过程中使用的算法是完全相同的,唯一不同点在于该算法的解密密钥是由它的加密密钥进行逆序变换后得到的。

SMS4分组加密算法是中国无线标准中使用的分组加密算法,在2012年已经被国家商用密码管理局确定为国家密码行业标准,标准编号GM/T 0002-2012并且改名为SM4算法,与SM2椭圆曲线公钥密码算法,SM3密码杂凑算法共同作为国家密码的行业标准,在我国密码行业中有着极其重要的位置。

SMS4算法的分组长度为128bit,密钥长度也是128bit。加解密算法均采用32轮非平衡Feistel迭代结构,该结构最先出现在分组密码LOKI的密钥扩展算法中。

SMS4通过32轮非线性迭代后加上一个反序变换,这样只需要解密密钥是加密密钥的逆序,就能使得解密算法与加密算法保持一致。SMS4加解密算法的结构完全相同,只是在使用轮密钥时解密密钥是加密密钥的逆序。

S盒是一种利用非线性变换构造的分组密码的一个组件,主要是为了实现分组密码过程中的混淆的特性和设计的。SMS4算法中的S盒在设计之初完全按照欧美分组密码的设计标准进行,它采用的方法是能够很好抵抗差值攻击的仿射函数逆映射复合法。

1.SM4/ECB/PKCS5Padding

实现代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

import org.bouncycastle.util.encoders.Hex;

  

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.spec.SecretKeySpec;

import java.security.Key;

import java.security.SecureRandom;

import java.security.Security;

import java.util.Arrays;

  

/**

 * Sm4 国密算法

 *

 */

public final class Sm4Utils {

  

    static {

        Security.addProvider(new BouncyCastleProvider());

    }

  

    private static final String ENCODING = "UTF-8";

    public static final String ALGORITHM_NAME = "SM4";

    // 加密算法/分组加密模式/分组填充方式

    // PKCS5Padding-以8个字节为一组进行分组加密

    // 定义分组加密模式使用:PKCS5Padding

    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";

    // 128-32位16进制;256-64位16进制

    public static final int DEFAULT_KEY_SIZE = 128;

  

    /**

     * 自动生成密钥

     *

     * @return

     * @explain

     */

    public static String generateKey() throws Exception {

        return new String(Hex.encode(generateKey(DEFAULT_KEY_SIZE)));

    }

  

    /**

     * @param keySize

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] generateKey(int keySize) throws Exception {

        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);

        kg.init(keySize, new SecureRandom());

        return kg.generateKey().getEncoded();

    }

  

    /**

     * 生成ECB暗号

     *

     * @param algorithmName 算法名称

     * @param mode          模式

     * @param key

     * @return

     * @throws Exception

     * @explain ECB模式(电子密码本模式:Electronic codebook)

     */

    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {

        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);

        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);

        cipher.init(mode, sm4Key);

        return cipher;

    }

  

    /**

     * sm4加密

     *

     * @param hexKey   16进制密钥(忽略大小写)

     * @param paramStr 待加密字符串

     * @return 返回16进制的加密字符串

     * @explain 加密模式:ECB

     * 密文长度不固定,会随着被加密字符串长度的变化而变化

     */

    public static String encryptEcb(String hexKey, String paramStr) {

        try {

            String cipherText = "";

            // 16进制字符串-->byte[]

            byte[] keyData = ByteUtils.fromHexString(hexKey);

            // String-->byte[]

            byte[] srcData = paramStr.getBytes(ENCODING);

            // 加密后的数组

            byte[] cipherArray = encryptEcbPadding(keyData, srcData);

            // byte[]-->hexString

            cipherText = ByteUtils.toHexString(cipherArray);

            return cipherText;

        } catch (Exception e) {

            return paramStr;

        }

    }

  

    /**

     * 加密模式之Ecb

     *

     * @param key

     * @param data

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] encryptEcbPadding(byte[] key, byte[] data) throws Exception {

        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);

        return cipher.doFinal(data);

    }

  

    /**

     * sm4解密

     *

     * @param hexKey     16进制密钥

     * @param cipherText 16进制的加密字符串(忽略大小写)

     * @return 解密后的字符串

     * @throws Exception

     * @explain 解密模式:采用ECB

     */

    public static String decryptEcb(String hexKey, String cipherText) {

        // 用于接收解密后的字符串

        String decryptStr = "";

        // hexString-->byte[]

        byte[] keyData = ByteUtils.fromHexString(hexKey);

        // hexString-->byte[]

        byte[] cipherData = ByteUtils.fromHexString(cipherText);

        // 解密

        byte[] srcData = new byte[0];

        try {

            srcData = decryptEcbPadding(keyData, cipherData);

            // byte[]-->String

            decryptStr = new String(srcData, ENCODING);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return decryptStr;

    }

  

    /**

     * 解密

     *

     * @param key

     * @param cipherText

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] decryptEcbPadding(byte[] key, byte[] cipherText) throws Exception {

        Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);

        return cipher.doFinal(cipherText);

    }

  

    /**

     * 校验加密前后的字符串是否为同一数据

     *

     * @param hexKey     16进制密钥(忽略大小写)

     * @param cipherText 16进制加密后的字符串

     * @param paramStr   加密前的字符串

     * @return 是否为同一数据

     * @throws Exception

     * @explain

     */

    public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {

        // 用于接收校验结果

        boolean flag = false;

        // hexString-->byte[]

        byte[] keyData = ByteUtils.fromHexString(hexKey);

        // 将16进制字符串转换成数组

        byte[] cipherData = ByteUtils.fromHexString(cipherText);

        // 解密

        byte[] decryptData = decryptEcbPadding(keyData, cipherData);

        // 将原字符串转换成byte[]

        byte[] srcData = paramStr.getBytes(ENCODING);

        // 判断2个数组是否一致

        flag = Arrays.equals(decryptData, srcData);

        return flag;

    }

  

    public static void main(String[] args) {

        try {

            String paramStr = "Hello, world";

            System.out.println("==========加密前源数据==========");

            System.out.println(paramStr);

            // 生成32位16进制密钥

            String key = Sm4Utils.generateKey();

            System.out.println("==========生成key==========");

            System.out.println(key);

            String cipher = Sm4Utils.encryptEcb(key, paramStr);

            System.out.println("==========加密串==========");

            System.out.println(cipher);

            System.out.println("==========是否为同一数据==========");

            System.out.println(Sm4Utils.verifyEcb(key, cipher, paramStr));

            paramStr = Sm4Utils.decryptEcb(key, cipher);

            System.out.println("==========解密后数据==========");

            System.out.println(paramStr);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

结果如下:

2.SM4/CBC/PKCS5Padding

示例代码

1

2

3

4

5

<dependency>

   <groupId>org.bouncycastle</groupId>

   <artifactId>bcprov-jdk15to18</artifactId>

   <version>1.68</version>

</dependency>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;

  

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.security.AlgorithmParameters;

import java.security.Key;

import java.security.SecureRandom;

import java.security.Security;

import java.util.Arrays;

  

/**

 * Sm4 国密算法

 *

 */

public final class Sm4Util {

  

    static {

        Security.addProvider(new BouncyCastleProvider());

    }

  

    private static final String ENCODING = "UTF-8";

  

    public static final String ALGORITHM_NAME = "SM4";

    // 加密算法/分组加密模式/分组填充方式

    // PKCS5Padding-以8个字节为一组进行分组加密

    // 定义分组加密模式使用:PKCS5Padding

  

    public static final String ALGORITHM_NAME_CBC_PADDING = "SM4/CBC/PKCS5Padding";

    // 128-32位16进制;256-64位16进制

    public static final int DEFAULT_KEY_SIZE = 128;

  

    /**

     * 自动生成密钥

     *

     * @return

     * @explain

     */

    public static byte[] generateKey() throws Exception {

        return generateKey(DEFAULT_KEY_SIZE);

    }

  

  

    /**

     * 自动生成密钥

     * @return

     * @throws Exception

     */

    public static String generateKeyString() throws Exception {

        return ByteUtils.toHexString(generateKey());

    }

  

    /**

     * @param keySize

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] generateKey(int keySize) throws Exception {

        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);

        kg.init(keySize, new SecureRandom());

        return kg.generateKey().getEncoded();

    }

  

    /**

     * sm4加密

     *

     * @param hexKey   16进制密钥(忽略大小写)

     * @param paramStr 待加密字符串

     * @return 返回16进制的加密字符串

     * @throws Exception

     * @explain 加密模式:CBC

     */

    public static String encrypt(String hexKey, String paramStr) throws Exception {

        String result = "";

        // 16进制字符串-->byte[]

        byte[] keyData = ByteUtils.fromHexString(hexKey);

        // String-->byte[]

        byte[] srcData = paramStr.getBytes(ENCODING);

        // 加密后的数组

        byte[] cipherArray = encryptCbcPadding(keyData, srcData);

  

        // byte[]-->hexString

        result = ByteUtils.toHexString(cipherArray);

        return result;

    }

  

    /**

     * 加密模式之CBC

     *

     * @param key

     * @param data

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] encryptCbcPadding(byte[] key, byte[] data) throws Exception {

        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.ENCRYPT_MODE, key);

        return cipher.doFinal(data);

    }

  

    /**

     * 加密模式之CBC

     * @param algorithmName

     * @param mode

     * @param key

     * @return

     * @throws Exception

     */

    private static Cipher generateCbcCipher(String algorithmName, int mode, byte[] key) throws Exception {

        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);

        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);

        cipher.init(mode, sm4Key, generateIV());

        return cipher;

    }

  

    /**

     * 生成iv

     * @return

     * @throws Exception

     */

    public static AlgorithmParameters generateIV() throws Exception {

        //iv 为一个 16 字节的数组,这里采用和 iOS 端一样的构造方法,数据全为0

        byte[] iv = new byte[16];

        Arrays.fill(iv, (byte) 0x00);

        AlgorithmParameters params = AlgorithmParameters.getInstance(ALGORITHM_NAME);

        params.init(new IvParameterSpec(iv));

        return params;

    }

  

    /**

     * sm4解密

     *

     * @param hexKey 16进制密钥

     * @param text   16进制的加密字符串(忽略大小写)

     * @return 解密后的字符串

     * @throws Exception

     * @explain 解密模式:采用CBC

     */

    public static String decrypt(String hexKey, String text) throws Exception {

        // 用于接收解密后的字符串

        String result = "";

        // hexString-->byte[]

        byte[] keyData = ByteUtils.fromHexString(hexKey);

        // hexString-->byte[]

        byte[] resultData = ByteUtils.fromHexString(text);

        // 解密

        byte[] srcData = decryptCbcPadding(keyData, resultData);

        // byte[]-->String

        result = new String(srcData, ENCODING);

        return result;

    }

  

    /**

     * 解密

     *

     * @param key

     * @param cipherText

     * @return

     * @throws Exception

     * @explain

     */

    public static byte[] decryptCbcPadding(byte[] key, byte[] cipherText) throws Exception {

        Cipher cipher = generateCbcCipher(ALGORITHM_NAME_CBC_PADDING, Cipher.DECRYPT_MODE, key);

        return cipher.doFinal(cipherText);

    }

  

    public static void main(String[] args) throws Exception {

  

        String str = "Hello, world" ;

        System.out.println("==========生成密钥==========");

        String generateKey = generateKeyString();

        System.out.println(generateKey);

        System.out.println("==========加密==========");

        String encrypt = encrypt(generateKey, str);

        System.out.println(encrypt);

        System.out.println("==========解密==========");

        String decrypt = decrypt(generateKey, encrypt);

        System.out.println(decrypt);

    }

}

结果如下


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/trustProcess/article/details/127865787
相关文章
  • Java实现解析.xlsb文件的教程

    Java实现解析.xlsb文件的教程
    Java解析.Xlsb文件 pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 dependency groupIdorg.apache.poi/groupId artifactIdpoi/artifactId version3.17/version /dependency dependency groupI
  • Java实现国产加密算法SM4的介绍

    Java实现国产加密算法SM4的介绍
    国产SM4加密解密算法概念 SMS4算法是在国内广泛使用的WAPI无线网络标准中使用的加密算法,是一种32轮的迭代非平衡Feistel结构的分组加密算
  • java多线程实现同步锁卖票实战项目

    java多线程实现同步锁卖票实战项目
    同步概念与方法: 窗口类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Ticket implements Runnable{ int tickets=20;//总共20张票 @Override public
  • Elasticsearch percolate 查询示例介绍
    我们将文档索引到 Elasticsearch 中并对其运行查询以获得满足提供的搜索条件的文档。 我们构造一个匹配或术语查询作为输入,匹配查询的文
  • Java类的构造方法介绍

    Java类的构造方法介绍
    Java语言中,类的构造方法是一种很特殊的方法。关于构造方法要记忆和理解的知识点其实挺多的,下面我们就来详细的讲讲构造方法,相信
  • 基于EasyExcel实现百万级数据导入导出

    基于EasyExcel实现百万级数据导入导出
    在项目开发中往往需要使用到数据的导入和导出,导入就是从Excel中导入到DB中,而导出就是从DB中查询数据然后使用POI写到Excel上。 大数据的
  • Java使用Zxing二维码生成的代码
    1、二维码简介 二维条形码是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的,在代码编
  • Java经典面试题最全汇总208道(六)

    Java经典面试题最全汇总208道(六)
    短时间提升自己最快的手段就是背面试题,最近总结了Java常用的面试题,分享给大家,希望大家都能圆梦大厂,加油,我命由我不由天。
  • Spring中Bean注入源码介绍

    Spring中Bean注入源码介绍
    BeanDefinition和Bean 在Spring中Bean的注入涉及两部分: BeanDefinition Bean 两个对象存在先后顺序,先注入BeanDefinition之后才执行Bean对象的注入。 那
  • Java流程控制语句最全汇总(上篇)

    Java流程控制语句最全汇总(上篇)
    本章是关于Java流程控制语句的最全汇总,本篇为汇总上篇。 流程是人们生活中不可或缺的一部分,它表示人们每天都在按照一定的流程做事
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计