使用 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;
}

这样,前后端的通信安全性得到了保障,数据传输过程中的隐私性、完整性和不可否认性都能得到充分保障。

点赞(0)

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部