加密方案

lishihuan大约 15 分钟

加密方案

场景:针对脚本中需要使用密码等数据的时候,比如数据库备份脚本,可以通过使用环境变量的方式进行加密

1. 环境变量的方式

您可以使用配置环境变量的方法,避免在服务中显式地配置密码,从而降低泄漏风险。

环境变量是操作系统中用于存储有关系统环境的信息的变量。您可以通过环境变量来配置密码,这样即使您的代码库被公开,密码也不会泄漏

参考:阿里大模型-通过环境变量配置API-KEYopen in new window

1.1 Linux系统

当您使用Linux系统(如Ubuntu、CentOS等)中的命令行添加DashScope的API-KEY为环境变量时,可以选择在当前会话添加临时性环境变量,或对当前用户添加永久性环境变量。

  • 添加临时性环境变量

    如果您仅想在当前会话中添加并使用临时性环境变量,您可以运行以下命令:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    export DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"
    

    您可以在当前会话运行以下命令检查环境变量是否生效:

    echo $DASHSCOPE_API_KEY
    
  • 对当前用户添加永久性环境变量

    如果您想对当前用户添加永久性环境变量,使得在该用户的新会话中也可以使用该环境变量,您可以把以下命令语句复制并添加到~/.bashrc文件中:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    export DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"
    

    或直接运行以下命令将上述命令语句添加到~/.bashrc中:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    echo "export DASHSCOPE_API_KEY='YOUR_DASHSCOPE_API_KEY'" >> ~/.bashrc
    

    添加完成后,您可以运行以下命令使得环境变量生效:

    source ~/.bashrc
    

    您可以新建立一个会话,运行以下命令检查环境变量是否生效:

    echo $DASHSCOPE_API_KEY
    

1.2 Linux系统

在Windows系统中,您可以使用CMD或PowerShell(推荐)运行命令。

1.2.1 通过CMD命令

当您使用CMD中的命令行添加DashScope的API-KEY为环境变量时,可以选择在当前会话添加临时性环境变量,或对当前用户添加永久性环境变量。

  • 添加临时性环境变量

    如果您仅想在当前会话中添加并使用临时性环境变量,您可以运行以下命令:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    set DASHSCOPE_API_KEY="YOUR_DASHSCOPE_API_KEY"
    

    您可以在当前会话运行以下命令检查环境变量是否生效:

    echo %DASHSCOPE_API_KEY%
    
  • 对当前用户添加永久性环境变量

    当您在CMD中需要为当前用户添加永久性环境变量时,您可以运行以下命令:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    setx DASHSCOPE_API_KEY "YOUR_DASHSCOPE_API_KEY"
    

    您可以新建立一个会话,运行以下命令检查环境变量是否生效:

    echo %DASHSCOPE_API_KEY%
    

1.2.1 通过PowerShell命令

当您使用PowerShell中的命令行添加DashScope的API-KEY为环境变量时,可以选择在当前会话添加临时性环境变量,或对当前用户添加永久性环境变量。

  • 添加临时性环境变量

    如果您仅想在当前会话中添加并使用临时性环境变量,您可以运行以下命令:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    $env:DASHSCOPE_API_KEY = "YOUR_DASHSCOPE_API_KEY"
    

    您可以在当前会话运行以下命令检查环境变量是否生效:

    echo $env:DASHSCOPE_API_KEY
    
  • 对当前用户添加永久性环境变量

    如果您在PowerShell中需要为当前用户添加永久性环境变量,您可以运行以下命令:

    # 用您的 DashScope API-KEY 代替 YOUR_DASHSCOPE_API_KEY
    [Environment]::SetEnvironmentVariable("DASHSCOPE_API_KEY", "YOUR_DASHSCOPE_API_KEY", [EnvironmentVariableTarget]::User)
    

    您可以新建立一个会话,运行以下命令检查环境变量是否生效:

    echo $env:DASHSCOPE_API_KEY
    

2. 前端实现

2.1 简易的方式实现

