demo1
sequenceDiagram actor c as 客户端 participant f as 前端服务器 participant b as 后端服务器 c ->> f: 触发请求 f ->> +b: 发送请求 b ->> b: 通过RSA生成pubkey1和prikey1 note right of b: pubkey1, prikey1 b -->> -f: 将pubkey1返回前端 b --> +f: f ->> f: 通过RSA生成pubkey2和prikey2 note left of f: pubkey2, prikey2 f ->> f: 加密: pubkey1(pubkey2) => secret1 f ->> -b: 用secret1请求后端 f --> +b: b ->> b: 解密: prikey1(secret1) => pubkey2 b ->> b: 加密: pubkey2(AESkey) => secret2 b ->> -f: 返回secret2 b --> +f: f ->> f: 解密: prikey2(secret2) => AESkey f ->> f: 加密: AESkey(data) => secretData f ->> -b: 将加密数据发送给后端
<template>
<div>
<input type="text" v-model="text" />
<button @click="encryptData">加密</button>
<button @click="decryptData">解密</button>
</div>
</template>
<script>
import CryptoJS from 'crypto-js'
export default {
data() {
return {
text: '',
key: null,
nonce: null,
ciphertext: null,
tag: null
}
},
methods: {
// 使用AES算法加密数据
encryptData() {
const key = CryptoJS.lib.WordArray.random(16)
const nonce = CryptoJS.lib.WordArray.random(12)
const encrypted = CryptoJS.AES.encrypt(this.text, key, {
mode: CryptoJS.mode.GCM,
iv: nonce
})
this.key = CryptoJS.enc.Base64.stringify(key)
this.nonce = CryptoJS.enc.Base64.stringify(nonce)
this.ciphertext = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
this.tag = CryptoJS.enc.Base64.stringify(encrypted.finalize())
},
// 使用AES算法解密数据
decryptData() {
const key = CryptoJS.enc.Base64.parse(this.key)
const nonce = CryptoJS.enc.Base64.parse(this.nonce)
const ciphertext = CryptoJS.enc.Base64.parse(this.ciphertext)
const tag = CryptoJS.enc.Base64.parse(this.tag)
const decrypted = CryptoJS.AES.decrypt(
{ ciphertext },
key,
{
mode: CryptoJS.mode.GCM,
iv: nonce,
tag: tag
}
)
this.text = decrypted.toString(CryptoJS.enc.Utf8)
}
}
}
</script>
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
public class EncryptionUtil {
private static final int KEY_SIZE = 2048;
// 生成RSA密钥对
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(KEY_SIZE);
return generator.generateKeyPair();
}
// 使用RSA公钥加密AES密钥
public static byte[] encryptKey(byte[] key, PublicKey publicKey) throws Exception {
byte[] encryptedKey = null;
try {
GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
KeyParameter keyParameter = new KeyParameter(key);
AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
cipher.init(true, parameters);
encryptedKey = new byte[cipher.getOutputSize(key.length)];
int len = cipher.processBytes(key, 0, key.length, encryptedKey, 0);
cipher.doFinal(encryptedKey, len);
} catch (InvalidCipherTextException e) {
e.printStackTrace();
}
return PublicKeyFactory.createKey(publicKey.getEncoded()).encrypt(encryptedKey);
}
// 使用RSA私钥解密AES密钥
public static byte[] decryptKey(byte[] encryptedKey, PrivateKey privateKey) throws Exception {
byte[] decryptedKey = PrivateKeyFactory.createKey(privateKey.getEncoded()).decrypt(encryptedKey);
GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
KeyParameter keyParameter = new KeyParameter(decryptedKey);
AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
cipher.init(false, parameters);
byte[] key = new byte[cipher.getOutputSize(decryptedKey.length)];
int len = cipher.processBytes(decryptedKey, 0, decryptedKey.length, key, 0);
cipher.doFinal(key, len);
return key;
}
// 使用AES算法加密数据
public static byte[] encryptData(byte[] data, byte[] key) throws Exception {
GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
KeyParameter keyParameter = new KeyParameter(key);
AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
cipher.init(true, parameters);
byte[] ciphertext = new byte[cipher.getOutputSize(data.length)];
int len = cipher.processBytes(data, 0, data.length, ciphertext, 0);
cipher.doFinal(ciphertext, len);
return ciphertext;
}
// 使用AES算法解密数据
public static byte[] decryptData(byte[] ciphertext, byte[] key, byte[] nonce, byte[] tag) throws Exception {
GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
KeyParameter keyParameter = new KeyParameter(key);
AEADParameters parameters = new AEADParameters(keyParameter, 128, nonce, tag);
cipher.init(false, parameters);
byte[] data = new byte[cipher.getOutputSize(ciphertext.length)];
int len = cipher.processBytes(ciphertext, 0, ciphertext.length, data, 0);
cipher.doFinal(data, len);
return data;
}
public static void main(String[] args) throws Exception {
// 生成RSA密钥对
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// 加密数据
String data = "Hello World!";
byte[] key = new byte[16];
for (int i = 0; i < key.length; i++) {
key[i] = (byte) (Math.random() * 256);
}
byte[] encryptedKey = encryptKey(key, publicKey);
byte[] nonce = new byte[12];
for (int i = 0; i < nonce.length; i++) {
nonce[i] = (byte) (Math.random() * 256);
}
byte[] ciphertext = encryptData(data.getBytes(StandardCharsets.UTF_8), key);
byte[] tag = new byte[16];
System.arraycopy(ciphertext, ciphertext.length - 16, tag, 0, 16);
// 输出加密后的数据
System.out.println("Key: " + Base64.getEncoder().encodeToString(key));
System.out.println("Nonce: " + Base64.getEncoder().encodeToString(nonce));
System.out.println("Ciphertext: " + Base64.getEncoder().encodeToString(ciphertext));
System.out.println("Tag: " + Base64.getEncoder().encodeToString(tag));
// 解密数据
key = decryptKey(encryptedKey, privateKey);
byte[] plaintext = decryptData(ciphertext, key, nonce, tag);
System.out.println(new String(plaintext, StandardCharsets.UTF_8)); // 输出:Hello World!
}
}
上述代码使用了CryptoJS库和Bouncy Castle库实现了前后端数据加密。在这个示例中,前端使用AES算法对数据进行加密,然后使用RSA公钥加密AES密钥,将加密后的密钥和加密后的数据一起发送给后端。后端使用RSA私钥解密AES密钥,然后使用解密后的密钥对数据进行解密。同样,后端也可以使用AES算法对数据进行加密,然后使用RSA公钥加密AES密钥,将加密后的密钥和加密后的数据一起发送给前端。前端使用RSA私钥解密AES密钥,然后使用解密后的密钥对数据进行解密。
demo2
sequenceDiagram actor a as 用户 participant f as 前端服务器 participant b as 后端服务器 a ->> +f: 触发操作 f ->> f: 生成随机AES密钥 f ->> f: AES(data) => secretData f ->> f: RSA_priKey(AES) => aesKey f ->> +b: aesKey + secretData b ->> b: RSA_pubKey(aesKey) => AES b ->> b: AES(secretData) => data b ->> b: 同等方式加密 b -->> -f: 响应数据 f -->> -a: 响应给用户