当前位置: 首页 > news >正文

发送加密信息的简单实现【Java】

(修改期)

一、代码的引用处

public static SecretKeys generateKeys() throws NoSuchAlgorithmException {: 

定义一个公共静态方法,用于生成 AES 和 HMAC 密钥对。

public static String encrypt(String plaintext, SecretKey aesKey, SecretKey hmacKey) throws Exception {: 

定义一个公共静态方法,用于加密给定的明文,并使用 HMAC 保护其完整性。 它接受明文、AES 密钥和 HMAC 密钥作为输入,并返回 Base64 编码的加密字符串。

public static String decrypt(String encryptedText, SecretKey aesKey, SecretKey hmacKey) throws Exception {:

定义一个公共静态方法,用于解密给定的加密文本并验证其完整性。 它接受 Base64 编码的加密文本、AES 密钥和 HMAC 密钥作为输入,并返回解密的明文。

public static String[] encryptKey(SecretKeys keys, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {

定义一个公共静态方法,用于加密生成的AES 密钥和 HMAC 密钥。它接收AES 密钥和 HMAC 密钥和接收者发来的公钥,并返回加密后的密钥字符串数组。

public static SecretKeys decryptKey(String []cipherText,PrivateKey privateKey) throws Exception {

 定义一个公共静态方法,用于解密发送端传来的秘钥。它接收密钥字符串数组和接收者生成的私钥,并返回一个包装密钥的SecretKeys对象。

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

public class SecureAESUtils {
    private static final int GCM_TAG_LENGTH = 128;
    private static final int IV_LENGTH = 12;
    private static final int HMACDigest = 32;
    private static final int AES_KEY_LENGTH = 256;
    private static final int HMAC_KEY_LENGTH = 256;
    private static final String encryptionAlgorithm = "AES";
    private static final String AES_ALGORITHM = encryptionAlgorithm + "/GCM/NoPadding";
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final String HMAC_ALGORITHM = "HmacSHA256";

    public static class SecretKeys {
        private final SecretKey aesKey;
        private final SecretKey hmacKey;

        public SecretKeys(SecretKey aesKey, SecretKey hmacKey) {
            this.aesKey = aesKey;
            this.hmacKey = hmacKey;
        }

        public String getAesKeyBase64() {
            return Base64.getEncoder().encodeToString(aesKey.getEncoded());
        }

        public String getHmacKeyBase64() {
            return Base64.getEncoder().encodeToString(hmacKey.getEncoded());
        }

        public static SecretKeys fromBase64(String aesKeyBase64, String hmacKeyBase64) {
            SecretKey aesKey = new SecretKeySpec(Base64.getDecoder().decode(aesKeyBase64), encryptionAlgorithm);
            SecretKey hmacKey = new SecretKeySpec(Base64.getDecoder().decode(hmacKeyBase64), HMAC_ALGORITHM);
            return new SecretKeys(aesKey, hmacKey);
        }
    }

    public static SecretKeys generateKeys() throws NoSuchAlgorithmException {
        KeyGenerator aesKeyGen = KeyGenerator.getInstance(encryptionAlgorithm);
        aesKeyGen.init(AES_KEY_LENGTH);
        SecretKey secretKey = aesKeyGen.generateKey();
        KeyGenerator hmacKeyGen = KeyGenerator.getInstance(HMAC_ALGORITHM);
        hmacKeyGen.init(HMAC_KEY_LENGTH);
        SecretKey hmacKey = hmacKeyGen.generateKey();
        return new SecretKeys(secretKey, hmacKey);
    }

    public static String encrypt(String plainText, SecretKeys keys) throws Exception {
        byte[] iv = new byte[IV_LENGTH];
        SecureRandom random = SecureRandom.getInstanceStrong();
        random.nextBytes(iv);

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, keys.aesKey, gcmSpec);
        byte[] encryptedText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        Mac hmac = Mac.getInstance(HMAC_ALGORITHM);
        hmac.init(keys.hmacKey);
        hmac.update(iv);
        hmac.update(encryptedText);
        byte[] hmacDigest = hmac.doFinal();

        byte[] result = new byte[IV_LENGTH + encryptedText.length + HMACDigest];
        System.arraycopy(iv, 0, result, 0, IV_LENGTH);
        System.arraycopy(encryptedText, 0, result, IV_LENGTH, encryptedText.length);
        System.arraycopy(hmacDigest, 0, result, IV_LENGTH + encryptedText.length, HMACDigest);
        return Base64.getEncoder().encodeToString(result);
    }

    public static String[] encryptKey(SecretKeys keys, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        String aesKey=keys.getAesKeyBase64();
        String hmacKey=keys.getHmacKeyBase64();

        Cipher cipher=Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte []encryptAesKey=cipher.doFinal(aesKey.getBytes(StandardCharsets.UTF_8));
        byte []encryptHmacKey=cipher.doFinal(hmacKey.getBytes(StandardCharsets.UTF_8));

        return new String[]{
                Base64.getEncoder().encodeToString(encryptAesKey),
                Base64.getEncoder().encodeToString(encryptHmacKey)
        };
    }

    public static String decrypt(String cipherText, SecretKeys keys) throws Exception {
        byte[] cipherTextBytes = Base64.getDecoder().decode(cipherText);
        if (cipherTextBytes.length < IV_LENGTH + HMACDigest) {
            throw new IllegalArgumentException("无效的加密数据!");
        }
        byte[] iv = new byte[IV_LENGTH];
        byte[] encryptedData = new byte[cipherTextBytes.length - IV_LENGTH - HMACDigest];
        byte[] hmacDigest = new byte[HMACDigest];

        System.arraycopy(cipherTextBytes, 0, iv, 0, IV_LENGTH);
        System.arraycopy(cipherTextBytes, IV_LENGTH, encryptedData, 0, encryptedData.length);
        System.arraycopy(cipherTextBytes, IV_LENGTH + HMACDigest, hmacDigest, 0, HMACDigest);

        Mac hmac = Mac.getInstance(HMAC_ALGORITHM);
        hmac.init(keys.hmacKey);
        hmac.update(iv);
        hmac.update(encryptedData);
        byte[] calculatedHmacDigest = hmac.doFinal();

        if(!MessageDigest.isEqual(calculatedHmacDigest, hmacDigest)) {
            throw new SecurityException("HMAC校验失败,数据可能被篡改!");
        }

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, keys.aesKey, gcmSpec);
        try{
            byte[] decryptedText = cipher.doFinal(encryptedData);
            return new String(decryptedText, StandardCharsets.UTF_8);
        }catch (AEADBadTagException e){
            throw new SecurityException("GCM 标签校验失败,数据可能被篡改!", e);
        }
    }

    public static SecretKeys decryptKey(String []cipherText,PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] decryptedAesBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText[0]));
        String aesKeyBase64=new String(decryptedAesBytes, StandardCharsets.UTF_8);

        byte[] decryptedHmacBytes =cipher.doFinal(Base64.getDecoder().decode(cipherText[1]));
        String hmacKeyBase64=new String(decryptedHmacBytes, StandardCharsets.UTF_8);

        return SecretKeys.fromBase64(aesKeyBase64,hmacKeyBase64);
    }
}

 这个类提供公钥和私钥的生成。

直接调用构造方法即可生成,用getPrivateKey方法获取私钥,用getPublicKeyBase64方法获取用于发送的公钥。

import java.security.*;
import java.util.Base64;

public class GenerateRSAKeyPairs{
    private static PrivateKey privateKey;
    public static PublicKey publicKey;
    public PrivateKey getPrivateKey() {
        return privateKey;
    }
    public String getPublicKeyBase64(){
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }
    public GenerateRSAKeyPairs () throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair=keyGen.generateKeyPair();
        privateKey=keyPair.getPrivate();
        publicKey=keyPair.getPublic();
    }
}

 这个方法将接收到的字符串形形式的公钥还原成PublicKey形式。接受Base64 编码的加密文本,返回公钥。

