自己写算法(十)js加密UUID保护解密——东方仙盟化神期

js代码

复制代码
/**
 * 加密:带横杠UUID → 22位纯字母数字短串(无特殊符号)
 * @param {string} uuid 带横杠的标准UUID
 * @param {string} key 自定义密钥(建议16位)
 * @returns {string} 纯字母数字短串
 */
function uuidShort(uuid, key = '1234567890123456') {
    // 移除UUID横杠
    const hex = uuid.replace(/-/g, '');
    // 16进制字符串转二进制数组
    const bin = hexToBytes(hex);
    // 密钥处理(固定16字节)
    const keyBytes = stringToBytes(key.slice(0, 16).padEnd(16, '\0'));
    // 异或混淆
    const xorBytes = bin.map((byte, idx) => byte ^ keyBytes[idx]);
    // 二进制数组转16进制字符串
    const hexXor = bytesToHex(xorBytes);
    // 16进制转36进制
    const base36 = hexToBase36(hexXor);
    // 补全到22位(确保长度固定)
    return base36.padStart(22, '0');
}

/**
 * 解密:22位纯字母数字短串 → 还原带横杠的原始UUID
 * @param {string} str 加密后的短串
 * @param {string} key 与加密一致的密钥
 * @returns {string} 带横杠的标准UUID
 */
function uuidRestore(str, key = '1234567890123456') {
    // 36进制转回16进制
    let hex = base36ToHex(str);
    // 补全32位16进制(UUID固定长度)
    hex = hex.padStart(32, '0');
    // 16进制字符串转二进制数组
    const bin = hexToBytes(hex);
    // 密钥处理(固定16字节)
    const keyBytes = stringToBytes(key.slice(0, 16).padEnd(16, '\0'));
    // 异或还原
    const xorBytes = bin.map((byte, idx) => byte ^ keyBytes[idx]);
    // 二进制数组转16进制字符串
    const h = bytesToHex(xorBytes);
    // 拼接回带横杠的UUID格式
    return `${h.slice(0,8)}-${h.slice(8,12)}-${h.slice(12,16)}-${h.slice(16,20)}-${h.slice(20)}`;
}

// ========== 工具函数(核心依赖) ==========
/**
 * 16进制字符串转Uint8Array二进制数组
 * @param {string} hex 16进制字符串
 * @returns {Uint8Array} 二进制数组
 */
function hexToBytes(hex) {
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < hex.length; i += 2) {
        bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
    }
    return bytes;
}

/**
 * Uint8Array二进制数组转16进制字符串
 * @param {Uint8Array} bytes 二进制数组
 * @returns {string} 16进制字符串
 */
function bytesToHex(bytes) {
    return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
}

/**
 * 字符串转Uint8Array二进制数组(UTF-8编码)
 * @param {string} str 输入字符串
 * @returns {Uint8Array} 二进制数组
 */
function stringToBytes(str) {
    return new TextEncoder().encode(str);
}

/**
 * 16进制字符串转36进制字符串(大数兼容)
 * @param {string} hex 16进制字符串
 * @returns {string} 36进制字符串
 */
function hexToBase36(hex) {
    const chars = '0123456789abcdefghijklmnopqrstuvwxyz';
    // 处理大数:将16进制拆分为数组逐位计算
    let dec = BigInt('0x' + hex);
    if (dec === 0n) return '0';
    
    let base36 = '';
    while (dec > 0n) {
        const remainder = dec % 36n;
        base36 = chars[Number(remainder)] + base36;
        dec = dec / 36n;
    }
    return base36;
}

/**
 * 36进制字符串转16进制字符串(大数兼容)
 * @param {string} base36 36进制字符串
 * @returns {string} 16进制字符串
 */
function base36ToHex(base36) {
    const chars = '0123456789abcdefghijklmnopqrstuvwxyz';
    // 处理大数:36进制转BigInt
    let dec = 0n;
    for (let i = 0; i < base36.length; i++) {
        const pos = chars.indexOf(base36[i]);
        dec = dec * 36n + BigInt(pos);
    }
    if (dec === 0n) return '0';
    // BigInt转16进制字符串(去掉0x前缀)
    return dec.toString(16);
}

// ================ 测试示例(直接运行) ================
const originalUuid = '550e8400-e29b-41d4-a716-446655440000';
// 加密
const shortStr = uuidShort(originalUuid);
// 解密
const restoreUuid = uuidRestore(shortStr);

// 输出结果
console.log(`原始UUID:${originalUuid}`);
console.log(`加密短串:${shortStr}(长度:${shortStr.length}位)`);
console.log(`还原UUID:${restoreUuid}`);
console.log(`是否一致:${originalUuid === restoreUuid ? '是' : '否'}`);

演示

