当前位置:   article > 正文

RSA与AES:打造高效且超安全的混合加密方案

RSA与AES:打造高效且超安全的混合加密方案

RSA + AES 混合加密

RSA非对称加密的一种,具有两个密钥:公共密钥和私有密钥。公钥和私钥是一对,公钥加密后的内容只有私钥才能解密。两个密钥的不同,所以是非对称的。

AES对称加密的一种,加密和解密的密钥都是一个

由此就可以看出两者的优势和劣势:

RSA相对安全,但是加密速度则会慢;而AES加密速度快,但是安全性相对差。

下面直接用登录功能的前后端交互图作为案例:

在这里插入图片描述

而后就是对应的工具库的问题,有很多可以实现加密的工具。但是前后端需要能用一样的加密和解密的算法才行。

RSA工具库:

RSA/ECB/PKCS1Padding,这个是RSA算法的具体实现方式,这个有很多种,比如还有ECB因此很容易和别人的算法不匹配。

  • ECB 模式 在 RSA 加密中使用是安全的,因为 RSA 加密的主要对象是小数据块(如会话密钥),而不是大数据量的数据块。
  • PKCS1Padding 提供了额外的安全性,确保加密的数据块长度合适,并防止某些攻击,如小明文本攻击。

这里看了别人的文章补充一下:

  • Java 默认的 RSA 实现是 RSA/None/PKCS1Padding
  • 在创建RSA秘钥对时,长度最好选择 2048的整数倍,长度为1024在已经不很安全了
  • DER是RSA密钥的二进制格式,PEM是DER转码为Base64的字符格式,用PEM比较通用,字符串方便阅读。

后端代码:

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec; 
import javax.crypto.Cipher;
import java.util.Base64;

public class RSADecrypt {

    public static String decrypt(String encryptedText, String privateKey) throws Exception {
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey key = keyFactory.generatePrivate(keySpec);

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);

        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }


    public static void main(String[] args) throws Exception {
        // 生成RSA密钥对
        // 使用自定义的种子值来初始化 KeyPairGenerator
        byte[] seed = "RSA".getBytes(); // 用自己想要的值替换这里的固定种子值
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048, new SecureRandom(seed));

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 将公钥和私钥转换成Base64编码的字符串,以便传递给前端和后端
        String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());

}
  • 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

前端RSA工具库(加密):

“jsencrypt”: “^3.3.2”

import JsEncrypt from 'jsencrypt'

var encrypt = new JsEncrypt();


encrypt.setPublicKey();


this.encryptedAesKey = encrypt.encrypt()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

AES工具类后端:

AES/ECB/PKCS5Padding 注意算法方式

import org.apache.commons.codec.DecoderException; 
import org.apache.commons.codec.binary.Hex;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * AES对称加密工具类
 */
public class AESUtil {
    /**
     * 加密算法
     */
    private static String Algorithm = "AES";

    /**
     * 算法/模式/补码方式
     */
    private static String AlgorithmProvider = "AES/ECB/PKCS5Padding";

    /**
     * 加密
     *
     * @param src       原内容
     * @param uniqueKey 唯一key
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws DecoderException
     */
    public static String encrypt(String src, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, DecoderException {
        byte[] key = uniqueKey.getBytes();
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] cipherBytes = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
        return byteToHexString(cipherBytes);
    }

    /**
     * 解密
     *
     * @param enc       加密内容
     * @param uniqueKey 唯一key
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws DecoderException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String decrypt(String enc, String uniqueKey) throws NoSuchPaddingException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException, DecoderException, BadPaddingException, IllegalBlockSizeException {
        byte[] key = uniqueKey.getBytes();
        SecretKey secretKey = new SecretKeySpec(key, Algorithm);
        Cipher cipher = Cipher.getInstance(AlgorithmProvider);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] hexBytes = hexStringToBytes(enc);
        byte[] plainBytes = cipher.doFinal(hexBytes);
        return new String(plainBytes, "UTF-8").replaceAll("^\"|\"$", "");
    }

    /**
     * 将byte数组转换为16进制字符串
     *
     * @param src
     * @return
     */
    private static String byteToHexString(byte[] src) {
        return Hex.encodeHexString(src);
    }

    /**
     * 将16进制字符串转换为byte数组
     *
     * @param hexString
     * @return
     */
    private static byte[] hexStringToBytes(String hexString) throws DecoderException {
        return Hex.decodeHex(hexString);
    }

}
  • 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

AES前端代码:

    //生成指定长度随机字符串
    generateRandomStr(strLength = 16) {
      let code = '';
      const chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; 
      const charsArr = chars.split('');

      for (let i = 0; i < strLength; i++) {
        const num = Math.floor(Math.random() * charsArr.length);
        code += charsArr[num];
      }
      return code;
    },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
const encryptedContent_zh = CryptoJS.AES.encrypt(content_zh, this.key, {
          mode: CryptoJS.mode.ECB,
          padding: CryptoJS.pad.Pkcs7
        });
        const encStr_zh = encryptedContent_zh.ciphertext.toString();
        this.encStr_zh = encryptedContent_zh.ciphertext.toString();

        const encryptedContent_mm = CryptoJS.AES.encrypt(content_mm, this.key, {
          mode: CryptoJS.mode.ECB,
          padding: CryptoJS.pad.Pkcs7
        });


        // 解密方法
        const decryptedContent_zh = CryptoJS.AES.decrypt(
          CryptoJS.format.Hex.parse(encStr_zh),
          this.key,//注意:后面这里最好使用 CryptoJS.format.Utf8.parse(key) 
          {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
          }
        );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/626471
推荐阅读
相关标签
  

闽ICP备14008679号