public static PublicKey restorePublicKey(String data){
        byte[] publicKeyBytes= Base64.getDecoder().decode(data);
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyBytes);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

二、代码的实现

SecureAESUtils类

1. 导入

import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
  • import javax.crypto.*;: 导入javax.crypto包下的所有类,该包提供加密和解密相关的类和接口,例如CipherSecretKey等。

  • import javax.crypto.spec.GCMParameterSpec;: 导入GCMParameterSpec类,用于指定GCM( Galois/Counter Mode)模式的参数。

  • import javax.crypto.spec.SecretKeySpec;: 导入SecretKeySpec类,用于从字节数组构建SecretKey对象。

  • import java.nio.charset.StandardCharsets;: 导入StandardCharsets类,提供标准的字符集常量,例如UTF-8。

  • import java.security.*;: 导入java.security包下的所有类,该包提供安全相关的类和接口,例如KeyPairGeneratorPublicKeyPrivateKey等。

  • import java.security.spec.InvalidKeySpecException;: 导入 InvalidKeySpecException 类,当提供的密钥规范(Key Specification)无效时,抛出此异常。Key Specification 用于将密钥以特定的格式表示(如字节数组),以便于存储或传输。

  • import java.security.spec.X509EncodedKeySpec;: 导入X509EncodedKeySpec类,用于表示以X.509标准编码的公钥。

  • import java.util.Base64;: 导入Base64类,用于进行Base64编码和解码。

