登录 立即注册

首页 > 绿虎论坛 > 软件开发 > 编程语言 > HTML/CSS/JS (发帖)

标题: 写了一个单网页加密工具 可以离线使用生成密文或二维码

作者: @Ta

时间: 03-26 21:50发布,03-26 22:01修改

点击: 3160

适用场景:

  • 想备份软件助记词 ,但不敢直接写在纸上,怕被偷窥。
  • 需要保存软件恢复密钥 ,但明文存储总担心泄露风险。
  • 重要密码或隐私文本 ,既想长期保存,又怕数字文件存网盘不安全或者被泄露。

传统加密工具往往需要联网、依赖复杂软件,而今天,我写了一款基于浏览器的离线工具,无需安装、不依赖网络(想完全离线可以自己下载单页跟js文件存手机,未来想打包成apk,在线使用应该也没问题,代码完全公开,也可以加载页面后断网使用),通过AES算法加密任意文本,并直接生成可打印的二维码,将敏感信息“凝固”为一张纸或一张图。

对于保存好的二维码或打印好的二维码,可以直接使用手机扫码或者选择二维码图片识别,并输入根密码即可解密

演示:https://cway.top/ai/jm


[隐藏样式|查看源码]


『回复列表(6|隐藏机器人聊天)』

1.
层主 @咯叽 于 2025-04-01 22:36 删除了该楼层。
(/@Ta/2025-03-26 22:40//
被锁定
)

2.

@咯叽,可以,像hu60可以用ubb插入html,可以输入密码解码出原html再在页面显示

