Sanctum:密码学可否认的保险库系统(IPFS 存储)
发布: (2026年1月9日 GMT+8 07:03)
8 分钟阅读
原文: Dev.to
Source: Dev.to

🎭 问题:加密不足
传统的加密存储存在致命缺陷:
Attacker: "Give me the password or else."
You: "I don't have one."
Attacker: *checks encrypted file* "This is clearly encrypted. Try again."
你无法证明数据的不存在——直到现在。
✨ 解决方案:加密否认
Sanctum 创建 三个不可区分的层:
| 层 | 描述 |
|---|---|
| Decoy Layer | 无害内容(家庭照片、一个装有 200 美元的小钱包) |
| Hidden Layer | 真正的机密(举报者文档、主要加密钱包) |
| Panic Layer | 在胁迫下显示 “保险箱已删除” |
魔法是什么? 三者在密码学上完全相同。对手无法证明哪一层是真实的——甚至无法确定是否存在隐藏层。
🏗️ 架构:零信任设计
客户端加密流程
// 1. User creates vault with decoy + hidden content
const decoyBlob = encrypt(decoyContent, ''); // Empty passphrase
const hiddenBlob = encrypt(hiddenContent, deriveKey(passphrase));
// 2. XOR both layers (makes them indistinguishable)
const combined = xor(decoyBlob, hiddenBlob);
// 3. Upload to IPFS
const decoyCID = await ipfs.upload(decoyBlob);
const hiddenCID = await ipfs.upload(hiddenBlob);
// 4. Split‑key architecture
const keyA = randomBytes(32); // Stays in URL
const keyB = randomBytes(32); // Encrypted in database
const vaultURL = `https://sanctumvault.online/unlock/${vaultId}#${encode(keyA)}`;
技术栈
- Frontend: Next.js 15 + React + Web Crypto API
- Cryptography: XChaCha20‑Poly1305 + Argon2id(256 MB 内存,3 次迭代)
- Storage: IPFS via Pinata / Filebase(免费层)
- Database: Cloudflare D1(仅分键存储)
- Hosting: Cloudflare Pages(静态站点)
安全特性
// RAM‑only storage (no disk persistence)
class SecureStorage {
private keys = new Map();
store(key: string, value: Uint8Array): void {
this.keys.set(key, value);
// Auto‑clear after 5 minutes
setTimeout(() => this.wipe(key), 300_000);
}
wipe(key: string): void {
const data = this.keys.get(key);
if (data) {
data.fill(0); // Overwrite memory
this.keys.delete(key);
}
}
}
// Panic key: Double‑press Escape
let escapeCount = 0;
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
escapeCount++;
if (escapeCount === 2) {
wipeAllKeys();
window.location.href = '/';
}
setTimeout(() => (escapeCount = 0), 500);
}
});
🎯 实际使用案例
-
记者保护信息来源
Decoy: Published articles, public research notes Hidden: Confidential source documents, whistleblower communications Scenario: Device seized at border → reveal decoy, sources stay protected -
受压迫的加密资产持有者
Decoy: Small wallet with $200 ("this is all I have") Hidden: Main wallet with life savings Scenario: $5 wrench attack → hand over decoy wallet, real funds stay safe -
专制政权下的活动人士
Decoy: Personal photos, innocuous social media content Hidden: Protest coordination plans, evidence of government abuse Scenario: Police raid → show decoy layer, cannot prove hidden content exists
🛡️ 攻击防御
| Attack Vector | Defense |
|---|---|
| Physical Duress | 揭示诱饵密码短语;隐藏层保持不可区分。 |
| Disk Forensics | RAM‑only 存储;密钥从未写入磁盘;在标签关闭时自动擦除。 |
| Timing Analysis | 对所有操作随机延迟 500‑2000 ms。 |
| Blob Size Analysis | 填充至标准大小(1 KB、10 KB、100 KB、1 MB、10 MB、25 MB)。 |
| Brute Force | Argon2id 使用 256 MB 内存,使暴力破解在计算上不可行。 |
🚀 快速开始
对于用户
- 配置 Pinata 或 Filebase(免费 IPFS 提供商)
- 创建一个带有可选诱饵内容的保险库
- 为隐藏层设置密码短语
- 分享链接——只有你知道密码短语
对于开发者
# Clone repository
git clone https://github.com/Teycir/Sanctum.git
cd Sanctum
# Install dependencies
npm install
# Run development server
npm run dev
🔬 技术深度解析
为什么选择 XChaCha20‑Poly1305?
// AES‑GCM: 96‑bit nonce (collision risk after 2^48 encryptions)
// XChaCha20: 192‑bit nonce (collision risk after 2^96 encryptions)
import { xchacha20poly1305 } from '@noble/ciphers/chacha';
export function encrypt(
plaintext: Uint8Array,
key: Uint8Array
): Uint8Array {
const nonce = randomBytes(24); // 192‑bit nonce
const cipher = xchacha20poly1305(key, nonce);
return cipher.encrypt(plaintext);
}
XChaCha20‑Poly1305 提供了极其庞大的 nonce 空间,消除了 nonce 重用的顾虑,并在浏览器中提供了具有强大性能的认证加密。
// Encryption function
function encryptData(
plaintext: Uint8Array,
key: Uint8Array
): EncryptionResult {
const nonce = randomBytes(24); // 192‑bit nonce
const cipher = xchacha20poly1305(key, nonce);
const ciphertext = cipher.encrypt(plaintext);
return {
ciphertext,
nonce,
// Authenticated encryption tag (last 16 bytes)
authTag: ciphertext.slice(-16),
};
}
分割密钥架构
// KeyA: Stays in URL fragment (never sent to server)
// KeyB: Encrypted in database with vault‑specific key
const vaultKey = deriveKey(vaultId + salt);
const encryptedKeyB = encrypt(keyB, vaultKey);
// To decrypt IPFS CIDs:
const masterKey = xor(keyA, keyB);
const decoyCID = decrypt(encryptedDecoyCID, masterKey);
const hiddenCID = decrypt(encryptedHiddenCID, masterKey);
30‑Day Grace Period
-- Stage 1: Soft delete (mark inactive)
UPDATE vaults
SET is_active = 0
WHERE expires_at < NOW();
-
✅ 未收到任何:
- 国家安全信函(NSLs)
- FISA 法院命令
- 禁言令
- 实施后门的请求
-
✅ 架构保证:
- 零知识:无法解密用户保险库
- 无用户日志:不记录 IP 地址或元数据
- 无后门:所有代码均为开源
- 仅使用 RAM:密钥不进行持久化存储
🌐 为什么选择 IPFS?
传统云存储存在单点故障:
| Issue | Cloud Storage | IPFS |
|---|---|---|
| Centralized | Provider can be compelled to hand over data | Data replicated across many nodes |
| Censorable | Governments can block access | Content‑addressed (CID), not location‑based |
| Deletable | Provider can delete your data | Immutable – once uploaded, cannot be modified |
| Cost | Ongoing fees | Free tiers: Pinata (1 GB) + Filebase (5 GB) |
🚫 What Sanctum Is NOT
- ❌ 密码管理器 – 使用 KeePassXC / Bitwarden
- ❌ 备份解决方案 – IPFS 数据可能被取消固定
- ❌ 文件共享服务 – 链接是永久的,无法删除
- ❌ VPN – 使用 Tor 浏览器实现匿名
💡 经验教训
1. 仅 RAM 存储很困难
// ❌ WRONG: localStorage persists to disk
localStorage.setItem('key', encode(key));
// ✅ CORRECT: In‑memory only
const keyStore = new Map();
2. 时序攻击是真实存在的
// ❌ WRONG: Instant response reveals wrong passphrase
if (passphrase !== correctPassphrase) {
return { error: 'Invalid passphrase' };
}
// ✅ CORRECT: Constant‑time comparison + random delay
const isValid = timingSafeEqual(hash(passphrase), hash(correctPassphrase));
await sleep(randomInt(500, 2000));
return isValid ? { data } : { error: 'Invalid passphrase' };
3. 浏览器历史是泄漏源
// Vault URLs contain KeyA in fragment.
// Must clear from browser history.
if (window.history.replaceState) {
window.history.replaceState(null, '', '/unlock');
}
🔮 未来路线图
- Shamir Secret Sharing – 将金库访问权限拆分给多个人
- Dead Man’s Switch – 在长时间不活动后自动释放
- Steganography – 将金库隐藏在看似无害的图像中
- Hardware Key Support – 支持 YubiKey / Ledger 集成
- Mobile Apps – iOS / Android 支持生物识别解锁的移动应用
🙏 致谢
- VeraCrypt – 可实现合理否认的灵感
- Cloudflare Pages – 免费静态站点托管
- Pinata / Filebase – 免费 IPFS 固定服务
- @noble/ciphers – 已审计的密码学库
📜 许可证
Business Source License 1.1 – 免费用于非生产使用。生产使用在 4 年后需要商业许可证。
🔗 链接
- 现场演示:
- GitHub:
- 视频演示:
- 联系:
💬 讨论
你怎么看?你会为敏感数据使用加密否认性吗?你还能想象哪些其他用例?
在下方留下评论或在 GitHub 上打开 issue!
由 Teycir Ben Soltane 用 ❤️ 和 🔒 构建
免责声明:Sanctum 是满足合法隐私需求的工具。用户需自行遵守当地法律。开发者不支持任何非法活动。