2. 类定义和常量

public class SecureAESUtils {    
    private static final int GCM_TAG_LENGTH = 128;
    private static final int IV_LENGTH = 12;
    private static final int HMACDigest = 32;
    private static final int AES_KEY_LENGTH = 256;
    private static final int HMAC_KEY_LENGTH = 256;
    private static final String encryptionAlgorithm = "AES";
    private static final String AES_ALGORITHM = encryptionAlgorithm + "/GCM/NoPadding";
    private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
    private static final String HMAC_ALGORITHM = "HmacSHA256";
  • public class SecureAESUtils: 定义一个公共类SecureAESUtils,该类提供AES加密相关的工具方法。

  • private static final int GCM_TAG_LENGTH = 128;: 定义常量GCM_TAG_LENGTH,指定GCM认证标签的长度为128位。

  • private static final int IV_LENGTH = 12;: 定义常量IV_LENGTH,指定初始化向量(IV)的长度为12字节。

  • private static final int HMACDigest = 32;: 定义常量HMACDigest,指定HMAC摘要值的长度为32字节。

  • private static final int AES_KEY_LENGTH = 256;: 定义常量AES_KEY_LENGTH,指定AES密钥的长度为256位。

  • private static final int HMAC_KEY_LENGTH = 256;: 定义常量HMAC_KEY_LENGTH,指定HMAC密钥的长度为256位。

  • private static final String encryptionAlgorithm = "AES";: 定义常量encryptionAlgorithm,指定加密算法为AES。

  • private static final String AES_ALGORITHM = encryptionAlgorithm + "/GCM/NoPadding";: 定义常量AES_ALGORITHM,指定AES算法的完整模式为AES/GCM/NoPadding。GCM是一种认证加密模式,NoPadding表示不进行填充。

  • private static final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";: 定义常量RSA_ALGORITHM,指定RSA算法的完整模式为RSA/ECB/PKCS1Padding. ECB代表电子密码本模式,PKCS1Padding 是一种常用的填充方案,用于确保数据块的大小适合 RSA 算法的要求。

  • private static final String HMAC_ALGORITHM = "HmacSHA256";: 定义常量HMAC_ALGORITHM,指定HMAC算法为HmacSHA256。

3. 内部类 SecretKeys

public static class SecretKeys {
        private final SecretKey aesKey;
        private final SecretKey hmacKey;

        public SecretKeys(SecretKey aesKey, SecretKey hmacKey) {
            this.aesKey = aesKey;
            this.hmacKey = hmacKey;
        }

        public String getAesKeyBase64() {
            return Base64.getEncoder().encodeToString(aesKey.getEncoded());
        }

        public String getHmacKeyBase64() {
            return Base64.getEncoder().encodeToString(hmacKey.getEncoded());
        }

        public static SecretKeys fromBase64(String aesKeyBase64, String hmacKeyBase64) {
            SecretKey aesKey = new SecretKeySpec(Base64.getDecoder().decode(aesKeyBase64), encryptionAlgorithm);
            SecretKey hmacKey = new SecretKeySpec(Base64.getDecoder().decode(hmacKeyBase64), HMAC_ALGORITHM);
            return new SecretKeys(aesKey, hmacKey);
        }
    }
  • public static class SecretKeys: 定义一个公共静态内部类SecretKeys,用于封装AES密钥和HMAC密钥。

  • private final SecretKey aesKey;: 定义私有final成员变量aesKey,用于存储AES密钥。

  • private final SecretKey hmacKey;: 定义私有final成员变量hmacKey,用于存储HMAC密钥。

  • public SecretKeys(SecretKey aesKey, SecretKey hmacKey): 定义构造方法,用于初始化aesKeyhmacKey

  • public String getAesKeyBase64(): 定义方法getAesKeyBase64,用于获取AES密钥的Base64编码字符串。

    • aesKey.getEncoded(): 获取AES密钥的原始字节数组。

    • Base64.getEncoder().encodeToString(...): 将字节数组进行Base64编码。