// 替换算法加密函数
function encryptText(text, shift) {
  let result = "";
  for (let i = 0; i < text.length; i++) {
    let charCode = text.charCodeAt(i);
    if (charCode >= 65 && charCode <= 90) {
      result += String.fromCharCode(((charCode - 65 + shift) % 26) + 65);
    } else if (charCode >= 97 && charCode <= 122) {
      result += String.fromCharCode(((charCode - 97 + shift) % 26) + 97);
    } else {
      result += text[i];
    }
  }
  return result;
}

// 替换算法解密函数
function decryptText(text, shift) {
  return encryptText(text, 26 - shift);
}

// 加密
function encrypt(data) {
  return encryptText(data, 3); // 使用偏移量为3进行加密
}
// 解密
function decrypt(decryptData) {
  return decryptText(decryptData, 3); // 使用偏移量为3进行解密
}

// 示例:生成密钥并加密数据
(() => {
  try {
    const orgData = 'lihuan@1234';
    console.log("原始数据:", orgData);
    const encrypted = encrypt(orgData);
    console.log("加密结果:", encrypted);
    const decryptedData = decrypt(encrypted);
    console.log("解密后的原始数据:", decryptedData);
  } catch (error) {
    // 错误处理
    console.log(error);
  }
})();

使用crypto库

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <!-- import CSS -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.9/theme-chalk/index.css" />
</head>

<body>
    <div>
        <div>{{info}}</div>
        <input type="button" value="按钮" @click="onClick()" />
        <!-- 其他 Vue 组件和代码 -->
    </div>

    <!-- import JavaScript -->
    <script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://cdn.staticfile.org/element-ui/2.15.9/index.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>
    <script src="encryption.js"></script>
    <script>
        let v = new Vue({
            el: "body>div",
            data: {
                info: "事件绑定"
            },
            mounted() {
                // this.getData()
            },
            methods: {
                onClick() {
                    alert("按钮点击了!");
                    // 在这里调用加密函数
                    const orgData = "lihuan@1234";
                    let key = "lishihuan";
                    console.log("原始数据:", orgData);
                    const encrypted = encryptText(orgData, key);
                    console.log("加密结果:", encrypted);
                    const decryptedData = decryptText(encrypted, key);
                    console.log("解密后的原始数据:", decryptedData);
                }
            }
        });
    </script>

</body>

</html>

通过 URL 的方式来引入 CryptoJS 库

目前测试无法在其他页面调用

// 异步加载 CryptoJS 库
function loadCryptoJS(url, callback) {
  var script = document.createElement("script");
  script.type = "text/javascript";

  if (script.readyState) {
    // For IE
    script.onreadystatechange = function () {
      if (script.readyState === "loaded" || script.readyState === "complete") {
        script.onreadystatechange = null;
        callback();
      }
    };
  } else {
    // For other browsers
    script.onload = function () {
      callback();
    };
  }

  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
}

// 加载 CryptoJS 库
loadCryptoJS(
  "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js",
  function () {
    console.log("CryptoJS library loaded.");

    // 加密函数
    window.encryptText = function (text, key) {
      return CryptoJS.AES.encrypt(text, key).toString();
    };

    // 解密函数
    window.decryptText = function (ciphertext, key) {
      let bytes = CryptoJS.AES.decrypt(ciphertext, key);
      return bytes.toString(CryptoJS.enc.Utf8);
    };

    console.log("Functions exposed globally.");

    // 待加密数据
    const orgData = "lihuan@1234";
    // 密钥
    let key = "lishihuan";
    console.log("原始数据:", orgData);
    const encrypted = encryptText(orgData, key);
    console.log("加密结果:", encrypted);
    const decryptedData = decryptText(encrypted, key);
    console.log("解密后的原始数据:", decryptedData);
  }
);

后端实现

  • 方式一
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.68</version>
        </dependency>
package com.example.demo.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Base64;

/**
 * @author lishihuan
 */
public class EncryptionUtils {

