当前位置:   article > 正文

java集成国密SM4_sm4 java

sm4 java

1 加密信息介绍

在项目中有接触到使用国密SM4进行数据加密,因此整理一份java实现国密SM4的文档;

关于SM4是对称加密算法,因此只需要一个密钥即可;根据不同的工作模式,需要提供额外的参数;SM4加密存在的工作模式有:

  • ECB(Electronic Codebook):最基础的加密模式,每个数据块独立加密,相同明文块加密后得到相同的密文块。这种模式不提供数据之间的 diffusion(扩散),安全性相对较低,容易受到模式识别攻击。
  • CBC(Cipher Block Chaining):每个数据块在加密前会与前一个加密块的密文进行XOR运算,增加了数据块间的依赖性,提高了安全性。需要一个随机的初始化向量(IV)以保证每次加密的唯一性。
  • CFB(Cipher Feedback):每个数据块在加密前会与前一个加密块的密文进行XOR运算,增加了数据块间的依赖性,提高了安全性。需要一个随机的初始化向量(IV)以保证每次加密的唯一性。
  • OFB(Output Feedback):将加密块的输出(而非密文)与明文进行XOR,生成密文。同样使用IV,并且加密操作与数据流解耦,可以并行处理。
  • CTR(Counter):使用一个计数器(通常是初始向量加上一个递增的计数器值)与密钥加密,得到的输出与明文异或产生密文。此模式支持并行计算,安全性高且效率好。
  • GCM(Galois/Counter Mode):结合了CTR模式的高效性和认证加密(AEAD,Authenticated Encryption with Associated Data),提供了数据的机密性、完整性校验和认证。需要一个128位的nonce(随机数)和可选的附加数据。
  • CCM(Counter with CBC-MAC):同样是AEAD模式,结合了CTR模式加密和CBC-MAC消息认证码,适用于资源有限的环境。

综上所述,选择安全系数较高的的工作模式:GCM工作模式

2 代码示例

2.1 使用注意事项

  • 使用方法,请查看类中的main方法

2.2 代码实现

  • 使用国密SM4需要依赖三方的包bouncycastle-bcprov-jdk15on,以maven项目为示例,
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 下面的具体的实现代码
package com.panape.sm3demo.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

public class SM4Util {
    /**
     * 加密秘钥,长度必须为16位
     */
    private static final String KEY = "1234567890abcdef";
    /**
     * 初始化向量
     */
    private static final String IV = "qwertyuiopas2356";
    /**
     * 加密算法
     */
    public static final String ALGORITHM = "SM4";
    /**
     * 加密工作模式:GCM
     * 数据填充模式:PKCS5Padding
     */
    public static final String ALGORITHM_MODEL_GCM_PADDING = "SM4/GCM/NoPadding";
    /**
     * 随机数的长度
     */
    public static final int NONCE_LENGTH = 128;