  • public String getHmacKeyBase64(): 定义方法getHmacKeyBase64,用于获取HMAC密钥的Base64编码字符串,原理同上。

  • public static SecretKeys fromBase64(String aesKeyBase64, String hmacKeyBase64): 定义静态方法fromBase64,用于从Base64编码的字符串创建SecretKeys对象。

    • Base64.getDecoder().decode(aesKeyBase64): 将Base64编码的AES密钥字符串解码为字节数组。

    • new SecretKeySpec(..., encryptionAlgorithm): 使用字节数组和算法名称创建SecretKeySpec对象,作为AES密钥。

    • Base64.getDecoder().decode(hmacKeyBase64): 将Base64编码的HMAC密钥字符串解码为字节数组。

    • new SecretKeySpec(..., HMAC_ALGORITHM): 使用字节数组和算法名称创建SecretKeySpec对象,作为HMAC密钥。

    • return new SecretKeys(aesKey, hmacKey): 创建并返回SecretKeys对象。

4. generateKeys() 方法

public static SecretKeys generateKeys() throws NoSuchAlgorithmException {
        KeyGenerator aesKeyGen = KeyGenerator.getInstance(encryptionAlgorithm);
        aesKeyGen.init(AES_KEY_LENGTH);
        SecretKey secretKey = aesKeyGen.generateKey();
        KeyGenerator hmacKeyGen = KeyGenerator.getInstance(HMAC_ALGORITHM);
        hmacKeyGen.init(HMAC_KEY_LENGTH);
        SecretKey hmacKey = hmacKeyGen.generateKey();
        return new SecretKeys(secretKey, hmacKey);
    }

public static SecretKeys generateKeys() throws NoSuchAlgorithmException: 定义公共静态方法generateKeys,用于生成AES密钥和HMAC密钥。

  • KeyGenerator aesKeyGen = KeyGenerator.getInstance(encryptionAlgorithm);: 创建一个KeyGenerator对象,用于生成AES密钥。

  • aesKeyGen.init(AES_KEY_LENGTH);: 初始化KeyGenerator对象,指定密钥长度为AES_KEY_LENGTH(256位)。

  • SecretKey secretKey = aesKeyGen.generateKey();: 生成一个AES密钥。

  • KeyGenerator hmacKeyGen = KeyGenerator.getInstance(HMAC_ALGORITHM);: 创建一个KeyGenerator对象,用于生成HMAC密钥。

  • hmacKeyGen.init(HMAC_KEY_LENGTH);: 初始化KeyGenerator对象,指定密钥长度为HMAC_KEY_LENGTH(256位)。

  • SecretKey hmacKey = hmacKeyGen.generateKey();: 生成一个HMAC密钥。

  • return new SecretKeys(secretKey, hmacKey);: 创建并返回包含AES密钥和HMAC密钥的SecretKeys对象。

  • throws NoSuchAlgorithmException: 抛出NoSuchAlgorithmException异常,如果指定的算法不可用。

5. encrypt() 方法

public static String encrypt(String plainText, SecretKeys keys) throws Exception {
        byte[] iv = new byte[IV_LENGTH];
        SecureRandom random = SecureRandom.getInstanceStrong();
        random.nextBytes(iv);

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, keys.aesKey, gcmSpec);
        byte[] encryptedText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        Mac hmac = Mac.getInstance(HMAC_ALGORITHM);
        hmac.init(keys.hmacKey);
        hmac.update(iv);
        hmac.update(encryptedText);
        byte[] hmacDigest = hmac.doFinal();