    public static void main(String[] args) {
        Security.addProvider(new BouncyCastleProvider());
        try {
            // 生成密钥
            String secretKey = "1234567890123456";
            // 加密字符串
            String originalString = "lishihuan";
            String encryptedString = encrypt(originalString, secretKey);
            // 解密字符串
            String decryptedString = decrypt(encryptedString, secretKey);
            System.out.println("原始字符串: " + originalString);
            System.out.println("加密后的字符串: " + encryptedString);
            System.out.println("解密后的字符串: " + decryptedString);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static SecretKey generateAESKey(String key) {
        byte[] keyBytes = key.getBytes();
        return new SecretKeySpec(keyBytes, "AES");
    }

    public static String encrypt(String plainText, String key) throws Exception {
        SecretKey secretKey = generateAESKey(key);
        Cipher cipher = Cipher.getInstance("AES", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    public static String decrypt(String encryptedString, String key) throws Exception {
        SecretKey secretKey = generateAESKey(key);
        Cipher cipher = Cipher.getInstance("AES", "BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedString);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }
}

调用

 Security.addProvider(new BouncyCastleProvider()); // 如果不加则出现 java.security.NoSuchProviderException: no such provider: BC
            System.out.println(EncryptionUtils.decrypt("c2l5MSAfD+Yrs7vVhWq52TFvLxlToxS75NkSKiTSODurjUgb6mq9d3JuM2vEYM5J", "1234567890123456"));
  • 方式二
package com.example.demo.utils;

import java.security.Key;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class EncryptionUtils {

    public static Key generateKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        return keyGenerator.generateKey();
    }

    public static String encrypt(String plainText, Key key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return byteArrayToHexString(encryptedBytes);
    }

    public static String decrypt(String encryptedText, Key key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);

        byte[] encryptedBytes = hexStringToByteArray(encryptedText);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }

    public static String byteArrayToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }

    public static void main(String[] args) throws Exception {
        String originalString = "sk-56767e1cbae3489ca2cc41bfdc2d4287";

        // 生成密钥
        Key key = generateKey();
        System.out.println("生成密钥: " + key);
        // 加密
        String encryptedString = encrypt(originalString, key);

        System.out.println("加密后的字符串: " + encryptedString);
        // 解密
        String decryptedString = decrypt(encryptedString, key);
        System.out.println("解密后的字符串: " + decryptedString);
    }
}

Base64 编码【可逆,简单】

如果需求是: “轻量级加密”或“可逆的简单混淆”,不要求高安全性,只是防止一眼看出内容。那我们可以使用Base64 编码,它在 JavaScript、Java 和 SQL(比如 MySQL)中都可以很好地编码和解码。

  • 不是真正的加密,但能有效隐藏原文
  • 无法通过简单观察识别内容
  • 无复杂运算,适合大数据量处理
  • 完整支持 UTF-8 字符(包括中文)
  • 支持特殊符号和数字

JavaScript 示例:

btoaatob 只能处理 Latin1(单字节)字符集,也就是普通的英文字符。

  • 如果你要处理包含中文或 emoji 的字符串,需要转成 UTF-8 后再编码。
// 编码
const encoded = btoa("HelloWorld");
console.log(encoded); // "SGVsbG9Xb3JsZA=="

// 解码
const decoded = atob(encoded);
console.log(decoded); // "HelloWorld"

//========================================# 针对中文 #========================================
function utf8ToBase64(str) {
  return btoa(unescape(encodeURIComponent(str)));
}

function base64ToUtf8(base64) {
  return decodeURIComponent(escape(atob(base64)));
}

const original = "你好,世界!";
const encoded = utf8ToBase64(original);
console.log("Encoded:", encoded);

const decoded = base64ToUtf8(encoded);
console.log("Decoded:", decoded);

Java 示例:

import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class Base64Example {
    public static void main(String[] args) {
        String original = "你好,世界!";

        // 编码(指定 UTF-8)
        String encoded = Base64.getEncoder().encodeToString(original.getBytes(StandardCharsets.UTF_8));
        System.out.println("Encoded: " + encoded);

        // 解码(指定 UTF-8)
        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String decoded = new String(decodedBytes, StandardCharsets.UTF_8);
        System.out.println("Decoded: " + decoded);
    }
}

MySQL 示例:

sql复制-- 编码
SELECT TO_BASE64('HelloWorld'); -- 返回:SGVsbG9Xb3JsZA==

-- 解码
SELECT FROM_BASE64('SGVsbG9Xb3JsZA=='); -- 返回:HelloWorld

🔒 如果你希望稍微“更难看懂一点”:

你可以在 Base64 的基础上再做一点点变形,比如:

  • 替换字符(如 = 换成 ~/ 换成 _ 等)
  • 前后加点干扰字符(如加个前缀/后缀再去解)

例如:

const original = "HelloWorld";
const encoded = btoa(original).replace(/=/g, '~').replace(/\//g, '_');
console.log(encoded); // 变形后的Base64

// 解码前替换回去
const cleaned = encoded.replace(/~/g, '=').replace(/_/g, '/');
const decoded = atob(cleaned);
console.log(decoded); // HelloWorld

二次 Base64 + 干扰字符插入

✅ 目标:

  1. 非明文传输(防止敏感数据被直观看出)
  2. 支持三端解码(JS、Java、MySQL)
  3. 加入干扰字符,防止一眼看出可还原
  4. 保持简单、易实现、轻量无依赖

🧠 加密逻辑说明:

最终加密串 = 插入干扰字符 ( base64( base64(原始字符串) ) )
例如原始字符串:Hello123
步骤1:base64 编码 => SGVsbG8xMjM=
步骤2:再次 base64 => U0dWc2JHODFNak09
步骤3:插入干扰 => 插入 2 个固定或随机字符,比如在第5位插入"X1",=> U0dWX1NiRzAxTWpNPT0=

✅ 前端 JavaScript 实现

function doubleBase64WithNoise(str) {
  const b64 = btoa(unescape(encodeURIComponent(str)));
  const doubleB64 = btoa(b64);
  // 插入干扰(固定插入也可以随机):
  return doubleB64.slice(0, 5) + "X1" + doubleB64.slice(5);
}

function decodeDoubleBase64WithNoise(noisedStr) {
  // 去除干扰
  const cleaned = noisedStr.slice(0, 5) + noisedStr.slice(7);
  const once = atob(cleaned);
  return decodeURIComponent(escape(atob(once)));
}

const encrypted = doubleBase64WithNoise("你好Hello123");
console.log("加密:", encrypted);

const decrypted = decodeDoubleBase64WithNoise(encrypted);
console.log("解密:", decrypted);

✅ Java 实现

import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class Encoder {
    public static String encode(String input) {
        String base64_1 = Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
        String base64_2 = Base64.getEncoder().encodeToString(base64_1.getBytes(StandardCharsets.UTF_8));
        return base64_2.substring(0, 5) + "X1" + base64_2.substring(5); // 插入干扰
    }

    public static String decode(String input) {
        String cleaned = input.substring(0, 5) + input.substring(7); // 去除干扰
        byte[] decoded1 = Base64.getDecoder().decode(cleaned);
        byte[] decoded2 = Base64.getDecoder().decode(new String(decoded1, StandardCharsets.UTF_8));
        return new String(decoded2, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String encoded = encode("你好Hello123");
        System.out.println("加密: " + encoded);

        String decoded = decode(encoded);
        System.out.println("解密: " + decoded);
    }
}

✅ MySQL 实现

自定义函数:

-- 加密函数:Base64两次 + 插入干扰字符(第6位插入'X1')
DELIMITER $$

CREATE FUNCTION double_base64_with_noise(input TEXT) RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE b64_1 TEXT;
  DECLARE b64_2 TEXT;
  DECLARE result TEXT;

  SET b64_1 = TO_BASE64(input);
  SET b64_2 = TO_BASE64(b64_1);
  SET result = CONCAT(LEFT(b64_2, 5), 'X1', SUBSTRING(b64_2, 6));
  RETURN result;
END$$

DELIMITER ;

解密函数:

DELIMITER $$

CREATE FUNCTION decode_double_base64_with_noise(input TEXT) RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE cleaned TEXT;
  DECLARE step1 TEXT;
  DECLARE result TEXT;

  SET cleaned = CONCAT(LEFT(input, 5), SUBSTRING(input, 8)); -- 去除干扰
  SET step1 = FROM_BASE64(cleaned);
  SET result = FROM_BASE64(step1);
  RETURN result;
END$$

DELIMITER ;

✅ 使用示例(MySQL):

SELECT double_base64_with_noise('你好Hello123');  -- 加密
SELECT decode_double_base64_with_noise('U0dWX1NiRzAxTWpNPT0=');  -- 解密

✅ 总结

环节方案特点
加密Base64 → Base64 → 插入干扰字符无外部依赖、快速
解密去干扰 → Base64 → Base64完整还原
安全性防止明文 + 不容易一眼看出非对称安全,不适合高保密场景
支持JS / Java / MySQL✅ 三端兼容

Base64 编码+加盐

✅ 简单解释「加盐」

“加盐”指在原始内容的基础上添加一段额外的、固定或可控的信息,让加密结果更难猜。

在我们的场景中,可以这样实现:

✳️ 加盐策略示例(统一三端):

步骤说明
1原始字符串进行 Base64 编码
2在特定位置(如中间或前后)插入一段固定“盐值”字符串
3作为最终加密结果传输
4解密时移除盐值,再 Base64 解码

✳️ 盐值策略建议:

类型示例是否固定推荐用途
固定盐值"s@lt123"最简单
动态前缀/后缀"timestamp" + base64对抗重放攻击(复杂)
插入特定位置"ABC" + base64.slice(0,5) + "XYZ" + base64.slice(5)易实现,适合你当前需求

🧪 JavaScript 示例(加盐版)

const SALT = 's@lt123';

function encryptWithSalt(str) {
  const base64 = btoa(unescape(encodeURIComponent(str)));
  const salted = base64.slice(0, 4) + SALT + base64.slice(4);  // 插入盐
  return salted;
}

function decryptWithSalt(saltedStr) {
  const base64 = saltedStr.replace(SALT, '');
  return decodeURIComponent(escape(atob(base64)));
}

const origin = "你好123abcABC";
const encrypted = encryptWithSalt(origin);
const decrypted = decryptWithSalt(encrypted);
console.log("加密后:", encrypted);
console.log("解密后:", decrypted);

☕ Java 对应实现

public class SaltedBase64 {
    private static final String SALT = "s@lt123";

    public static String encrypt(String input) {
        String base64 = java.util.Base64.getEncoder().encodeToString(input.getBytes(java.nio.charset.StandardCharsets.UTF_8));
        return base64.substring(0, 4) + SALT + base64.substring(4);
    }

    public static String decrypt(String input) {
        String unsalted = input.replace(SALT, "");
        byte[] decoded = java.util.Base64.getDecoder().decode(unsalted);
        return new String(decoded, java.nio.charset.StandardCharsets.UTF_8);
    }
}

🛢️ MySQL 对应方案(仅限固定盐值

-- 加密(Base64 + 加盐插入位置)
SELECT 
  CONCAT(SUBSTRING(base64, 1, 4), 's@lt123', SUBSTRING(base64, 5)) AS encrypted
FROM 
  (SELECT TO_BASE64('你好123abcABC') AS base64) t;

-- 解密(去除盐值 + 解码)
SELECT 
  FROM_BASE64(REPLACE('加密后的值', 's@lt123', '')) AS decrypted;

🔹 复杂一点也可以写成函数或触发器,但这就是最小实现成本的方式。


✅ 加盐 vs 字符替换对比

技术易用性安全性提升跨端支持解码复杂度
替换字符非常简单一点点简单
加盐稍复杂明显提升中等(需去盐)

✅ 总结建议

如果你推荐方案
要求极简Base64 + 替换(适合 URL 场景)
想再多混淆一点Base64 + 固定加盐(插入中间) ✅推荐
安全性要求高那就不能再用 Base64,应切换到 AES 等非对称加密

Base64+替换字符串+干扰

📌 1. 设计目标

  • 轻量级混淆:基于 Base64 编码,通过字符替换与插入干扰字符实现可逆加密。
  • 跨平台兼容:前端 JavaScript、后端 Java、数据库 MySQL 均可加解密互通。
  • 避免一眼识破:打破标准 Base64 特征,提升可读性混淆效果。

🔁 2. 加解密流程图


💻 3. 平台实现

🌐 JavaScript 实现

const CryptoConfig = {
  CHAR_MAP: {
    'A': 'q', 'B': 'w', 'C': 'e', 'D': 'r',
    '+': '-', '/': '_', '=': '.'
  },
  SALT: {
    length: 2,
    position: 4,
    generate: () => Math.random().toString(36).slice(2, 4)
  }
};

function pseudoEncrypt(str) {
  if (!str) return '';
  const base64 = btoa(unescape(encodeURIComponent(str)));
  const replaced = base64.replace(/[A-Z+\/=]/g, c => CryptoConfig.CHAR_MAP[c] || c);
  const salt = CryptoConfig.SALT.generate();
  return replaced.slice(0, CryptoConfig.SALT.position) + salt + replaced.slice(CryptoConfig.SALT.position);
}

function pseudoDecrypt(encryptedStr) {
  if (!encryptedStr) return '';
  const { position, length } = CryptoConfig.SALT;
  const cleaned = encryptedStr.slice(0, position) + encryptedStr.slice(position + length);
  const reverseMap = Object.fromEntries(Object.entries(CryptoConfig.CHAR_MAP).map(([k, v]) => [v, k]));
  const restored = cleaned.replace(/[qwer\-_\.]/g, c => reverseMap[c] || c);
  return decodeURIComponent(escape(atob(restored)));
}

☕ Java 实现

import java.util.*;
import java.util.stream.Collectors;
import java.nio.charset.StandardCharsets;

public class PseudoCrypto {
  private static final Map<Character, Character> CHAR_MAP = Map.of(
    'A', 'q', 'B', 'w', 'C', 'e', 'D', 'r',
    '+', '-', '/', '_', '=', '.'
  );
  private static final Map<Character, Character> REVERSE_MAP = CHAR_MAP.entrySet()
    .stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

  private static final int SALT_POSITION = 4;
  private static final int SALT_LENGTH = 2;

  public static String encrypt(String input) {
    if (input == null || input.isEmpty()) return "";
    String base64 = Base64.getEncoder().encodeToString(input.getBytes(StandardCharsets.UTF_8));
    String replaced = base64.chars()
      .mapToObj(c -> String.valueOf(CHAR_MAP.getOrDefault((char) c, (char) c)))
      .collect(Collectors.joining());
    String salt = generateSalt();
    return new StringBuilder(replaced).insert(SALT_POSITION, salt).toString();
  }

  public static String decrypt(String encrypted) {
    if (encrypted == null || encrypted.isEmpty()) return "";
    String cleaned = encrypted.substring(0, SALT_POSITION) + encrypted.substring(SALT_POSITION + SALT_LENGTH);
    String restored = cleaned.chars()
      .mapToObj(c -> String.valueOf(REVERSE_MAP.getOrDefault((char) c, (char) c)))
      .collect(Collectors.joining());
    return new String(Base64.getDecoder().decode(restored), StandardCharsets.UTF_8);
  }

  private static String generateSalt() {
    Random r = new Random();
    return r.ints(2, 0, 36)
      .mapToObj(i -> String.valueOf(i < 10 ? (char) ('0' + i) : (char) ('a' + i - 10)))
      .collect(Collectors.joining());
  }
}

🛢️ MySQL 实现

-- 需要 MySQL 5.6+
DELIMITER $$

CREATE FUNCTION fn_pseudo_encrypt(input TEXT)
RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE base64 TEXT;
  DECLARE replaced TEXT;
  DECLARE salt CHAR(2);

  IF input IS NULL THEN RETURN NULL; END IF;
  SET base64 = TO_BASE64(CAST(input AS BINARY));

  SET replaced = base64;
  SET replaced = REPLACE(replaced, 'A', 'q');
  SET replaced = REPLACE(replaced, 'B', 'w');
  SET replaced = REPLACE(replaced, 'C', 'e');
  SET replaced = REPLACE(replaced, 'D', 'r');
  SET replaced = REPLACE(replaced, '+', '-');
  SET replaced = REPLACE(replaced, '/', '_');
  SET replaced = REPLACE(replaced, '=', '.');

  SET salt = LOWER(HEX(RANDOM_BYTES(1))); -- 2位16进制随机盐
  RETURN CONCAT(SUBSTRING(replaced, 1, 4), salt, SUBSTRING(replaced, 5));
END$$

CREATE FUNCTION fn_pseudo_decrypt(encrypted TEXT)
RETURNS TEXT
DETERMINISTIC
BEGIN
  DECLARE cleaned TEXT;
  DECLARE restored TEXT;

  IF encrypted IS NULL THEN RETURN NULL; END IF;
  SET cleaned = CONCAT(SUBSTRING(encrypted, 1, 4), SUBSTRING(encrypted, 7));

  SET restored = cleaned;
  SET restored = REPLACE(restored, 'q', 'A');
  SET restored = REPLACE(restored, 'w', 'B');
  SET restored = REPLACE(restored, 'e', 'C');
  SET restored = REPLACE(restored, 'r', 'D');
  SET restored = REPLACE(restored, '-', '+');
  SET restored = REPLACE(restored, '_', '/');
  SET restored = REPLACE(restored, '.', '=');

  RETURN CAST(FROM_BASE64(restored) AS CHAR);
END$$

DELIMITER ;

✅ 4. 跨平台一致性保障表

项目JavaScriptJavaMySQL
Base64 编码btoa (UTF-8)Base64.getEncoder()TO_BASE64()
字符替换表{A→q, B→w, ...}Map<Character, Character>多次 REPLACE()
干扰字符Math.random() 2位Random().ints(2,0,36)HEX(RANDOM_BYTES(1))
插入位置index=4index=4SUBSTRING(1,4) + salt

🧪 5. 示例场景

📦 前端 → 后端解密

// JavaScript
const encrypted = pseudoEncrypt("/api/用户信息");
fetch(`/api?path=${encodeURIComponent(encrypted)}`);
// Java 控制器
@GetMapping("/api")
public String getPath(@RequestParam String path) {
  String realPath = PseudoCrypto.decrypt(path);
  return "你请求的路径是:" + realPath;
}

🗄️ MySQL 存储与查询

-- 加密插入
INSERT INTO user_data (path) VALUES (fn_pseudo_encrypt('/api/private'));

-- 查询解密
SELECT fn_pseudo_decrypt(path) AS real_path FROM user_data;

🔐 6. 安全说明

项目描述
🔓 不是真正加密本方案为可逆混淆算法,不适用于敏感数据保护
🔑 可视为“变体密钥”CHAR_MAP 相当于“算法密钥”,可定期变更
⚡ 轻量无依赖无需外部库,适合 URL、表单字段、数据库字段混淆
🧠 不建议用于传输密码、Token真正敏感信息请使用 AES、RSA 等标准加密

📎 附:测试用例示例

const str = "/demo/测试文件123.xlsx";
const enc = pseudoEncrypt(str);
const dec = pseudoDecrypt(enc);
console.log({ str, enc, dec }); // dec 应该与 str 完全一致
SELECT fn_pseudo_encrypt('/demo/测试文件123.xlsx') AS enc,
       fn_pseudo_decrypt(fn_pseudo_encrypt('/demo/测试文件123.xlsx')) AS dec;

前端url加密显示

考虑到有些页面需要带参数 路由跳转,防止用户篡改

通过自定义Vue RouterstringifyQueryparseQuery方法,实现URL参数的自动加密与解密

vue路由加密方案