马上注册,结交更多好友,享用更多功能,让你轻松玩转小K网。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
零宽字符隐写工具(可以定制字并隐藏任何字)
我的需求介绍:为什么要有这个工具,因为之前我弄个RSA加密的激活码太长,怕用户看的麻烦,所以我只好做了个这个零宽工具,让客户有更好的体验
原理就是利用零宽字符(Zero Width Characters,如 \u200B)不可见的特性,将秘密信息二进制化后隐藏在普通文本(宿主文本)中。复制出来的文本看起来很正常,但粘贴到解密区就能看到隐藏内容。整个工具封装在一个 HTML 文件中,使用了 Tailwind CSS 做 UI,支持自动跟随系统的暗黑模式。
工具特点:- 纯本地运行:所有逻辑都在浏览器完成,不上传服务器,安全隐私。
- 单文件:HTML/CSS/JS 合一,双击即用,方便部署或收藏。
- UI 美观:适配移动端和桌面端,支持深色/浅色模式切换。
- 一键复制:交互体验优化,支持一键复制加密结果。
使用场景:- 在公开论坛/群聊传递秘密信息。
- 给文字添加“数字水印”。
- 单纯觉得好玩,整蛊朋友(比如表面发一句“你好”,实际隐藏了“V我50”)。
目前测试情况: QQ全端支持,微信手机端不支持发送零宽,只接受和复制粘贴
源码:代码直接保存为 .html 文件,用浏览器打开即可
注意:该工具不是加密工具,只是将字变成了零宽大小,专业的零宽加密工具找风导的
零宽字符隐写工具(可以定制字并隐藏任何字)
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Zero Text - 零宽文本加密</title>
- <!-- 引入 Tailwind CSS (CDN) -->
- <script src="https://cdn.tailwindcss.com"></script>
- <!-- 配置 Tailwind 主题 -->
- <script>
- tailwind.config = {
- darkMode: 'class',
- theme: {
- extend: {
- colors: {
- primary: '#3b82f6', // blue-500
- primaryHover: '#2563eb', // blue-600
- darkBg: '#0f172a', // slate-900
- darkCard: '#1e293b', // slate-800
- },
- boxShadow: {
- 'glow': '0 0 15px rgba(59, 130, 246, 0.5)',
- }
- }
- }
- }
- </script>
- <style>
- /* 自定义滚动条样式 */
- ::-webkit-scrollbar {
- width: 8px;
- height: 8px;
- }
- ::-webkit-scrollbar-track {
- background: transparent;
- }
- ::-webkit-scrollbar-thumb {
- background: #cbd5e1;
- border-radius: 4px;
- }
- .dark ::-webkit-scrollbar-thumb {
- background: #475569;
- }
- ::-webkit-scrollbar-thumb:hover {
- background: #94a3b8;
- }
-
- /* 动画过渡 */
- .transition-all-300 {
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
- }
-
- /* 文本域聚焦样式 */
- .input-group:focus-within label {
- color: #3b82f6;
- }
- </style>
- </head>
- <body class="min-h-screen bg-gray-100 dark:bg-darkBg text-slate-800 dark:text-slate-200 transition-colors duration-300 flex flex-col items-center py-8 px-4 font-sans">
-
- <!-- 顶部标题栏 -->
- <header class="w-full max-w-5xl flex justify-between items-center mb-8">
- <div class="flex items-center gap-3">
- <div class="bg-blue-600 p-2 rounded-lg shadow-lg text-white">
- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
- </div>
- <div>
- <h1 class="text-2xl font-bold tracking-tight text-slate-900 dark:text-white">Zero Text</h1>
- <p class="text-xs text-slate-500 dark:text-slate-400">零宽字符隐写工具</p>
- </div>
- </div>
-
- <div class="flex items-center gap-4">
- <!-- GitHub Link -->
- <a href="https://www.52pojie.cn/" target="_blank" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-slate-700 transition-colors text-slate-600 dark:text-slate-400" title="View on GitHub">
- <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
- </a>
- <!-- Theme Toggle -->
- <button id="themeToggle" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-slate-700 transition-colors text-slate-600 dark:text-slate-400">
- <svg id="iconSun" class="hidden w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
- <svg id="iconMoon" class="block w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path></svg>
- </button>
- </div>
- </header>
-
- <!-- 主容器 -->
- <main class="w-full max-w-5xl grid grid-cols-1 md:grid-cols-2 gap-8">
-
- <!-- 左侧:加密卡片 -->
- <section class="bg-white dark:bg-darkCard rounded-2xl shadow-xl overflow-hidden border border-gray-200 dark:border-slate-700 flex flex-col h-full transition-all-300 hover:shadow-2xl">
- <div class="bg-gradient-to-r from-blue-500 to-blue-600 p-4">
- <h2 class="text-white font-semibold flex items-center gap-2">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg>
- 加密 / 隐藏信息
- </h2>
- </div>
-
- <div class="p-6 flex flex-col gap-5 flex-1">
- <!-- 宿主文本 -->
- <div class="input-group">
- <label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
- 1. 宿主文本(表面显示的内容)
- </label>
- <textarea id="carrierText" class="w-full h-24 p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="例如:今天天气真不错,要不要一起去喝咖啡?"></textarea>
- </div>
-
- <!-- 秘密文本 -->
- <div class="input-group">
- <label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
- 2. 秘密文本(要隐藏的内容)
- </label>
- <textarea id="secretText" class="w-full h-24 p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="例如:你好鸭"></textarea>
- </div>
-
- <!-- 按钮区 -->
- <button id="encryptBtn" class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-xl shadow-lg shadow-blue-500/30 transition-all active:scale-[0.98] flex items-center justify-center gap-2 group">
- <span class="group-hover:scale-110 transition-transform">🔒</span>
- 生成加密文本
- </button>
-
- <!-- 结果区 -->
- <div class="relative mt-2">
- <label class="block text-xs font-semibold uppercase text-slate-400 dark:text-slate-500 mb-1 tracking-wider">
- 加密结果
- </label>
- <div class="relative group">
- <div id="encryptResult" class="w-full h-28 p-3 pr-12 rounded-lg border-2 border-dashed border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 text-sm text-slate-500 dark:text-slate-400 break-all overflow-y-auto font-mono transition-colors group-hover:border-blue-300 dark:group-hover:border-slate-500">
- (等待生成...)
- </div>
-
- <!-- 复制按钮 (悬浮) -->
- <button id="copyEncryptBtn" disabled class="absolute top-2 right-2 p-2 bg-white dark:bg-slate-700 border border-gray-200 dark:border-slate-600 rounded-md shadow-sm text-slate-500 hover:text-blue-600 hover:border-blue-200 dark:hover:text-blue-400 transition-all disabled:opacity-50 disabled:cursor-not-allowed group-hover:opacity-100" title="复制结果">
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
- </button>
- </div>
- </div>
- </div>
- </section>
-
- <!-- 右侧:解密卡片 -->
- <section class="bg-white dark:bg-darkCard rounded-2xl shadow-xl overflow-hidden border border-gray-200 dark:border-slate-700 flex flex-col h-full transition-all-300 hover:shadow-2xl">
- <div class="bg-gradient-to-r from-emerald-500 to-emerald-600 p-4">
- <h2 class="text-white font-semibold flex items-center gap-2">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>
- 解密 / 提取信息
- </h2>
- </div>
-
- <div class="p-6 flex flex-col gap-5 flex-1">
- <!-- 解密输入 -->
- <div class="input-group">
- <label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
- 粘贴包含零宽字符的文本
- </label>
- <textarea id="decodeInput" class="w-full h-[220px] p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-emerald-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="在此处粘贴..."></textarea>
- </div>
-
- <!-- 按钮区 -->
- <button id="decryptBtn" class="w-full py-3 bg-emerald-600 hover:bg-emerald-700 text-white font-semibold rounded-xl shadow-lg shadow-emerald-500/30 transition-all active:scale-[0.98] flex items-center justify-center gap-2 group">
- <span class="group-hover:scale-110 transition-transform">🔓</span>
- 解密提取内容
- </button>
-
- <!-- 结果区 -->
- <div class="relative mt-2 flex-1 flex flex-col">
- <label class="block text-xs font-semibold uppercase text-slate-400 dark:text-slate-500 mb-1 tracking-wider">
- 还原结果
- </label>
- <div class="relative group flex-1">
- <div id="decryptResult" class="w-full h-full min-h-[112px] p-3 pr-12 rounded-lg border-2 border-dashed border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 text-sm text-slate-500 dark:text-slate-400 break-all overflow-y-auto font-mono transition-colors group-hover:border-emerald-300 dark:group-hover:border-slate-500">
- (等待解密...)
- </div>
-
- <!-- 复制按钮 (悬浮) -->
- <button id="copyDecryptBtn" disabled class="absolute top-2 right-2 p-2 bg-white dark:bg-slate-700 border border-gray-200 dark:border-slate-600 rounded-md shadow-sm text-slate-500 hover:text-emerald-600 hover:border-emerald-200 dark:hover:text-emerald-400 transition-all disabled:opacity-50 disabled:cursor-not-allowed group-hover:opacity-100" title="复制结果">
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
- </button>
- </div>
- </div>
- </div>
- </section>
-
- </main>
-
- <footer class="mt-8 text-center text-xs text-slate-400 dark:text-slate-500">
- <p>🔒 所有加密/解密均在本地浏览器完成,不会上传数据</p>
- </footer>
-
- <!-- JavaScript 逻辑 -->
- <script>
- // ==========================================
- // 核心加密解密逻辑 (保持不变)
- // ==========================================
- const ZWC = { 0: '\u200B', 1: '\u200C' };
-
- function textToBinary(text) {
- const utf8 = new TextEncoder().encode(text);
- return Array.from(utf8)
- .map((b) => b.toString(2).padStart(8, '0'))
- .join('');
- }
-
- function binaryToText(bin) {
- const bytesMatch = bin.match(/.{8}/g);
- if (!bytesMatch) return '';
- const bytes = bytesMatch.map((b) => parseInt(b, 2));
- return new TextDecoder().decode(new Uint8Array(bytes));
- }
-
- function binaryToZWC(bin) {
- return bin.split('').map((b) => ZWC[Number(b)]).join('');
- }
-
- function zwcToBinary(zwcText) {
- return [...zwcText]
- .map((c) => (c === '\u200B' ? '0' : c === '\u200C' ? '1' : ''))
- .join('');
- }
-
- function insertZWCIntoCarrier(carrier, zwc) {
- if (!carrier) carrier = " ";
- const mid = Math.floor(carrier.length / 2);
- return carrier.slice(0, mid) + zwc + carrier.slice(mid);
- }
-
- // ==========================================
- // DOM 操作
- // ==========================================
-
- document.addEventListener('DOMContentLoaded', () => {
- const carrierInput = document.getElementById('carrierText');
- const secretInput = document.getElementById('secretText');
- const encryptBtn = document.getElementById('encryptBtn');
- const encryptResultDiv = document.getElementById('encryptResult');
- const copyEncryptBtn = document.getElementById('copyEncryptBtn');
-
- const decodeInput = document.getElementById('decodeInput');
- const decryptBtn = document.getElementById('decryptBtn');
- const decryptResultDiv = document.getElementById('decryptResult');
- const copyDecryptBtn = document.getElementById('copyDecryptBtn');
-
- const themeToggle = document.getElementById('themeToggle');
- const iconSun = document.getElementById('iconSun');
- const iconMoon = document.getElementById('iconMoon');
-
- let encryptedValue = '';
- let decryptedValue = '';
-
- // 辅助函数:更新结果框状态
- function updateResultBox(element, text, isPlaceholder = false) {
- element.innerText = text;
- if (isPlaceholder) {
- element.classList.add('text-slate-500', 'dark:text-slate-400');
- element.classList.remove('text-slate-800', 'dark:text-slate-200');
- } else {
- element.classList.remove('text-slate-500', 'dark:text-slate-400');
- element.classList.add('text-slate-800', 'dark:text-slate-200');
- }
- }
-
- // --- 加密 ---
- encryptBtn.addEventListener('click', () => {
- const secret = secretInput.value;
- const carrier = carrierInput.value;
-
- if (!secret) {
- // 简单的震动反馈或边框红色提示
- secretInput.classList.add('ring-2', 'ring-red-500');
- setTimeout(() => secretInput.classList.remove('ring-2', 'ring-red-500'), 500);
- return;
- }
-
- try {
- const binary = textToBinary(secret);
- const zwcText = binaryToZWC(binary);
- const final = insertZWCIntoCarrier(carrier || 'Processing...', zwcText);
-
- encryptedValue = final;
- updateResultBox(encryptResultDiv, final);
- copyEncryptBtn.disabled = false;
-
- // 视觉反馈:稍微闪烁一下结果框
- encryptResultDiv.classList.add('bg-blue-50', 'dark:bg-blue-900/20');
- setTimeout(() => encryptResultDiv.classList.remove('bg-blue-50', 'dark:bg-blue-900/20'), 300);
- } catch (e) {
- console.error(e);
- alert('加密失败');
- }
- });
-
- // --- 解密 ---
- decryptBtn.addEventListener('click', () => {
- const input = decodeInput.value;
- if (!input) return;
-
- try {
- const zwcChars = [...input]
- .filter((c) => c === '\u200B' || c === '\u200C')
- .join('');
-
- if (!zwcChars) {
- updateResultBox(decryptResultDiv, "⚠️ 未检测到隐藏信息", true);
- decryptedValue = "";
- copyDecryptBtn.disabled = true;
- return;
- }
-
- const binary = zwcToBinary(zwcChars);
- const text = binaryToText(binary);
-
- decryptedValue = text;
- updateResultBox(decryptResultDiv, text);
- copyDecryptBtn.disabled = false;
-
- // 视觉反馈
- decryptResultDiv.classList.add('bg-emerald-50', 'dark:bg-emerald-900/20');
- setTimeout(() => decryptResultDiv.classList.remove('bg-emerald-50', 'dark:bg-emerald-900/20'), 300);
-
- } catch (e) {
- console.error(e);
- updateResultBox(decryptResultDiv, "❌ 解密失败:数据损坏", true);
- }
- });
-
- // --- 复制 ---
- async function copyToClipboard(text, btnElement) {
- if (!text) return;
- try {
- await navigator.clipboard.writeText(text);
- const originalIcon = btnElement.innerHTML;
-
- // 切换为打钩图标
- btnElement.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-green-500"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
-
- setTimeout(() => {
- btnElement.innerHTML = originalIcon;
- }, 1500);
- } catch (err) {
- alert('复制失败');
- }
- }
-
- copyEncryptBtn.addEventListener('click', () => {
- copyToClipboard(encryptedValue, copyEncryptBtn);
- });
-
- copyDecryptBtn.addEventListener('click', () => {
- copyToClipboard(decryptedValue, copyDecryptBtn);
- });
-
- // --- 深色模式 ---
- function updateThemeIcon(isDark) {
- if (isDark) {
- iconSun.classList.remove('hidden');
- iconMoon.classList.add('hidden');
- } else {
- iconSun.classList.add('hidden');
- iconMoon.classList.remove('hidden');
- }
- }
-
- function initTheme() {
- const stored = localStorage.getItem('theme');
- const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
-
- if (stored === 'dark' || (!stored && prefersDark)) {
- document.documentElement.classList.add('dark');
- updateThemeIcon(true);
- } else {
- document.documentElement.classList.remove('dark');
- updateThemeIcon(false);
- }
- }
-
- themeToggle.addEventListener('click', () => {
- const isDark = document.documentElement.classList.toggle('dark');
- localStorage.setItem('theme', isDark ? 'dark' : 'light');
- updateThemeIcon(isDark);
- });
-
- initTheme();
- });
- </script>
- </body>
- </html>
复制代码
|