        byte[] result = new byte[IV_LENGTH + encryptedText.length + HMACDigest];
        System.arraycopy(iv, 0, result, 0, IV_LENGTH);
        System.arraycopy(encryptedText, 0, result, IV_LENGTH, encryptedText.length);
        System.arraycopy(hmacDigest, 0, result, IV_LENGTH + encryptedText.length, HMACDigest);
        return Base64.getEncoder().encodeToString(result);
    }
  • public static String encrypt(String plainText, SecretKeys keys) throws Exception: 定义公共静态方法encrypt,用于加密字符串。

    • String plainText: 要加密的明文字符串。

    • SecretKeys keys: 包含AES密钥和HMAC密钥的SecretKeys对象。

    • throws Exception: 抛出可能出现的异常。

  • byte[] iv = new byte[IV_LENGTH];: 创建一个字节数组iv,用于存储初始化向量(IV)。

  • SecureRandom random = SecureRandom.getInstanceStrong();: 创建一个SecureRandom对象,用于生成安全的随机数。

  • random.nextBytes(iv);: 使用SecureRandom对象填充iv字节数组,生成随机的IV。

  • Cipher cipher = Cipher.getInstance(AES_ALGORITHM);: 创建一个Cipher对象,用于进行AES加密。

  • GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);: 创建一个GCMParameterSpec对象,用于指定GCM参数。

  • cipher.init(Cipher.ENCRYPT_MODE, keys.aesKey, gcmSpec);: 初始化Cipher对象,设置为加密模式,使用AES密钥和GCM参数。

  • byte[] encryptedText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));: 对明文字符串进行加密,并将结果存储在encryptedText字节数组中。

  • Mac hmac = Mac.getInstance(HMAC_ALGORITHM);: 创建一个Mac对象,用于计算HMAC。

  • hmac.init(keys.hmacKey);: 初始化Mac对象,使用HMAC密钥。

  • hmac.update(iv);: 使用IV更新HMAC。

  • hmac.update(encryptedText);: 使用加密后的数据更新HMAC。

  • byte[] hmacDigest = hmac.doFinal();: 计算HMAC摘要值,并将结果存储在hmacDigest字节数组中。

  • byte[] result = new byte[IV_LENGTH + encryptedText.length + HMACDigest];: 创建一个字节数组result,用于存储最终的加密结果,包括IV、加密数据和HMAC摘要值。

  • System.arraycopy(iv, 0, result, 0, IV_LENGTH);: 将IV复制到result字节数组的开头。

  • System.arraycopy(encryptedText, 0, result, IV_LENGTH, encryptedText.length);: 将加密数据复制到result字节数组中,紧跟在IV之后。

  • System.arraycopy(hmacDigest, 0, result, IV_LENGTH + encryptedText.length, HMACDigest);: 将HMAC摘要值复制到result字节数组中,紧跟在加密数据之后。

  • return Base64.getEncoder().encodeToString(result);: 将最终的加密结果进行Base64编码,并返回编码后的字符串。

6. encryptKey() 方法

