遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
遇到一个网站 检查元素复制出来的 内容是 音颜值天板主 网页显示是 极品抖音颜值天花板主播小 movo 这种是怎么实现的呢?自定义一字体吗?那源数据是怎么录入的呢?
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
之前有加过我的直接可以联系我. 联系方式: R2F1ZGlfRm94 (base64)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>AES-256-CBC 加解密工具 | 在线对称加密</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: linear-gradient(145deg, #1a1e2b 0%, #2a2f3f 100%); min-height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Segoe UI', Roboto, system-ui, -apple-system, sans-serif; padding: 1.5rem; margin: 0; } .container { max-width: 750px; width: 100%; background: rgba(255, 255, 255, 0.07); backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); border-radius: 2.5rem; padding: 2.2rem 2rem; box-shadow: 0 30px 50px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.15); transition: all 0.2s ease; } h1 { text-align: center; font-weight: 500; font-size: 2.1rem; letter-spacing: 2px; color: #e0e5f0; margin-bottom: 0.3rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem; } h1 span { background: #3b82f6; color: white; font-size: 1rem; font-weight: 600; padding: 0.2rem 0.9rem; border-radius: 30px; letter-spacing: 0.5px; } .subtitle { text-align: center; color: #9aa4bf; margin-bottom: 2.2rem; font-size: 0.95rem; border-bottom: 1px dashed rgba(255,255,255,0.2); padding-bottom: 1.2rem; } .field { margin-bottom: 1.5rem; } label { display: flex; align-items: center; gap: 0.4rem; font-weight: 500; color: #cbd5e1; margin-bottom: 0.5rem; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.4px; } label i { font-style: normal; font-size: 1rem; } textarea, input { width: 100%; background: rgba(10, 15, 25, 0.7); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 1.2rem; padding: 0.9rem 1.2rem; font-size: 0.95rem; color: #f1f5f9; outline: none; transition: all 0.25s; font-family: 'Fira Code', 'JetBrains Mono', monospace; resize: vertical; backdrop-filter: blur(4px); } textarea:focus, input:focus { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.35); background: rgba(20, 25, 40, 0.8); } textarea { min-height: 100px; } .key-wrapper { display: flex; gap: 0.6rem; align-items: center; } .key-wrapper input { flex: 1; } .icon-btn { background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.25); color: #cbd5e1; padding: 0.7rem 1rem; border-radius: 1rem; font-size: 1.1rem; cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(8px); } .icon-btn:hover { background: rgba(59, 130, 246, 0.25); border-color: #3b82f6; color: white; } .actions { display: flex; gap: 1rem; margin: 2rem 0 1.2rem; flex-wrap: wrap; } .btn { flex: 1; min-width: 120px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.2); padding: 0.9rem 1.2rem; border-radius: 1.5rem; font-weight: 600; font-size: 1rem; color: #e2e8f0; cursor: pointer; backdrop-filter: blur(10px); transition: all 0.25s; display: flex; align-items: center; justify-content: center; gap: 0.4rem; letter-spacing: 0.5px; } .btn-encrypt { background: #2563eb; border-color: #3b82f6; box-shadow: 0 8px 18px -6px #1e3a8a; color: white; } .btn-encrypt:hover { background: #1d4ed8; border-color: #60a5fa; box-shadow: 0 10px 22px -6px #1e3a8a; } .btn-decrypt { background: #7c3aed; border-color: #8b5cf6; box-shadow: 0 8px 18px -6px #4c1d95; color: white; } .btn-decrypt:hover { background: #6d28d9; border-color: #a78bfa; } .btn-copy { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.25); } .btn-copy:hover { background: rgba(255, 255, 255, 0.18); border-color: #94a3b8; } .info-row { display: flex; justify-content: space-between; align-items: center; margin-top: 0.8rem; font-size: 0.8rem; color: #94a3b8; flex-wrap: wrap; gap: 0.5rem; } .badge { background: rgba(0,0,0,0.4); padding: 0.3rem 1rem; border-radius: 20px; backdrop-filter: blur(4px); } hr { border-color: rgba(255,255,255,0.1); margin: 1.2rem 0 0.8rem; } .footer-note { color: #7f8aa0; font-size: 0.8rem; text-align: center; } @media (max-width: 500px) { .container { padding: 1.5rem; } .actions { flex-direction: column; } } </style> </head> <body> <div class="container"> <h1> 🔐 AES-256-CBC <span>Crypto</span> </h1> <div class="subtitle">使用 Web Crypto API · 安全客户端加解密</div> <!-- 密钥输入 --> <div class="field"> <label><i>🔑</i> 密钥 (32字节 / 256位)</label> <div class="key-wrapper"> <input type="text" id="keyInput" placeholder="输入32字符密钥或点击生成随机密钥" autocomplete="off" spellcheck="false"> <button class="icon-btn" id="generateKeyBtn" title="生成随机256位密钥 (hex)">🎲</button> <button class="icon-btn" id="copyKeyBtn" title="复制密钥">📋</button> </div> <div class="info-row"> <span id="keyLengthIndicator">⚡ 长度: 0 / 32 字节</span> <span class="badge" id="keyStatus">未设置</span> </div> </div> <!-- 明文输入 --> <div class="field"> <label><i>📝</i> 明文 (Plaintext)</label> <textarea id="plaintextInput" placeholder="输入要加密的内容..."></textarea> </div> <!-- 密文输入 (Base64) --> <div class="field"> <label><i>🔒</i> 密文 (Base64格式)</label> <textarea id="ciphertextInput" placeholder="输入Base64密文进行解密..."></textarea> </div> <!-- 操作按钮组 --> <div class="actions"> <button class="btn btn-encrypt" id="encryptBtn">🔒 加密</button> <button class="btn btn-decrypt" id="decryptBtn">🔓 解密</button> <button class="btn btn-copy" id="copyCipherBtn">📋 复制密文</button> </div> <!-- 结果/状态信息 --> <div class="info-row" style="justify-content: center;"> <span id="operationStatus" class="badge" style="background: #1e293b;">⚪ 等待操作</span> </div> <hr> <div class="footer-note"> AES-256-CBC · 每次加密使用随机IV (16字节) · 密文格式: IV + 密文 (Base64) </div> </div> <script> (function() { // DOM 元素 const keyInput = document.getElementById('keyInput'); const plaintextInput = document.getElementById('plaintextInput'); const ciphertextInput = document.getElementById('ciphertextInput'); const encryptBtn = document.getElementById('encryptBtn'); const decryptBtn = document.getElementById('decryptBtn'); const generateKeyBtn = document.getElementById('generateKeyBtn'); const copyKeyBtn = document.getElementById('copyKeyBtn'); const copyCipherBtn = document.getElementById('copyCipherBtn'); const keyLengthIndicator = document.getElementById('keyLengthIndicator'); const keyStatus = document.getElementById('keyStatus'); const operationStatus = document.getElementById('operationStatus'); // ---------- 工具函数 ---------- function hexStringToUint8Array(hexString) { // 移除空格并确保小写 hexString = hexString.replace(/\s+/g, '').toLowerCase(); if (hexString.length % 2 !== 0) { throw new Error('十六进制字符串长度必须为偶数'); } const bytes = new Uint8Array(hexString.length / 2); for (let i = 0; i < hexString.length; i += 2) { const byte = parseInt(hexString.substr(i, 2), 16); if (isNaN(byte)) throw new Error('无效的十六进制字符'); bytes[i / 2] = byte; } return bytes; } function uint8ArrayToHexString(uint8Array) { return Array.from(uint8Array) .map(b => b.toString(16).padStart(2, '0')) .join(''); } // 生成随机16字节IV (用于CBC) function generateRandomIV() { return crypto.getRandomValues(new Uint8Array(16)); } // 将Base64字符串转换为Uint8Array function base64ToUint8Array(base64) { try { const binaryString = atob(base64); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; } catch (e) { throw new Error('Base64解码失败:无效的Base64字符串'); } } // 将Uint8Array转换为Base64 function uint8ArrayToBase64(uint8Array) { let binaryString = ''; uint8Array.forEach(byte => { binaryString += String.fromCharCode(byte); }); return btoa(binaryString); } // 验证并获取CryptoKey (AES-256-CBC) async function getCryptoKeyFromHex(hexKey) { if (!hexKey || hexKey.trim() === '') { throw new Error('密钥不能为空'); } const cleanHex = hexKey.replace(/\s+/g, ''); if (cleanHex.length !== 64) { throw new Error(`密钥长度必须为64个十六进制字符 (32字节),当前长度: ${cleanHex.length}`); } if (!/^[0-9a-fA-F]{64}$/.test(cleanHex)) { throw new Error('密钥包含无效的十六进制字符'); } const rawKey = hexStringToUint8Array(cleanHex); return await crypto.subtle.importKey( 'raw', rawKey, { name: 'AES-CBC' }, false, ['encrypt', 'decrypt'] ); } // 更新密钥状态显示 function updateKeyIndicator() { const rawValue = keyInput.value.replace(/\s+/g, ''); const byteLength = rawValue.length / 2; keyLengthIndicator.textContent = `⚡ 长度: ${byteLength} / 32 字节 (${rawValue.length} hex字符)`; if (rawValue.length === 0) { keyStatus.textContent = '未设置'; keyStatus.style.color = '#f87171'; } else if (rawValue.length === 64 && /^[0-9a-fA-F]{64}$/.test(rawValue)) { keyStatus.textContent = '✅ 有效256位密钥'; keyStatus.style.color = '#4ade80'; } else { keyStatus.textContent = '❌ 格式无效'; keyStatus.style.color = '#fbbf24'; } } // 生成随机256位密钥 (hex) function generateRandomHexKey() { const randomBytes = new Uint8Array(32); crypto.getRandomValues(randomBytes); return uint8ArrayToHexString(randomBytes); } // 设置操作状态 function setStatus(message, isError = false) { operationStatus.textContent = message; operationStatus.style.color = isError ? '#fca5a5' : '#e2e8f0'; if (isError) { operationStatus.style.background = '#7f1d1d'; } else { operationStatus.style.background = '#1e293b'; } } // ---------- 加密操作 ---------- async function performEncrypt() { try { const plaintext = plaintextInput.value; if (plaintext === '') { throw new Error('明文不能为空'); } const keyHex = keyInput.value.trim(); const cryptoKey = await getCryptoKeyFromHex(keyHex); // 生成随机IV const iv = generateRandomIV(); // 将明文编码为Uint8Array (UTF-8) const encoder = new TextEncoder(); const plaintextBytes = encoder.encode(plaintext); // 执行加密 const encryptedBuffer = await crypto.subtle.encrypt( { name: 'AES-CBC', iv: iv }, cryptoKey, plaintextBytes ); // 组合 IV + 密文 const encryptedBytes = new Uint8Array(encryptedBuffer); const combined = new Uint8Array(iv.length + encryptedBytes.length); combined.set(iv, 0); combined.set(encryptedBytes, iv.length); // 转换为Base64 const base64Cipher = uint8ArrayToBase64(combined); ciphertextInput.value = base64Cipher; setStatus('✅ 加密成功 (IV已前置)'); } catch (error) { console.error('加密失败:', error); setStatus(`加密失败: ${error.message}`, true); // 不清空密文框,但提示错误 } } // ---------- 解密操作 ---------- async function performDecrypt() { try { const cipherBase64 = ciphertextInput.value.trim(); if (cipherBase64 === '') { throw new Error('密文不能为空'); } const keyHex = keyInput.value.trim(); const cryptoKey = await getCryptoKeyFromHex(keyHex); // 解码Base64得到 IV + 密文 const combined = base64ToUint8Array(cipherBase64); // 检查最小长度:至少需要16字节IV + 16字节块 (AES块大小) if (combined.length < 32) { throw new Error('密文数据太短,必须包含16字节IV和至少一个加密块'); } // 提取IV (前16字节) const iv = combined.slice(0, 16); // 提取密文 (剩余部分) const cipherData = combined.slice(16); // 执行解密 const decryptedBuffer = await crypto.subtle.decrypt( { name: 'AES-CBC', iv: iv }, cryptoKey, cipherData ); // 解码为UTF-8字符串 const decoder = new TextDecoder(); const plaintext = decoder.decode(decryptedBuffer); plaintextInput.value = plaintext; setStatus('🔓 解密成功'); } catch (error) { console.error('解密失败:', error); setStatus(`解密失败: ${error.message}`, true); // 解密失败不修改明文框 } } // 复制到剪贴板 async function copyToClipboard(text, elementDescription = '内容') { if (!text || text.trim() === '') { setStatus(`⚠️ 没有可复制的${elementDescription}`, true); return; } try { await navigator.clipboard.writeText(text); setStatus(`📋 已复制${elementDescription}到剪贴板`); } catch (err) { setStatus(`❌ 复制失败: ${err.message}`, true); } } // ---------- 事件绑定 ---------- keyInput.addEventListener('input', updateKeyIndicator); generateKeyBtn.addEventListener('click', () => { const newKey = generateRandomHexKey(); keyInput.value = newKey; updateKeyIndicator(); setStatus('🎲 已生成随机256位密钥'); }); copyKeyBtn.addEventListener('click', () => { const keyValue = keyInput.value.trim(); copyToClipboard(keyValue, '密钥'); }); encryptBtn.addEventListener('click', performEncrypt); decryptBtn.addEventListener('click', performDecrypt); copyCipherBtn.addEventListener('click', () => { const cipherValue = ciphertextInput.value.trim(); copyToClipboard(cipherValue, '密文'); }); // 可选:回车快捷操作(在密文框按Ctrl+Enter尝试解密,明文框Ctrl+Enter加密) plaintextInput.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); performEncrypt(); } }); ciphertextInput.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'Enter') { e.preventDefault(); performDecrypt(); } }); // 初始化状态显示 updateKeyIndicator(); // 设置一个默认示例密钥(方便测试,但提示用户可自行生成) // 使用一个固定的示例密钥 (32字节 hex) : "a1b2c3d4e5f6071829aabbccddeeff00112233445566778899aabbccddeeff" const defaultKey = "a1b2c3d4e5f6071829aabbccddeeff00112233445566778899aabbccddeeff"; if (keyInput.value === '') { keyInput.value = defaultKey; updateKeyIndicator(); setStatus('ℹ️ 已加载示例密钥,建议生成随机密钥'); } })(); </script> </body> </html> 在线使用 a5a3e081.pinme.dev AES-256-CBC 加解密工具 | 在线对称加密 6 个帖子 - 3 位参与者 阅读完整话题