二、加密基础原理:四大基石,缺一不可
说实话,很多SDK开发者最头疼的还不是接口怎么调,而是“到底该用哪种加密”。我见过不止一次,有人把AES密钥直接发给对方,还觉得万事大吉。嗯,这就是我们今天要讲的——四种基础原理,搞懂了,你就知道为什么字段级加密里,每个原则都不能乱用。
2.1 对称加密
对称加密,说白了就是加密和解密用同一把钥匙。就像你用一把锁锁门,同一把钥匙也能开门。最简单的例子是AES(高级加密标准),它在字段级加密里几乎无处不在。
// Node.js 示例:AES-256-GCM 加密
const crypto = require('crypto');
const key = crypto.randomBytes(32); // 256位密钥
const iv = crypto.randomBytes(16); // 初始化向量
function encrypt(plaintext, key, iv) {
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag().toString('hex');
return { encrypted, iv: iv.toString('hex'), authTag };
}
对称加密的优点是快,非常快。你想想看,AES硬件加速几乎在所有CPU上都支持,加解密一条64字节的字段,也就几十纳秒。缺点呢?密钥分发问题——你得想办法把密钥安全地送到对方手里。
| 模式 | 安全性 | 性能 | 适用场景 |
|---|---|---|---|
| AES-256-GCM | 高(认证加密) | 快(硬件加速) | 字段级加密首选 |
| AES-256-CBC | 中(需配合MAC) | 中 | 旧系统兼容 |
| ChaCha20-Poly1305 | 高 | 软件实现更快 | 移动端或低端CPU |
2.2 非对称加密
我经常把非对称加密称为“分手快乐加密”。你用公钥加密,只有私钥能解密——哪怕加密的人自己拿着公钥也解不开。RSA和ECC(椭圆曲线)是这里的主角。
在字段级加密SDK里,非对称加密一般不直接加密数据。为什么?太慢。RSA加密256字节,就要几毫秒,而AES加密1MB数据也就这么多时间。所以标准做法是混合加密:用RSA加密AES密钥,再用AES加密具体字段。
// 混合加密实用流程
function hybridEncrypt(plaintext, rsaPublicKey) {
const aesKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
// 1. AES加密字段
const { encrypted, authTag } = encryptAES(plaintext, aesKey, iv);
// 2. RSA加密AES密钥
const encryptedKey = crypto.publicEncrypt(rsaPublicKey, aesKey);
return {
ciphertext: encrypted,
encryptedKey: encryptedKey.toString('base64'),
iv: iv.toString('base64'),
authTag
};
}
我建议你记住:非对称加密不要用于加密大数据,它会让你后悔。我曾经接手过一个项目,某个同事直接拿RSA加密了整条用户记录,结果一次操作卡了3秒,整个系统就崩了。
2.3 哈希算法
哈希不是加密,这是第一原则。哈希是单向的,你从摘要无法反推出原文。字段级加密里,哈希主要用来做数据完整性校验和派生密钥。
你可能会问:“不做加密,为什么还要学它?”你想想看——你的SDK要校验数据是否被篡改,就需要哈希。你要从密码派生出AES密钥,也要用到哈希(其实是HKDF,但底层依赖哈希)。
// SHA-256 哈希示例
function hashField(data) {
return crypto.createHash('sha256').update(data).digest('hex');
}
// 注意:永远不要直接对密码做SHA-256,要用bcrypt/scrypt
常用的哈希算法:SHA-256足够安全(至少目前是的),SHA-1已经退役(我记得2017年Google就展示了碰撞攻击)。字段级加密里,我用的最多的是SHA-256和SHA-384。
2.4 密钥派生
密钥派生,说白了就是“从一个不那么随机的输入,生成一个真正随机的密钥”。比如你的用户密码是“abc123”,但AES-256需要256位熵,怎么办?用HKDF(基于HMAC的密钥派生函数)或pbkdf2。
我为什么单独强调这个?因为在SDK开发中,几乎所有密钥泄露问题都出在派生环节。有人直接把用户密码当AES密钥用,还有人从字符串“my-key”直接生成MD5当密钥——你想想看,这跟没加密有什么区别?
// HKDF 标准实现
function deriveKey(masterSecret, salt, info, keyLength) {
return crypto.hkdfSync('sha256', masterSecret, salt, info, keyLength);
}
// 使用示例
const userKey = deriveKey(
masterSecret, // 主密钥,必须从HSM或密钥管理服务获取
Buffer.from(userId), // 盐,每个用户不同
Buffer.from('field-encryption-v2'), // 上下文信息
32 // 输出32字节 = 256位
);
| 派生函数 | 用途 | 安全等级 | 我推荐的原因 |
|---|---|---|---|
| HKDF | 密钥派生(已有高熵密钥) | 高 | 标准可扩展,嵌入SDK的最佳选择 |
| PBKDF2 | 密码派生(低熵密码) | 中高 | 抗暴力破解,但需要高迭代次数 |
| 直接hash | 不要用 | 低 | 曾经有人用SHA-256直接派生,结果被彩虹表秒破 |
最后,我总结一个简单的对应关系:你开发SDK时,对称加密解决“怎么保护数据”,非对称加密解决“怎么传递密钥”,哈希解决“怎么验证没被改过”,密钥派生解决“怎么生成好密钥”。四者配合,才能构建一个真正可用的字段级加密方案。