public static String[] encryptKey(SecretKeys keys, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        String aesKey=keys.getAesKeyBase64();
        String hmacKey=keys.getHmacKeyBase64();

        Cipher cipher=Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte []encryptAesKey=cipher.doFinal(aesKey.getBytes(StandardCharsets.UTF_8));
        byte []encryptHmacKey=cipher.doFinal(hmacKey.getBytes(StandardCharsets.UTF_8));

        return new String[]{
                Base64.getEncoder().encodeToString(encryptAesKey),
                Base64.getEncoder().encodeToString(encryptHmacKey)
        };
    }
  • public static String[] encryptKey(SecretKeys keys, PublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException: 定义公共静态方法encryptKey,用于使用RSA公钥加密AES密钥和HMAC密钥。

    • SecretKeys keys: 包含AES密钥和HMAC密钥的SecretKeys对象。

    • PublicKey publicKey: 用于加密密钥的RSA公钥。

    • throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException: 抛出可能出现的异常。

  • String aesKey=keys.getAesKeyBase64();: 获取AES密钥的Base64编码字符串。

  • String hmacKey=keys.getHmacKeyBase64();: 获取HMAC密钥的Base64编码字符串。

  • Cipher cipher=Cipher.getInstance(RSA_ALGORITHM);: 创建一个Cipher对象,用于进行RSA加密。

  • cipher.init(Cipher.ENCRYPT_MODE,publicKey);: 初始化Cipher对象,设置为加密模式,使用RSA公钥。

  • byte []encryptAesKey=cipher.doFinal(aesKey.getBytes(StandardCharsets.UTF_8));: 使用RSA公钥加密AES密钥,并将结果存储在encryptAesKey字节数组中。

  • byte []encryptHmacKey=cipher.doFinal(hmacKey.getBytes(StandardCharsets.UTF_8));: 使用RSA公钥加密HMAC密钥,并将结果存储在encryptHmacKey字节数组中。

  • return new String[]{Base64.getEncoder().encodeToString(encryptAesKey), Base64.getEncoder().encodeToString(encryptHmacKey)};: 将加密后的AES密钥和HMAC密钥进行Base64编码,并返回包含这两个编码字符串的字符串数组。

7. decrypt() 方法

public static String decrypt(String cipherText, SecretKeys keys) throws Exception {
        byte[] cipherTextBytes = Base64.getDecoder().decode(cipherText);
        if (cipherTextBytes.length < IV_LENGTH + HMACDigest) {
            throw new IllegalArgumentException("无效的加密数据!");
        }
        byte[] iv = new byte[IV_LENGTH];
        byte[] encryptedData = new byte[cipherTextBytes.length - IV_LENGTH - HMACDigest];
        byte[] hmacDigest = new byte[HMACDigest];

        System.arraycopy(cipherTextBytes, 0, iv, 0, IV_LENGTH);
        System.arraycopy(cipherTextBytes, IV_LENGTH, encryptedData, 0, encryptedData.length);
        System.arraycopy(cipherTextBytes, IV_LENGTH + HMACDigest, hmacDigest, 0, HMACDigest);

        Mac hmac = Mac.getInstance(HMAC_ALGORITHM);
        hmac.init(keys.hmacKey);
        hmac.update(iv);
        hmac.update(encryptedData);
        byte[] calculatedHmacDigest = hmac.doFinal();

        if(!MessageDigest.isEqual(calculatedHmacDigest, hmacDigest)) {
            throw new SecurityException("HMAC校验失败,数据可能被篡改!");
        }

        Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
        GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, keys.aesKey, gcmSpec);
        try{
            byte[] decryptedText = cipher.doFinal(encryptedData);
            return new String(decryptedText, StandardCharsets.UTF_8);
        }catch (AEADBadTagException e){
            throw new SecurityException("GCM 标签校验失败,数据可能被篡改!", e);
        }
    }
  • public static String decrypt(String cipherText, SecretKeys keys) throws Exception: 定义公共静态方法decrypt,用于解密字符串。

    • String cipherText: 要解密的密文字符串。

    • SecretKeys keys: 包含AES密钥和HMAC密钥的SecretKeys对象。

    • throws Exception: 抛出可能出现的异常。

  • byte[] cipherTextBytes = Base64.getDecoder().decode(cipherText);: 将Base64编码的密文字符串解码为字节数组。

  • if (cipherTextBytes.length < IV_LENGTH + HMACDigest): 检查密文的长度是否足够,如果小于IV长度+HMAC长度,则抛出异常。

  • byte[] iv = new byte[IV_LENGTH];: 创建一个字节数组 iv,用于存储初始化向量(Initialization Vector)。

  • byte[] encryptedData = new byte[cipherTextBytes.length - IV_LENGTH - HMACDigest];: 创建一个字节数组 encryptedData,用于存储加密的数据部分。其长度等于总密文长度减去IV长度和HMAC长度。

  • byte[] hmacDigest = new byte[HMACDigest];: 创建一个字节数组 hmacDigest,用于存储HMAC(Hash-based Message Authentication Code)摘要。

  • System.arraycopy(cipherTextBytes, 0, iv, 0, IV_LENGTH);: 从密文字节数组中提取IV,复制到 iv 数组中。

  • System.arraycopy(cipherTextBytes, IV_LENGTH, encryptedData, 0, encryptedData.length);: 从密文字节数组中提取加密数据,复制到 encryptedData 数组中。

  • System.arraycopy(cipherTextBytes, IV_LENGTH + encryptedData.length, hmacDigest, 0, HMACDigest);: 从密文字节数组中提取HMAC摘要,复制到 hmacDigest 数组中。

  • Mac hmac = Mac.getInstance(HMAC_ALGORITHM);: 创建一个 Mac 对象,用于计算HMAC,使用的算法是之前定义的 HMAC_ALGORITHM(HmacSHA256)。

  • hmac.init(keys.hmacKey);: 使用存储在 keys 对象中的 HMAC 密钥初始化 Mac 对象。

  • hmac.update(iv);: 使用IV更新HMAC。

  • hmac.update(encryptedData);: 使用加密后的数据更新HMAC。

  • byte[] calculatedHmacDigest = hmac.doFinal();: 计算HMAC摘要值,并将结果存储在calculatedHmacDigest字节数组中。

  • if(!MessageDigest.isEqual(calculatedHmacDigest, hmacDigest)): 验证计算出的 HMAC 摘要是否与提供的摘要匹配。

  • throw new SecurityException("HMAC校验失败,数据可能被篡改!");: 如果HMAC校验失败,抛出异常。

  • Cipher cipher = Cipher.getInstance(AES_ALGORITHM);: 创建一个Cipher对象,用于进行AES解密。

  • GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);: 创建一个GCMParameterSpec对象,用于指定GCM参数。

  • cipher.init(Cipher.DECRYPT_MODE, keys.aesKey, gcmSpec);: 初始化Cipher对象,设置为解密模式,使用AES密钥和GCM参数。

  • byte[] decryptedText = cipher.doFinal(encryptedData);: 对密文字符串进行解密,并将结果存储在decryptedText字节数组中。

  • return new String(decryptedText, StandardCharsets.UTF_8);: 将解密后的字节数组转换为字符串,并返回。

  • catch (AEADBadTagException e): 捕获 AEADBadTagException 异常,这通常发生在 GCM 模式下认证标签验证失败时,意味着数据可能已被篡改。

  • throw new SecurityException("GCM 标签校验失败,数据可能被篡改!", e);: 重新抛出一个 SecurityException 异常,以表明 GCM 标签校验失败,数据可能已被篡改。原始的 AEADBadTagException 异常作为原因(cause)被包含在新异常中,有助于调试。