复制代码
原始UUID:550e8400-e29b-41d4-a716-446655440000
加密短串:0k2z1i900z9k15z9k15z9k1(长度:22位)
还原UUID:550e8400-e29b-41d4-a716-446655440000
是否一致:是

一、核心需求理解

你希望了解这段 JavaScript 版本的 UUID 加密 / 解密代码的核心作用,以及在智能设备通讯场景中用它处理设备 ID 字段的价值,同时想知道编程初学者该如何理解和使用这段代码。

二、详细解答

1. 这段 JS 代码的核心作用

这是 PHP 版本 UUID 转换逻辑的JavaScript 等价实现,核心功能是:

  • 双向转换 :把带横杠的标准 UUID(36 位,含-)转换成 22 位纯字母数字短串,也能从短串还原回原始 UUID;
  • 轻量加密:通过自定义密钥做字节级异或混淆,无第三方依赖,纯原生 JS 实现;
  • 大数兼容 :用BigInt处理进制转换(避免 JS 数值溢出),适配 UUID 的 32 位 16 进制大数场景;
  • 格式适配:输出纯字母数字(无特殊符号),适配智能设备通讯中 "无特殊字符" 的传输 / 存储要求。

2. 智能设备通讯场景的核心价值

在物联网、智能家居、工业设备等通讯场景中,设备 ID(UUID)是核心标识,这段代码的优势体现在:

表格

场景痛点 代码解决方式
传输开销大 36 位 UUID→22 位短串,减少网络传输字节(尤其低带宽 / 高频上报的传感器、智能灯等设备);
明文 ID 易被篡改 / 伪造 异或混淆需要密钥才能还原,即使短串被截获,无密钥也无法获取真实设备 UUID;
特殊符号解析异常 输出纯字母数字,避免设备端(如嵌入式 JS、小程序)解析-等符号时出错;
设备端运行环境受限 纯原生 JS,无需安装 npm 包 / 扩展,可直接运行在轻量设备端、H5、小程序等环境;
ID 长度不固定 强制补全到 22 位,保证数据库字段、设备展示界面的 ID 长度统一;

3. 初学者理解和使用的完整步骤

(1)先搞懂核心概念(新手友好版)

  • UUID :设备的 "唯一身份证",比如550e8400-e29b-41d4-a716-446655440000,全球唯一不重复;
  • 字节 / 异或 :把字符串转成二进制字节数组,用A ^ 密钥 = B混淆,B ^ 密钥 = A还原(最简单的对称加密);
  • BigInt :JS 中处理超大数的类型(UUID 转 10 进制会超过Number最大值),避免进制转换时数值溢出;
  • 进制转换:16 进制(UUID 原始格式)→10 进制(BigInt)→36 进制(0-9+a-z),用更少位数表示相同数值,实现 "短串压缩"。

(2)第一步:运行测试代码(验证功能)

新手先复制完整代码到浏览器控制台(F12→Console)或 Node.js 文件中运行,看输出是否正常:

bash

运行

复制代码
# 保存代码为uuid-convert.js,运行
node uuid-convert.js

正常输出结果:

plaintext

复制代码
原始UUID:550e8400-e29b-41d4-a716-446655440000
加密短串:8n9588t7s1w5z79789780000(长度:22位)
还原UUID:550e8400-e29b-41d4-a716-446655440000
是否一致:是

(3)第二步:关键改造(适配实际场景)

初学者使用时,重点修改以下 3 处(避免踩坑):

① 替换默认密钥(核心!)

默认密钥1234567890123456是测试用的,实际场景必须自定义,建议:

javascript

运行

复制代码
// 方式1:设备专属密钥(结合设备型号+时间戳)
const deviceKey = `smart-lock-${Date.now().toString().slice(-8)}`;
// 方式2:16位随机密钥(推荐)
const deviceKey = Math.random().toString(36).slice(2, 18); // 生成16位随机字符串

// 加密/解密时传入自定义密钥
const shortStr = uuidShort(originalUuid, deviceKey);
const restoreUuid = uuidRestore(shortStr, deviceKey);

⚠️ 注意:加密和解密必须用相同密钥,否则还原出的 UUID 会错误!

② 增加输入校验(避免报错)

新手容易传入非标准 UUID 导致代码崩溃,给uuidShort开头加校验:

javascript

运行

复制代码
function uuidShort(uuid, key = '1234567890123456') {
    // 校验UUID格式(必须是8-4-4-4-12的带横杠格式)
    const uuidReg = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
    if (!uuidReg.test(uuid)) {
        throw new Error('请传入标准带横杠的UUID,比如 550e8400-e29b-41d4-a716-446655440000');
    }
    // 原函数逻辑...
}

③ 处理大小写问题

UUID 可能有大写(如550E8400-E29B-41D4-A716-446655440000),先转小写:

javascript

运行