(/@Ta/2025-03-26 23:38//)

3.

源码呢。来个

(/@Ta/2025-03-27 19:27//)

4. @穴儿,源码不就在这

HTML代码

(/@Ta/2025-03-27 20:07//)

5.

@,666666

(/@Ta/2025-03-27 20:45//)

6.
<textarea id="inputText" placeholder="请输入要加密或此工具加密后要解密的文本"></textarea><input type="password" id="password" placeholder="此处必须输入密码"><button onclick="encrypt()">加密</button><button onclick="decrypt()">解密</button><textarea id="outputText" placeholder="加密或解密后的结果"></textarea><script>async function generateKey(password, salt) {const encoder = new TextEncoder();const passwordData = encoder.encode(password);const iterations = 500000;const keyMaterial = await window.crypto.subtle.importKey('raw',passwordData,{ name: 'PBKDF2' },false,['deriveKey']);return await window.crypto.subtle.deriveKey({name: "PBKDF2",salt: salt,iterations: iterations,hash: "SHA-384"},keyMaterial,{ name: "AES-GCM", length: 256 },false,["encrypt", "decrypt"]);}function arrayBufferToBase64(buffer) {return btoa(String.fromCharCode(...new Uint8Array(buffer)));}function base64ToArrayBuffer(base64) {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.buffer;}async function encrypt() {try {const inputText = document.getElementById('inputText').value;const password = document.getElementById('password').value;if (!inputText || !password) {alert('请输入文本和密码');return;}const encoder = new TextEncoder();const iv = window.crypto.getRandomValues(new Uint8Array(12));const salt = window.crypto.getRandomValues(new Uint8Array(32));const key = await generateKey(password, salt);const plaintext = encoder.encode(inputText);const ciphertext = await window.crypto.subtle.encrypt({name: "AES-GCM",iv: iv},key,plaintext);const combined = new Uint8Array(12 + 32 + ciphertext.byteLength);combined.set(iv, 0);combined.set(new Uint8Array(salt), 12);combined.set(new Uint8Array(ciphertext), 44);document.getElementById('outputText').value = arrayBufferToBase64(combined.buffer);} catch (error) {console.error('加密错误:', error);alert('加密失败: ' + error.message);}}async function decrypt() {try {const inputText = document.getElementById('inputText').value;const password = document.getElementById('password').value;if (!inputText || !password) {alert('请输入文本和密码');return;}const combined = new Uint8Array(base64ToArrayBuffer(inputText));const iv = combined.slice(0, 12);const salt = combined.slice(12, 44);const ciphertext = combined.slice(44);const key = await generateKey(password, salt);const decrypted = await window.crypto.subtle.decrypt({name: "AES-GCM",iv: iv},key,ciphertext);const decoder = new TextDecoder();document.getElementById('outputText').value = decoder.decode(decrypted);} catch (error) {console.error('解密错误', error);alert('解密失败'// + error.message
);}}

//按钮增加
const textareas = document.querySelectorAll('textarea');const confirmAndExecute = (action, confirmMessage) => {const confirmResult = window.confirm(confirmMessage);if (confirmResult) {action();}};const isUTF8 = (buffer) => {try {const decoder = new TextDecoder('utf-8', { fatal: true });decoder.decode(buffer);return true;} catch (e) {return false;}};textareas.forEach((textarea) => {const buttonContainer = document.createElement('span');buttonContainer.style.display = 'flex';buttonContainer.style.justifyContent = 'center';buttonContainer.style.opacity = '';const copyButton = document.createElement('button');copyButton.textContent = '复制';copyButton.addEventListener('click', () => {confirmAndExecute(() => {textarea.select();document.execCommand('copy');document.getSelection().removeAllRanges();}, '确认要复制该输入框内容吗?');});buttonContainer.appendChild(copyButton);const downloadButton = document.createElement('button');downloadButton.textContent = '下载';downloadButton.addEventListener('click', () => {const blob = new Blob([textarea.value], { type: 'text/plain' });const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = '输入框utf-8编码.txt';a.click();URL.revokeObjectURL(url);});buttonContainer.appendChild(downloadButton);const clearButton = document.createElement('button');clearButton.textContent = '清空';clearButton.addEventListener('click', () => {confirmAndExecute(() => {textarea.value = '';}, '确认要清空该输入框内容吗?');});buttonContainer.appendChild(clearButton);const fileButton = document.createElement('button');fileButton.textContent = '选择文件';fileButton.addEventListener('click', () => {const input = document.createElement('input');input.type = 'file';input.accept = 'text/*';input.onchange = (e) => {const file = e.target.files[0];if (!file) return;const reader = new FileReader();reader.onload = (event) => {const buffer = event.target.result;if (isUTF8(new Uint8Array(buffer))) {textarea.value = new TextDecoder('utf-8').decode(new Uint8Array(buffer));} else {alert('文件不是UTF-8编码,无法加载。');}};reader.readAsArrayBuffer(file);};input.click();});buttonContainer.appendChild(fileButton);textarea.parentNode.insertBefore(buttonContainer, textarea.nextSibling);});
</script>

HTML代码

基于Web Crypto API,采用AES-GCM-256算法配合动态PBKDF2-SHA384密钥派生(含32字节随机salt和12字节随机IV),通过将salt作为附加认证数据(AAD)并实现500000次动态迭代的密码哈希,通过 Uint8Array 和 ArrayBuffer 的相关操作来处理二进制数据,避免直接使用 btoa/atob。

通过按钮增加可添加utf8文件和导出直接文本。

我觉得密码部分应该也添加个上传文件,这样可以超大型密码。

好像还可以增强,就是每一次增东西都挺麻烦担心机器人丢了芝麻
你的描述已经是一个非常强大的加密方案,结合了现代密码学的最佳实践。不过,仍有几个可以进一步增强安全性和可靠性的方向:

1. 密钥管理增强
- 密钥轮换机制:  
  定期通过HKDF派生新密钥,避免长期使用同一密钥材料。

2. 算法参数优化
- AES-GCM-256:  
  当前选择已足够安全,但可考虑:
  - 强制验证密文长度(防止截断攻击)。
  - 显式设置authenticationTagLength为16字节(默认值,但显式声明更可靠)。
- PBKDF2-SHA384:  
  - 迭代次数动态化(如根据设备性能自适应调整,但需确保下限≥100,000)。

3. 数据完整性强化
- AAD扩展:  
  除salt外,可将时间戳、协议版本等元数据加入AAD,防止重放/版本混淆攻击。
- 双校验机制:  
  在AES-GCM的认证标签之外,额外用HMAC-SHA3对密文做二次验证。

4. 侧信道防御
- 恒定时间操作:  
  确保所有加密操作(如比较认证标签)使用恒定时间函数,避免时序攻击。
  - 内存清理:  
  加密后立即清零敏感数据(如派生密钥的ArrayBuffer):

5. 错误处理与日志
- 安全异常:  
  捕获所有SubtleCrypto错误并统一返回模糊化消息(如"Invalid operation"),避免泄露信息。
- 审计日志:  
  记录操作元数据(如时间、操作类型)但不记录任何密钥/明文数据。

6. 协议层增强
- 前向保密:  
  结合ECDH密钥交换(如X25519)生成临时会话密钥,即使主密钥泄露也无法解密历史数据。
- 量子抵抗:  
  若需长期保护,可混合使用Kyber-768(后量子KEM)与现有方案。

最终建议
  遵循NIST SP 800-63B和OWASP Cryptographic Cheat Sheet的最新要求。

你的方案已远超一般Web应用的安全需求,上述建议适用于对安全性有极端要求的场景(如金融/军事系统)。实际应用中需权衡安全性与性能成本。
(/@Ta/2025-06-05 23:22//)

回复需要登录

6月6日 06:30 星期五

本站由hu60wap6驱动

备案号: 京ICP备18041936号-1