    static {
        // 添加Bouncy Castle provider
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 使用传输的密钥和初始化向量进行加密
     *
     * @param plainText 需要加密的内容
     * @return 加密之后的内容
     * @throws Exception 加密过程中可能发生的异常
     */
    public static String encryptWithGCM(String plainText, String key, String iv) throws Exception {
        return encryptWithGCM(plainText, key.getBytes(), iv.getBytes());
    }

    /**
     * 使用传输的密钥和初始化向量进行加密
     *
     * @param plainText 需要加密的内容
     * @param key       密钥
     * @param iv        初始化向量
     * @return 加密之后的内容
     * @throws Exception 加密过程中可能发生的异常
     */
    public static String decryptWithGCM(String plainText, String key, String iv) throws Exception {
        return decryptWithGCM(plainText, key.getBytes(), iv.getBytes());
    }

    /**
     * 使用配置的密钥和初始化向量进行加密
     *
     * @param plainText 需要加密的内容
     * @return 加密之后的内容
     * @throws Exception 加密过程中可能发生的异常
     */
    public static String encryptWithGCM(String plainText) throws Exception {
        return encryptWithGCM(plainText, KEY.getBytes(), IV.getBytes());
    }

    /**
     * 使用配置的密钥和初始化向量进行解密
     *
     * @param cipherText 需要解密的内容
     * @return 解密之后的内容
     * @throws Exception 解密过程中可能发生的异常
     */
    public static String decryptWithGCM(String cipherText) throws Exception {
        return decryptWithGCM(cipherText, KEY.getBytes(), IV.getBytes());
    }

    /**
     * 使用SM4-GCM模式加密
     *
     * @param plainText 需要加密的内容
     * @param keyBytes  密钥字节数组
     * @param ivBytes   初始化向量字节数组
     * @return 加密之后的内容
     * @throws Exception 加密过程中可能发生的异常
     */
    public static String encryptWithGCM(String plainText, byte[] keyBytes, byte[] ivBytes) throws Exception {
        SecretKeySpec sm4Key = new SecretKeySpec(keyBytes, ALGORITHM);
        GCMParameterSpec ivSpec = new GCMParameterSpec(NONCE_LENGTH, ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL_GCM_PADDING, "BC");
        cipher.init(Cipher.ENCRYPT_MODE, sm4Key, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 使用SM4-GCM模式解密
     *
     * @param cipherText 需要解密的内容
     * @param keyBytes   密钥字节数组
     * @param ivBytes    初始化向量字节数据
     * @return 解密之后内容
     * @throws Exception 解密过程中可能发生的异常
     */
    public static String decryptWithGCM(String cipherText, byte[] keyBytes, byte[] ivBytes) throws Exception {
        SecretKeySpec sm4Key = new SecretKeySpec(keyBytes, ALGORITHM);
        GCMParameterSpec ivSpec = new GCMParameterSpec(NONCE_LENGTH, ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL_GCM_PADDING, "BC");
        cipher.init(Cipher.DECRYPT_MODE, sm4Key, ivSpec);
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText));
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 使用SecureRandom生成指定长度的密钥或IV
     *
     * @param length 密钥或IV的长度(字节数)
     * @return 生成的随机字节数组
     */
    public static byte[] generateKey(int length) {
        SecureRandom secureRandom = new SecureRandom();
        byte[] bytes = new byte[length];
        secureRandom.nextBytes(bytes);
        return bytes;
    }

    /**
     * 生成指定长度的初始化向量(IV)
     *
     * @param length IV的长度(字节数)
     * @return 生成的随机字节数组
     */
    public static byte[] generateIV(int length) {
        // IV的生成方式与密钥相同,使用SecureRandom
        return generateKey(length);
    }

    public static void main(String[] args) throws Exception {
        System.out.println("使用配置的密钥和初始化向量");
        String plainText = "1234567";
        String cipherText = encryptWithGCM(plainText);
        System.out.println("加密后:" + cipherText);

        String decryptedText = decryptWithGCM(cipherText);
        System.out.println("解密后:" + decryptedText);

        System.out.println();
        System.out.println("使用代码随机生成的密钥和初始化向量");
        // 使用随机的
        byte[] key = generateKey(16);
        byte[] iv = generateIV(16);
        String cipherText1 = encryptWithGCM(plainText, key, iv);
        System.out.println("加密后:" + cipherText1);

        String decryptedText1 = decryptWithGCM(cipherText1, key, iv);
        System.out.println("解密后:" + decryptedText1);

        System.out.println();
        System.out.println("使用外部传输的密钥和初始化向量");
        String cipherText2 = encryptWithGCM(plainText, KEY, IV);
        System.out.println("加密后:" + cipherText2);

        String decryptedText2 = decryptWithGCM(cipherText2, KEY, IV);
        System.out.println("解密后:" + decryptedText2);
    }
}
  • 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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/809939
推荐阅读
相关标签
  

闽ICP备14008679号