小程序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
相关推荐
互联科技报13 小时前
2026小程序店铺装修模板怎么选?小程序店铺装修教程是什么?
小程序
凡科网小帆13 小时前
右以云小程序:零基础企业的高性价比数字化落地实录
小程序
棋宣14 小时前
微信小程序onShareAppMessage 分享-生命周期函数 在vue3中 组合式函数 hooks中不生效
微信小程序·小程序
2601_9579665314 小时前
抽卡机盲盒小程序怎么做?完整功能搭建与开发要点
小程序
wuyoula1 天前
全新多平台电商代付商城源码
开发语言·c++·ui·小程序·php源码
低代码布道师1 天前
微搭低代码MBA 培训管理系统实战 36——小程序端课程预约功能实现
低代码·小程序
万岳科技系统开发1 天前
小程序直播架构调整指南:H5嵌套模式的优化与替代方案
小程序·架构
Greg_Zhong1 天前
学习AI 工程师第 3 天:小程序中调用豆包模型,实现ai助手(打字机效果与流式输出)
小程序·ai工程师·小程序调用豆包实现ai助手
于先生吖2 天前
家政派单小程序定制厂家
大数据·小程序
00后程序员张2 天前
完整指南 iOS App上架到App Store的步骤详解
macos·ios·小程序·uni-app·objective-c·cocoa·iphone