8. decryptKey() 方法

public static SecretKeys decryptKey(String []cipherText,PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        byte[] decryptedAesBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText[0]));
        String aesKeyBase64=new String(decryptedAesBytes, StandardCharsets.UTF_8);

        byte[] decryptedHmacBytes =cipher.doFinal(Base64.getDecoder().decode(cipherText[1]));
        String hmacKeyBase64=new String(decryptedHmacBytes, StandardCharsets.UTF_8);

        return SecretKeys.fromBase64(aesKeyBase64,hmacKeyBase64);
    }
  • public static SecretKeys decryptKey(String []cipherText,PrivateKey privateKey) throws Exception: 定义公共静态方法decryptKey,用于使用RSA私钥解密AES密钥和HMAC密钥。

    • String []cipherText: 包含加密后的AES密钥和HMAC密钥的字符串数组。

    • PrivateKey privateKey: 用于解密密钥的RSA私钥。

  • throws Exception: 抛出可能出现的异常。

  • Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);: 创建一个Cipher对象,用于进行RSA解密。

  • cipher.init(Cipher.DECRYPT_MODE, privateKey);: 初始化Cipher对象,设置为解密模式,使用RSA私钥。

  • byte[] decryptedAesBytes = cipher.doFinal(Base64.getDecoder().decode(cipherText[0]));: 使用RSA私钥解密AES密钥,并将结果存储在decryptedAesBytes字节数组中。

  • String aesKeyBase64=new String(decryptedAesBytes, StandardCharsets.UTF_8);: 将解密后的AES密钥字节数组转换为字符串。

  • byte[] decryptedHmacBytes =cipher.doFinal(Base64.getDecoder().decode(cipherText[1]));: 使用RSA私钥解密HMAC密钥,并将结果存储在decryptedHmacBytes字节数组中。

  • String hmacKeyBase64=new String(decryptedHmacBytes, StandardCharsets.UTF_8);: 将解密后的HMAC密钥字节数组转换为字符串。

  • return SecretKeys.fromBase64(aesKeyBase64,hmacKeyBase64);: 调用 SecretKeys.fromBase64() 方法,将Base64编码的AES密钥和HMAC密钥转换为 SecretKeys 对象,并返回。

9. restorePublicKey() 方法

public static PublicKey restorePublicKey(String data){
        byte[] publicKeyBytes= Base64.getDecoder().decode(data);
        X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyBytes);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }
  • public static PublicKey restorePublicKey(String data): 定义公共静态方法restorePublicKey,用于从Base64编码的字符串恢复公钥。

    • String data: Base64编码的公钥字符串。

  • byte[] publicKeyBytes= Base64.getDecoder().decode(data);: 将Base64编码的公钥字符串解码为字节数组。

  • X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKeyBytes);: 创建一个X509EncodedKeySpec对象,用于表示X.509编码的公钥。

  • KeyFactory keyFactory = KeyFactory.getInstance("RSA");: 创建一个KeyFactory对象,用于生成公钥。

  • return keyFactory.generatePublic(keySpec);: 使用KeyFactory对象和X509EncodedKeySpec对象生成公钥,并返回。

  • catch (NoSuchAlgorithmException | InvalidKeySpecException e): 捕获 NoSuchAlgorithmException 和 InvalidKeySpecException 异常。

  • throw new RuntimeException(e);: 如果在恢复公钥的过程中出现任何异常,则会创建一个 RuntimeException 异常,并将捕获到的原始异常(e)作为原因(cause)传递给新的 RuntimeException 异常。然后,新的 RuntimeException 异常会被抛出。

GenerateRSAKeyPairs 类 

1. 导入

