前后端数据交互混合加密方案

前后端数据交互混合加密方案

需求:前后端数据交互时,要求接口请求参数和响应参数都需要做数据加密处理,且在传输过程中即使密文被拦截,也无法破解。(其它情况举一反三,自行斟酌最佳加密方案)

双向加密算法介绍

加密算法首先分为两种:单向加密、双向加密。单向加密是不可逆的,也就是只能加密,不能解密。双向加密是可逆的,也就是说可以解密出原文,而双向加密算法一般分为对称性加密算法和非对称性加密算法。

对称性加密算法

在对称加密算法中,加密和解密使用的是同一把钥匙,即:使用相同的密匙对同一密码进行加密和解密。也称为单密钥加密。

加解密过程如下:

    加密:原文 + 密匙 = 密文

    解密:密文 + 密匙 = 原文

优点:算法简单,加密解密容易,效率高,执行快。

缺点:在数据传送前,发送方和接收方必须商定好秘钥,相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,信息很容易被破译。密钥管理也成为双方的负担。

几种常见的对称性加密算法

DES:已破解,不再安全,基本没有企业在用了。是对称加密算法的基石,具有学习价值。密钥长度56(JDK)、56/64(BC)。

3DES:早于AES出现来替代DES。计算密钥时间太长、加密效率不高,所以也基本上不用。密钥长度112/168(JDK)、128/192(BC)

AES:最常用的对称加密算法,密钥建立时间短、灵敏性好、内存需求低。实际使用中,使用工作模式为CTR(最好用BC去实现),此工作模式需要引入IV参数(16位的字节数组)。密钥长度128/192/256,其中192与256需要配置无政策限制权限文件(JDK6)。填充模式最常用的两种PKCS5Padding和PKCS7Padding,其中后者只有BC独有。

IDEA:常用的电子邮件加密算法,工作模式只有ECB,密钥长度128位。

非对称性加密算法

非对称加密有两个钥匙,公钥(Public Key)和私钥(Private Key)。公钥和私钥是成对的存在,如果对原文使用公钥加密,则只能使用对应的私钥才能解密;私钥只能由一方保管,不能外泄。公钥能够交给任何请求方。因为加密和解密使用的不是同一把密钥,所以这种算法称之为非对称加密算法。

加解密过程如下:

    加密:原文 + 公钥 = 密文

    解密:密文 + 私钥 = 原文

优点:安全性高,即使密文被拦截、公钥被获取,但是无法获取到私钥,也就无法破译密文。作为接收方,务必要保管好自己的私钥。

缺点:加密算法及其复杂,安全性依赖算法与密钥,而且加密和解密效率很低。

几种常见的非对称加密算法:RSA、DSA、ECC

几种常见的非对称性加密算法

RSA:为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。RSA是被研究得最广泛的公钥算法,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的加密方案之一。RSA 即可作为数字签名,也可以作为加密算法。不过作为加密使用的 RSA 有着随密钥长度增加,性能急剧下降的问题。

DSA:DSA 只能用于数字签名,而无法用于加密(某些扩展可以支持加密);在业界支持方面,RSA 显然是赢家。RSA 具有更为广泛的部署与支持。

ECC:椭圆曲线算法(Elliptic Curves Cryptography),与其他非对称加密算法相比ECC算法具有安全性更高(160位ECC已经与1024位RSA、DSA有相同的安全强度)、密钥短、计算量小、处理速度快、存储空间占用小、带宽要求低,在私钥的处理速度上(解密和签名),ECC远比RSA、DSA快得多等优势。由于椭圆曲线算法的优点,使其取代 RSA/DSA 而成为新一代通用的非对称加密算法成为可能。

为什么要使用混合加密方案?

我们先看看单一加密方案的缺点:

  1. 使用对称性加密算法
    对接时需要把秘钥告知对方,而前端获取秘钥和保存秘钥,或者用接口传输秘钥,均可以轻易被获取。

  2. 使用非对称加密算法
    后端提供接口和私钥、公钥。对接时需要把公钥告知前端,因为私钥不能提供给前端,所以只能做到请求参数加密传输。因为没有私钥,所以无法解密响应参数。

使用混合加密方案:对称性加密算法+非对称加密算法

用对称加密算法加密业务数据,用非对称加密算法加密对称加密算法的秘钥,以AES+RSA混合加密方案为例:

  1. 后端提供接口和RSA的私钥A、公钥B,通过接口提前将公钥传输给前端;
  2. 前端生成临时的随机的AES秘钥,调用接口时,将AES加密的数据通过RSA加密的AES秘钥传输给后端,例:{encryptData: “AES加密的请求数据”, “encryptAESKey”: “RSA加密的AES秘钥”};
  3. 后端拿到加密数据和AES秘钥后,先通过RSA私钥解密AES秘钥,再通过AES秘钥解密数据得到请求数据原文,然后进行业务处理;
  4. 后端返回数据时,使用前端提供的AES秘钥加密响应数据返回给前端
  5. 前端用AES秘钥解密数据得到响应数据原文。

常见混合加密方案推荐:RSA+AES、ECC+AES

其它

JAVA生成RSA秘钥

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
package com.example.rsa.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class RSAUtils {
private static final Logger logger = LoggerFactory.getLogger(RSAUtils.class);

// 加密算法 RSA
public static final String KEY_ALGORITHM = "RSA";
// RSA 位数
private static final int INITIALIZE_LENGTH = 1024;

public static void generateRSAKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(INITIALIZE_LENGTH);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
logger.info(publicKey);

String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
logger.info(privateKey);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

前端使用CryptoJs做AES加解密

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
var aesKey = getAESKey();
var parseKey = CryptoJS.enc.Utf8.parse(aesKey);
// /AES/CBC/Pkcs7Padding
var iv = CryptoJS.enc.Utf8.parse("1234567812345678");
var mode = CryptoJS.mode.CBC;
var padding = CryptoJS.pad.Pkcs7;

// 随机生成16位的aesKey
function getAESKey() {
let key = [];
for (let i = 0; i < 16; i++) {
let num = Math.floor(Math.random() * 26);
let charStr = String.fromCharCode(97 + num);
key.push(charStr.toUpperCase());
}
return key.join('');
};

// AES 数据加密
function encryptAES(value) {
return CryptoJS.enc.Base64.stringify(CryptoJS.AES.encrypt(value, parseKey, {
iv: iv,
mode: mode,
padding: padding
}).ciphertext);
};

// AES 数据解密
function decryptAES(value) {
return CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(value, parseKey, {
iv: iv,
mode: mode,
padding: padding
})).trim();
};

前后端数据交互混合加密方案

https://hormones.github.io/post/5a8089c3/

作者

Ethan Davis

发布于

2022-05-12

更新于

2022-05-12

许可协议

评论