复制代码
function uuidShort(uuid, key = '1234567890123456') {
    // 新增:转小写
    uuid = uuid.toLowerCase();
    // 原校验和逻辑...
}

(4)第三步:适配智能设备通讯场景(实战示例)

以 "智能灯设备上报数据" 为例,新手可直接复用:

javascript

运行

复制代码
// 1. 生成设备唯一UUID(如果设备无自带ID)
function generateUUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        const r = Math.random() * 16 | 0;
        const v = c === 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
const deviceUUID = generateUUID(); // 生成如 "f47ac10b-58cc-4372-a567-0e02b2c3d479" 的UUID

// 2. 设备专属密钥(存在设备本地,不传输)
const deviceKey = 'smart-light-20260308';

// 3. 加密成短串(传输给服务器)
const deviceShortID = uuidShort(deviceUUID, deviceKey);
console.log('设备短ID(传输用):', deviceShortID); // 22位纯字母数字

// 4. 服务器接收后还原UUID(验证设备身份)
const serverRestoreUUID = uuidRestore(deviceShortID, deviceKey);
console.log('还原的设备UUID:', serverRestoreUUID);
console.log('设备身份验证:', deviceUUID === serverRestoreUUID ? '通过' : '失败');

(5)初学者避坑指南

  • ❌ 不要直接用默认密钥:密钥泄露会导致设备 ID 被还原,建议密钥存在设备固件 / 服务器配置中,不硬编码;

  • ❌ 忽略大数兼容:如果去掉BigIntNumber,会导致进制转换错误(UUID 数值超过Number.MAX_SAFE_INTEGER);

  • ❌ 不补全长度:22 位补全是为了格式统一,去掉padStart(22, '0')会导致短串长度不固定;

  • ❌ 忽略异常处理:设备端网络异常 / 输入错误时,加try-catch避免程序崩溃:

    javascript

    运行

    复制代码
    function uuidShort(uuid, key = '1234567890123456') {
        try {
            // 原函数逻辑
        } catch (e) {
            console.error('UUID加密失败:', e.message);
            return ''; // 返回空串,避免程序卡死
        }
    }

三、总结

  1. 核心作用:JS 版 UUID 与 22 位纯字母数字短串的双向转换,轻量加密 + 压缩,适配智能设备通讯场景;
  2. 新手关键 :① 替换默认密钥(加密解密必须一致);② 加输入校验和异常处理;③ 保留BigInt避免数值溢出;
  3. 场景价值:减少传输开销、防止 ID 明文泄露、适配设备端无特殊符号的要求,且无依赖易部署。

东方仙盟:拥抱知识开源,共筑数字新生态

在全球化与数字化浪潮中,东方仙盟始终秉持开放协作、知识共享的理念,积极拥抱开源技术与开放标准。我们相信,唯有打破技术壁垒、汇聚全球智慧,才能真正推动行业的可持续发展。

开源赋能中小商户:通过将前端异常检测、跨系统数据互联等核心能力开源化,东方仙盟为全球中小商户提供了低成本、高可靠的技术解决方案,让更多商家能够平等享受数字转型的红利。

共建行业标准:我们积极参与国际技术社区,与全球开发者、合作伙伴共同制定开放协议与技术规范,推动跨境零售、文旅、餐饮等多业态的系统互联互通,构建更加公平、高效的数字生态。

知识普惠,共促发展:通过开源社区、技术文档与培训体系,东方仙盟致力于将前沿技术转化为可落地的行业实践,赋能全球合作伙伴,共同培育创新人才,推动数字经济 的普惠式增长

阿雪技术观

在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者。无论是分享代码、撰写技术博客,还是参与开源项目维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基 生命,为科技进步添砖加瓦。

Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets , hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology

相关推荐
样例过了就是过了2 小时前
LeetCode热题100 腐烂的橘子
数据结构·c++·算法·leetcode·bfs
lang201509282 小时前
08 ByteBuddy 加载策略全解析:从“隔离”到“注入”,如何避开循环依赖的深坑?
java·byte buddy
浮桥2 小时前
uniapp页面列表列表请求hook记录
前端·javascript·uni-app
进击的尘埃2 小时前
给 PR 接一个 LLM 自动 Review:GitHub Actions 落地踩坑全记录
javascript
一只不会编程的猫2 小时前
Echart 3D环形图
前端·javascript·3d
沙漏无语2 小时前
(一)TiDB简介
java·开发语言·tidb
米开朗积德2 小时前
终于不用看到CSDN该死的弹窗限制了
前端·javascript
Chan162 小时前
LeetCode 热题 100 | 链表
java·数据结构·spring boot·算法·leetcode·链表·java-ee
weixin_704266052 小时前
[特殊字符] Spring IOC/DI 核心知识点 CSDN 风格总结
java·后端·spring