小程序RSA、AES加密

1、下载

复制代码
npm i rsa-oaep-encryption crypto-js @types/crypto-js

2、AES 加解密方法

TypeScript 复制代码
import CryptoJS from 'crypto-js';

const aesKeys = "JMxEscETzuTGjsdwhDgqkHxAAqYWH/b0FWoQzM6gmLI="

export const generateAesKey = (length: number): Promise<any> => {
    return new Promise((resolve, reject) => {
        uni.getRandomValues({
            length,
            success: (res: any) => {
                const buffer = res.randomValues.buffer || res.randomValues;
                resolve(buffer)
            },
            fail: reject
        });
    });
};


/**
 * 在 uni-app 中加密数据(兼容微信小程序、H5、App)
 * @param data 任意可 JSON.stringify 的数据
 * @param aesKeyBase64 16字节 AES 密钥的 Base64 字符串(如 "abc123==")。可以调用 generateAesKey(32) 生成
 * @returns 格式:base64_iv:base64_ciphertext
 */
export const aesEncrypt = async (data: any, aesKeyBase64: ArrayBuffer): Promise<string> => {
    const plaintext = JSON.stringify(data);
    const aesKey = uni.arrayBufferToBase64(aesKeyBase64);
    const key = CryptoJS.enc.Base64.parse(aesKey);

    const ivBuffer = await generateAesKey(16)

    const ivWordArray = CryptoJS.lib.WordArray.create(new Uint8Array(ivBuffer));

    const encrypted = CryptoJS.AES.encrypt(plaintext, key, {
        iv: ivWordArray,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });

    // 转为 Base64 字符串
    const ivBase64 = CryptoJS.enc.Base64.stringify(ivWordArray);
    const ciphertextBase64 = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
    return `${ivBase64}:${ciphertextBase64}`;
};


// 解密
export const aesDecrypt = (encryptedData: string): string => {
    const parts = encryptedData.split(':');
    if (parts.length !== 2) {
        throw new Error('Invalid encrypted data format. Expected "iv:encrypted"');
    }
    const [ivBase64, encryptedBase64] = parts;
    const key = CryptoJS.enc.Base64.parse(aesKeys);
    const iv = CryptoJS.enc.Base64.parse(ivBase64);

    // 执行解密
    const decrypted = CryptoJS.AES.decrypt(
        encryptedBase64,
        key,
        {
            iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7,
        }
    );

    // 转换为 UTF-8 字符串
    const plaintext = decrypted.toString(CryptoJS.enc.Utf8);
    if (plaintext === '') {
        throw new Error('Decryption succeeded but result is empty (possibly wrong key)');
    }

    return plaintext;
}

3、RSA加密方法

TypeScript 复制代码
// ✅ 只导入需要的部分
import { importPublicKey, sha256 } from 'rsa-oaep-encryption';

const publicKeyPem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwaepXXet7q3Je2X/2BX8
bW3vkv8L+zvWOi53b8E70EKz+E2c6nXQXWXRtY96HebV3ShqrRHzztxPYNKTs8Jm
rM+sfix0X3jZj9ObKuFWcFJbJzXY5oS2Z7QnHSdMsmmXDGijnJ3HGHor26OmaWqc
eWw+PX6B3CTY90K2M9Y3B5K34WGpMmVTd4j32+ja6fEh/fgd/nLUDHZalAxraFxl
KLKz1tw8QIaMHQ8YbCUj8CBygJnLsWG1zi/0ASaScnqpPJpVWYGcDRjvBz199iYc
RAo+SDV8tvsKOtpBnaKX9JHTAOIFOU4IaITJdzyQoPhYsnrhlxDZ0OVFlvpC7Aig
yQIDAQAB
-----END PUBLIC KEY-----`;

export const rsaEncrypt = async (data: string): Promise<string> => {
    if (typeof data !== 'string') {
        throw new Error('RSA 加密输入必须是字符串');
    }
    const publicKey = await importPublicKey(publicKeyPem);

    const encryptedBytes = await publicKey.encrypt(data, sha256.create());

    return uni.arrayBufferToBase64(encryptedBytes);
};

4、使用

TypeScript 复制代码
import ajax, { AjaxRequestConfig } from 'uni-ajax';
import { aesDecrypt, aesEncrypt, generateAesKey } from './crypto/AES';
import { rsaEncrypt } from './crypto/RSA';

const instance = ajax.create({
    baseURL: 'http://localhost:8080/api',
});

instance.interceptors.request.use(
    async (config: AjaxRequestConfig) => {
        let userInfo = uni.getStorageSync("userInfo");
        if (userInfo && userInfo.token) {
            config.header['Authorization'] = 'Bearer ' + userInfo.token;
        }
        if (config.method == 'POST' && config.data) {
            const aesKey = await generateAesKey(32);
            config.data = {
                data: await aesEncrypt(config.data, aesKey),
                aesKey: await rsaEncrypt(uni.arrayBufferToBase64(aesKey))
            }
        }
        return config
    },
    error => {
        // 对请求错误做些什么
        console.log(error);
        return Promise.reject(error)
    }
)

// 添加响应拦截器
instance.interceptors.response.use(
    response => {
        response.data = JSON.parse(aesDecrypt(response.data))
        // 对响应数据做些什么
        if ((!response.config.responseType || response.config.responseType != 'arraybuffer') && (response.data.code != 200)) {
            uni.showToast({ title: response.data.message, icon: 'none' })
        }
        if (response.data.code == 401) {
            uni.removeStorageSync("userInfo")
            uni.navigateTo({ url: '/pages/login/index' })
        }
        return response
    },
    error => {
        // 对响应错误做些什么
        console.log(error);
        try {
        } catch (e) {
            console.log(e);
        }
        uni.showToast({ title: error?.data?.message ?? error.statusCode, icon: 'none' })
        return Promise.reject(error)
    }
)
export default instance
相关推荐
2501_916007472 小时前
苹果应用商店上架的系统逻辑,从产品开发到使用 开心上架 上架IPA 交付审核流程
android·ios·小程序·https·uni-app·iphone·webview
2501_916008893 小时前
Python抓包HTTPS详解:Wireshark、Fiddler、Charles等工具使用教程
python·ios·小程序·https·uni-app·wireshark·iphone
刻刻帝的海角3 小时前
uniapp引入qqmap-wx-jssdk实现微信小程序端获取用户当前位置
微信小程序·小程序·uni-app
2501_916008894 小时前
uni-app 上架到 App Store 的项目流程,构建、打包与使用开心上架(Appuploader)上传
android·ios·小程序·https·uni-app·iphone·webview
桐溪漂流4 小时前
微信小程序路由及 `EventChannel` 通信
微信小程序·小程序
00后程序员张4 小时前
怎么在 iOS 上架 App,从构建端到审核端的全流程协作解析
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_915918414 小时前
iOS 开发者工具全景指南,构建高效开发、调试与性能优化的多工具工作体系
android·ios·性能优化·小程序·uni-app·iphone·webview
多看书少吃饭17 小时前
小程序支持HTTP POST 流式接口吗?
网络协议·http·小程序
询问QQ:48773927820 小时前
CDB文件第0x2C位置存放温度阈值
小程序