AES GCM算法实现

当前业界敏感信息加密使用AES较多,GCM模式兼具效率和安全性,故选择使用该模式。

注意

我们经常使用256位秘钥,因为美国的安全管控,jdk8的较老版本安全策略不支持256位秘钥,需替换jdk\jre\lib\security 下的安全策略文件local_policy.jar 和US_export_policy.jar

java 1.8.0_151到1.8.0_161版本已经包含了不同的安全策略,需要修改jdk\jre\lib\security\java.security 文件,放开crypto.policy=unlimited的限制即可,这个配置决定选择policy目录下的unlimited或limited的策略文件;

 java 1.8.0_162版本后默认crypto.policy=unlimited 则不需修改。 

代码实现

package com.kwin.demo.api.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

/**
 * @author kwin
 * @Date 2022/7/13 16:20
 **/
public class AESUtil {
    private static final String KEY_ALGORITHM = "AES";
    private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
    private static final int TAG_LENGTH_BIT = 128;
    private static final int IV_LENGTH_BYTE = 12;
    private static final int SALT_LENGTH_BYTE = 16;
    private static final int AES_KEY_BIT = 256;

    /**
     * 安全随机数生成
     * @param numBytes
     * @return
     */
    public static byte[] getRandomNonce(int numBytes) {
        byte[] nonce = new byte[numBytes];
        new SecureRandom().nextBytes(nonce);
        return nonce;
    }

    /**
     * 生成盐值
     * @return
     */
    public static String generateSalt() {
        byte[] salt = getRandomNonce(SALT_LENGTH_BYTE);
        return Base64.encodeBase64String(salt);
    }

    /**
     * 生成初始向量
     * @return
     */
    public static String generateIv() {
        byte[] iv = getRandomNonce(IV_LENGTH_BYTE);
        return Base64.encodeBase64String(iv);
    }

    /**
     * 生成256位秘钥
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static SecretKey getAESKey() throws NoSuchAlgorithmException {
        KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGen.init(AES_KEY_BIT, SecureRandom.getInstanceStrong());
        return keyGen.generateKey();
    }

    /**
     * 生成256位秘钥,base64编码
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String generateAESKey() throws NoSuchAlgorithmException {
        return Base64.encodeBase64String(getAESKey().getEncoded());
    }

    /**
     * 通过密码和盐值生成256位aes秘钥
     * @param password 密码
     * @param salt 盐值
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static SecretKey getAESKeyFromPassword(char[] password, byte[] salt)
        throws NoSuchAlgorithmException, InvalidKeySpecException {

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        // iterationCount = 65536
        KeySpec spec = new PBEKeySpec(password, salt, 65536, AES_KEY_BIT);
        SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), KEY_ALGORITHM);
        return secret;

    }

    /**
     * 加密
     * @param source 明文
     * @param secret 秘钥
     * @param iv 初始向量
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] source, SecretKey secret, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
        byte[] encryptedText = cipher.doFinal(source);
        return encryptedText;
    }

    /**
     * 加密,base64编码
     * @param source 明文
     * @param key 秘钥
     * @param iv 初始向量
     * @return
     * @throws Exception
     */
    public static String encrypt(String source, String key, String iv) throws Exception {
        SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(key), KEY_ALGORITHM);//getAESKeyFromPassword(password.toCharArray(), Base64.decodeBase64(salt));
        byte[] encryptedText = encrypt(source.getBytes(StandardCharsets.UTF_8), secretKey, Base64.decodeBase64(iv));
        return Base64.encodeBase64String(encryptedText);
    }

    /**
     * 加密,通过base64编码,秘钥通过password和盐值生成
     * @param source 明文
     * @param password 密码
     * @param iv 初始向量
     * @param salt 盐值
     * @return
     * @throws Exception
     */
    public static String encrypt(String source, String password, String iv, String salt) throws Exception {
        SecretKey secretKey = getAESKeyFromPassword(password.toCharArray(), Base64.decodeBase64(salt));
        byte[] encryptedText = encrypt(source.getBytes(StandardCharsets.UTF_8), secretKey, Base64.decodeBase64(iv));
        return Base64.encodeBase64String(encryptedText);
    }

    /**
     * 解密
     * @param encryptBytes 加密数组
     * @param secret 秘钥
     * @param iv 初始向量
     * @return
     * @throws Exception
     */
    public static String decrypt(byte[] encryptBytes, SecretKey secret, byte[] iv) throws Exception {

        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
        byte[] plainText = cipher.doFinal(encryptBytes);
        return new String(plainText, StandardCharsets.UTF_8);
    }

    /**
     * 解密
     * @param encryptStr 加密字符串
     * @param password 密码
     * @param iv 初始向量
     * @param salt 盐值
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptStr, String password, String iv, String salt) throws Exception {
        SecretKey secretKey = getAESKeyFromPassword(password.toCharArray(), Base64.decodeBase64(salt));
        return decrypt(Base64.decodeBase64(encryptStr), secretKey, Base64.decodeBase64(iv));
    }

    /**
     * 解密
     * @param encryptStr 加密字符串
     * @param key 秘钥
     * @param iv 初始向量
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptStr, String key, String iv) throws Exception {
        SecretKey secretKey = new SecretKeySpec(Base64.decodeBase64(key), KEY_ALGORITHM);
        return decrypt(Base64.decodeBase64(encryptStr), secretKey, Base64.decodeBase64(iv));
    }

}

pom依赖

        <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.15</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AES_GCM是一种结合了AES对称加密算法GCM消息认证码的加密算法。在AES_GCM中,GCM指的是Galois/Counter Mode,其中的G代表GMAC,C代表CTR。AES_GCM算法可以同时提供对消息的加密和完整性校验,并且还可以提供附加消息的完整性校验。在实际应用中,有些信息可能不需要保密,但接收者需要确认其真实性,这些信息可以作为附加消息加入到MAC值的计算中。AES_GCM实现过程中,使用对称密钥对输入进行AES运算,并生成密文、初始向量IV和MAC值。密文接收者可以使用相同的密钥和IV来解密密文,并验证MAC值以确保消息的完整性和真实性。因此,AES_GCM是一种同时提供加密和完整性校验的高级加密标准。 #### 引用[.reference_title] - *1* *2* [AES-GCM加密算法的简单介绍](https://blog.csdn.net/qq_39500214/article/details/108888998)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [什么是 AES-GCM加密算法](https://blog.csdn.net/T0mato_/article/details/53160772)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值