自己写算法(十)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

相关推荐
未秃头的程序猿38 分钟前
Java 26正式发布!这3个新特性,让代码量直接减半
java·后端·面试
用户298698530141 小时前
Word 文档文本查找与替换的 Java 实现方案
java·后端
阿哉1 小时前
Nacos 服务发现源码:藏在背后的两套事件机制,90%的人只讲了一半
java
05Kevin1 小时前
lk每日冒险题--数据结构6.27
算法
默_笙1 小时前
🍞 我用 CSS 画了一个会转的 3D 立方体,同事以为我学了 Three.js(这节课真的很神奇,我很喜欢)
javascript
sarasuki1 小时前
JavaScript的对象、new的机制与原型包装类
javascript·后端
咖啡八杯1 小时前
GoF设计模式——命令模式
java·设计模式·架构
weedsfly1 小时前
JavaScript 事件流:彻底搞懂捕获、冒泡与事件委托
前端·javascript·react.js
AI人工智能_电脑小能手2 小时前
【大白话说Java面试题 第125题】【并发篇】第25题:说说 Java 线程的中断机制
java·后端·面试
Java内核笔记2 小时前
Spring Security 源码解析(六)无状态 JWT 实践:Session 共享与自定义过滤器
java·后端