前后端通信加密方案(RSA + AES):确保数据安全的全面解决方案
130 阅读
0 评论
0 点赞
使用 RSA 来进行密钥交换,而 AES 用于数据加密。此方案能够保证数据的机密性和完整性,适用于大多数 Web 应用。本文将详细介绍如何在 Java、PHP 和 JavaScript 中实现该方案,并生成相关的加解密文件。
1. PHP 后端加密示例
1.1 安装所需的依赖
PHP 使用 openssl
扩展来实现 RSA 和 AES 加解密。
sudo apt-get install php-openssl
1.2 生成 RSA 密钥对
在 PHP 中,你可以使用 openssl
工具生成 RSA 公私钥对。
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048 openssl rsa -pubout -in private.pem -out public.pem
1.3 加密和解密逻辑
<?php // 解密 AES 密钥 function decryptAesKey($encryptedAesKey, $privateKey) { openssl_private_decrypt($encryptedAesKey, $aesKey, $privateKey); return $aesKey; } // 使用 AES 解密数据 function decryptData($aesKey, $iv, $encryptedData) { $cipher = "aes-256-gcm"; $decrypted = openssl_decrypt($encryptedData, $cipher, $aesKey, OPENSSL_RAW_DATA, $iv); return $decrypted; } // 读取私钥 $privateKey = file_get_contents('private.pem'); // 接收加密数据 $data = json_decode(file_get_contents('php://input'), true); $encryptedAesKey = base64_decode($data['encryptedAesKey']); $encryptedData = base64_decode($data['encryptedData']); $iv = base64_decode($data['iv']); // 解密 AES 密钥 $aesKey = decryptAesKey($encryptedAesKey, $privateKey); // 解密数据 $decryptedData = decryptData($aesKey, $iv, $encryptedData); echo json_encode(['decryptedData' => $decryptedData]); ?>
1.4 前端加密示例
前端通过 RSA 公钥加密 AES 密钥和数据,然后发送给 PHP 后端。
// 假设 `publicKey` 是从后端获取的 RSA 公钥 async function encryptData(data) { const aesKey = crypto.getRandomValues(new Uint8Array(32)); // 生成 256 位的 AES 密钥 const iv = crypto.getRandomValues(new Uint8Array(12)); // 生成 12 字节的 IV const encoder = new TextEncoder(); const encodedData = encoder.encode(data); const encryptedData = await window.crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, aesKey, encodedData ); const encryptedAesKey = await crypto.subtle.encrypt( { name: 'RSA-OAEP' }, publicKey, aesKey ); return { encryptedAesKey: base64Encode(encryptedAesKey), encryptedData: base64Encode(encryptedData), iv: base64Encode(iv) }; } // Base64 编码 function base64Encode(buffer) { return btoa(String.fromCharCode(...new Uint8Array(buffer))); }
2. Java 后端加密示例
2.1 生成 RSA 密钥对
Java 使用 KeyPairGenerator
来生成 RSA 密钥对。
import java.security.*; public class RSAKeyPairGenerator { public static void main(String[] args) throws Exception { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(2048); KeyPair keyPair = keyGen.generateKeyPair(); // 输出公钥和私钥 System.out.println("Public Key: " + Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded())); System.out.println("Private Key: " + Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded())); } }
2.2 加密和解密
import javax.crypto.*;
import java.security.*;
import java.util.Base64;
public class AesEncryption {
// 使用 RSA 解密 AES 密钥
public static SecretKey decryptAesKey(byte[] encryptedAesKey, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] aesKey = cipher.doFinal(encryptedAesKey);
return new SecretKeySpec(aesKey, "AES");
}
// 使用 AES 解密数据
public static String decryptData(SecretKey aesKey, byte[] iv, byte[] encryptedData) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, aesKey, spec);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}
public static void main(String[] args) throws Exception {
// 加载私钥和接收到的加密数据
PrivateKey privateKey = loadPrivateKey("private.pem");
byte[] encryptedAesKey = Base64.getDecoder().decode("..."); // 从请求中获取
byte[] encryptedData = Base64.getDecoder().decode("..."); // 从请求中获取
byte[] iv = Base64.getDecoder().decode("..."); // 从请求中获取
// 解密 AES 密钥
SecretKey aesKey = decryptAesKey(encryptedAesKey, privateKey);
// 解密数据
String decryptedData = decryptData(aesKey, iv, encryptedData);
System.out.println("Decrypted Data: " + decryptedData);
}
}
3. Node.js 后端加密示例
3.1 使用 crypto
模块进行加解密
const crypto = require('crypto'); const fs = require('fs'); // 读取 RSA 私钥 const privateKey = fs.readFileSync('private.pem', 'utf8'); // 解密 AES 密钥 function decryptAesKey(encryptedAesKey) { const buffer = Buffer.from(encryptedAesKey, 'base64'); return crypto.privateDecrypt(privateKey, buffer); } // 解密数据 function decryptData(aesKey, iv, encryptedData) { const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv); let decrypted = decipher.update(encryptedData, 'base64', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } const encryptedAesKey = '...'; // 从请求中获取 const encryptedData = '...'; // 从请求中获取 const iv = '...'; // 从请求中获取 const aesKey = decryptAesKey(encryptedAesKey); const decryptedData = decryptData(aesKey, iv, encryptedData); console.log("Decrypted Data: ", decryptedData);
4. 前端加密示例 (JavaScript)
4.1 使用 Web Crypto API 加密数据并发送
// 获取后端的 RSA 公钥并加密数据 async function fetchPublicKey() { const response = await fetch('/api/public-key'); const publicKeyPem = await response.text(); return crypto.subtle.importKey( 'spki', str2ab(publicKeyPem), { name: 'RSA-OAEP', hash: { name: 'SHA-256' } }, false, ['encrypt'] ); } // 生成 AES 密钥并加密数据 async function encryptData(data) { const rsaPublicKey = await fetchPublicKey(); // 生成 AES 密钥 const aesKey = await crypto.subtle.generateKey( { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'] ); // 使用 AES 加密数据 const iv = crypto.getRandomValues(new Uint8Array(12)); const encryptedData = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, aesKey, new TextEncoder().encode(data) ); // 使用 RSA 加密 AES 密钥 const encryptedAesKey = await crypto.subtle.encrypt( { name: 'RSA-OAEP' }, rsaPublicKey, aesKey ); return { encryptedAesKey: ab2base64(encryptedAesKey), encryptedData: ab2base64(encryptedData), iv: ab2base64(iv) }; } // Base64 编码和解码工具 function ab2base64(buffer) { return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))); } function str2ab(str) { const binaryString = atob(str); const length = binaryString.length; const bytes = new Uint8Array(length); for (let i = 0; i < length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; }
5. 微信小程序加密方案
在微信小程序中,你可以利用 JavaScript 的 Web Crypto API 来实现类似的加密逻辑。为了与后端兼容,后端依然使用 RSA 加密 AES 密钥,前端使用 AES 加密数据。
5.1 前端加密(微信小程序)
在小程序中,可以通过 RSA + AES 的组合来实现前后端加密通信。首先获取 RSA 公钥,使用它来加密 AES 密钥。然后通过 AES 加密数据,再将加密后的数据和 AES 密钥发送给后端。
5.1.1 小程序加密示例
// 获取 RSA 公钥并加密 AES 密钥和数据 async function fetchPublicKey() { // 假设后端提供了 API 获取公钥 const res = await wx.request({ url: 'https://example.com/api/getPublicKey', // 后端 API 获取公钥 method: 'GET', header: { 'content-type': 'application/json' } }); return res.data.publicKey; } // 使用 RSA 公钥加密 AES 密钥 async function encryptAesKey(aesKey, publicKeyPem) { const publicKey = await crypto.subtle.importKey( 'spki', str2ab(publicKeyPem), { name: 'RSA-OAEP', hash: { name: 'SHA-256' } }, false, ['encrypt'] ); const encryptedAesKey = await crypto.subtle.encrypt( { name: 'RSA-OAEP' }, publicKey, aesKey ); return encryptedAesKey; } // 使用 AES 加密数据 async function encryptData(data, aesKey) { const iv = crypto.getRandomValues(new Uint8Array(12)); // 生成 IV const encryptedData = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, aesKey, new TextEncoder().encode(data) ); return { encryptedData, iv }; } // 加密并发送数据 async function encryptAndSendData(data) { const publicKeyPem = await fetchPublicKey(); // 获取公钥 const aesKey = crypto.getRandomValues(new Uint8Array(32)); // 生成 AES 密钥 // 使用 AES 加密数据 const { encryptedData, iv } = await encryptData(data, aesKey); // 使用 RSA 加密 AES 密钥 const encryptedAesKey = await encryptAesKey(aesKey, publicKeyPem); // 将加密后的数据发送给后端 wx.request({ url: 'https://example.com/api/encrypt', // 后端 API 接口 method: 'POST', data: { encryptedAesKey: base64Encode(encryptedAesKey), encryptedData: base64Encode(encryptedData), iv: base64Encode(iv) }, success: function (res) { console.log('Data sent successfully:', res); }, fail: function (err) { console.error('Failed to send data:', err); } }); } // Base64 编码 function base64Encode(buffer) { return wx.arrayBufferToBase64(buffer); } // ArrayBuffer 转 Base64 编码 function str2ab(str) { const binaryString = wx.base64ToArrayBuffer(str); const length = binaryString.length; const bytes = new Uint8Array(length); for (let i = 0; i < length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; }
5.2 后端解密(PHP/Java/Node.js)
后端的解密逻辑与之前的 PHP、Java 和 Node.js 示例类似,解密 AES 密钥后,再使用 AES 解密数据。
6. React Native 加密方案
对于 React Native,你可以利用 react-native-crypto 进行加密操作。此方案与在 Web 或小程序中的加密方式类似,后端仍然使用 RSA 解密 AES 密钥,然后使用 AES 解密数据。
6.1 安装依赖
首先需要安装 react-native-crypto 和其他加密依赖:
npm install --save react-native-crypto npm install --save react-native-randombytes react-native link react-native-randombytes
6.2 React Native 加密示例
import crypto from 'react-native-crypto'; import { TextEncoder } from 'text-encoding'; // 获取 RSA 公钥 async function fetchPublicKey() { const response = await fetch('https://example.com/api/getPublicKey'); const data = await response.json(); return data.publicKey; } // 使用 RSA 公钥加密 AES 密钥 async function encryptAesKey(aesKey, publicKeyPem) { const publicKey = await crypto.subtle.importKey( 'spki', str2ab(publicKeyPem), { name: 'RSA-OAEP', hash: { name: 'SHA-256' } }, false, ['encrypt'] ); return crypto.subtle.encrypt({ name: 'RSA-OAEP' }, publicKey, aesKey); } // 使用 AES 加密数据 async function encryptData(data, aesKey) { const iv = crypto.getRandomValues(new Uint8Array(12)); const encryptedData = await crypto.subtle.encrypt( { name: 'AES-GCM', iv: iv }, aesKey, new TextEncoder().encode(data) ); return { encryptedData, iv }; } // 加密并发送数据 async function encryptAndSendData(data) { const publicKeyPem = await fetchPublicKey(); const aesKey = crypto.getRandomValues(new Uint8Array(32)); // 使用 AES 加密数据 const { encryptedData, iv } = await encryptData(data, aesKey); // 使用 RSA 加密 AES 密钥 const encryptedAesKey = await encryptAesKey(aesKey, publicKeyPem); // 发送加密数据到后端 fetch('https://example.com/api/encrypt', { method: 'POST', body: JSON.stringify({ encryptedAesKey: base64Encode(encryptedAesKey), encryptedData: base64Encode(encryptedData), iv: base64Encode(iv) }), headers: { 'Content-Type': 'application/json' } }) .then((response) => response.json()) .then((responseJson) => { console.log(responseJson); }) .catch((error) => { console.error(error); }); } // Base64 编码 function base64Encode(buffer) { return Buffer.from(buffer).toString('base64'); } function str2ab(str) { const binaryString = Buffer.from(str, 'base64').toString(); const length = binaryString.length; const bytes = new Uint8Array(length); for (let i = 0; i < length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes.buffer; }
这样,前后端的通信安全性得到了保障,数据传输过程中的隐私性、完整性和不可否认性都能得到充分保障。
发表评论 取消回复