import java.security.*;
import java.util.Base64;
  • package com.backEndProject.encrypt;: 声明该类属于com.backEndProject.encrypt包,用于组织和管理Java类。

  • import java.security.*;: 导入java.security包下的所有类,该包提供安全相关的类和接口,例如KeyPairGeneratorPublicKeyPrivateKey等。

  • import java.util.Base64;: 导入Base64类,用于进行Base64编码。

2. 类定义和成员变量

public class GenerateRSAKeyPairs{
    private static PrivateKey privateKey;
    public static PublicKey publicKey;
  • public class GenerateRSAKeyPairs: 定义一个公共类GenerateRSAKeyPairs,该类用于生成RSA密钥对。

  • private static PrivateKey privateKey;: 定义一个私有静态成员变量privateKey,用于存储生成的私钥。 使用static,所有此类的示例都共享这个私钥。

  • public static PublicKey publicKey;: 定义一个公共静态成员变量publicKey,用于存储生成的公钥。 使用static,所有此类的示例都共享这个公钥。

3. getter方法

public PrivateKey getPrivateKey() {
        return privateKey;
    }
    public String getPublicKeyBase64(){
        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
    }
  • public PrivateKey getPrivateKey(): 定义一个公共方法getPrivateKey,用于获取私钥。

    • return privateKey;: 返回私钥。

  • public String getPublicKeyBase64(): 定义一个公共方法getPublicKeyBase64,用于获取公钥的Base64编码字符串。

    • publicKey.getEncoded(): 获取公钥的原始字节数组。

    • Base64.getEncoder().encodeToString(...): 将字节数组进行Base64编码。

    • return ...: 返回Base64编码后的公钥字符串。

4. 构造方法

public GenerateRSAKeyPairs () throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair=keyGen.generateKeyPair();
        privateKey=keyPair.getPrivate();
        publicKey=keyPair.getPublic();
    }
  • public GenerateRSAKeyPairs () throws NoSuchAlgorithmException: 定义构造方法,用于生成RSA密钥对。

    • throws NoSuchAlgorithmException: 抛出NoSuchAlgorithmException异常,如果指定的算法不可用。

  • KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");: 创建一个KeyPairGenerator对象,用于生成RSA密钥对。

  • keyGen.initialize(2048);: 初始化KeyPairGenerator对象,指定密钥长度为2048位。

  • KeyPair keyPair=keyGen.generateKeyPair();: 生成一个RSA密钥对。

  • privateKey=keyPair.getPrivate();: 从密钥对中获取私钥,并赋值给成员变量privateKey

  • publicKey=keyPair.getPublic();: 从密钥对中获取公钥,并赋值给成员变量publicKey

相关文章:

  • Linux下python虚拟环境搭建及使用
  • k8s 部署spring项目+动态启动pod
  • 【漫话机器学习系列】199.过拟合 vs 欠拟合(Overfit vs Underfit)
  • 常见的归一化(Normalization)方法
  • 【高并发内存池】从零到一的项目:项目介绍、内存池及定长内存池的设计
  • 关于MOS的二十个问题
  • 学习SqlSugar的跨库查询基本用法
  • 【JavaEE】SpringBoot 统一功能处理
  • 视觉SLAM十四讲2nd—学习笔记(一)
  • isce+mintpy水体掩膜
  • “堆积木”式话云原生微服务架构(第一回)
  • Autosar Nm开发问题-部分网络管理报文无法维持网络唤醒
  • 论文阅读笔记——Reactive Diffusion Policy
  • 基于51单片机的正负5V数字电压表( proteus仿真+程序+设计报告+讲解视频)
  • Maven java 项目引入2.0.16版本的slf4j-api后,提示jedis:5.1.0的子依赖slf4j-api:1.7.36与2.0.16冲突
  • (PC+WAP)大气滚屏网站模板 电气电力设备网站源码下载
  • llm开发框架新秀
  • 从 MySQL 切换到国产 YashanDB 数据库时,需要在数据库字段和应用连接方面进行适配 ,使用总结
  • HarmonyOS-ArkUI V2装饰器: @Provider和@Consumer装饰器:跨组件层级双向同步
  • 聊天室项目day4(redis实现验证码期限,实现redis连接池)
  • windows搭建网站/优帮云查询数据云查询
  • 网站关键词库是怎么做的/怎么建个网站
  • 天津网站建设市场/深圳百度推广电话
  • wordpress合并js/长治网站seo
  • 精品课程网站建设方案/西安网站建设排名
  • 来客seo/沈阳网络seo公司