非对称加密为什么不能直接拿公钥把整个大文件加密掉?

文章封面

做端到端聊天的时候,最开始的思路很简单:把对方公钥拿过来,把消息加密了发过去不就行了?

结果真做的时候发现不对:公钥加密是快,但加密的长度有限制。一条消息还能凑合,一张图片、一个大文件,公钥根本加不动。

那为什么微信、Telegram 这些端到端加密,大文件也能加密?它们是怎么做的?

一、先想清楚:为什么非对称加密不能直接加密大文件

先把最基础的问题想明白。

非对称加密,比如 RSA,它加密的原理是数学运算。这个运算本身就有长度限制。RSA 2048 位的密钥,一次最多也就加密两百多字节。你要加密一个 1MB 的文件,根本塞不进去。

加密方式加密速度能加密多大
非对称加密几百字节
对称加密任意大小

对称加密,比如 AES,速度快,加密多大文件都行。但对称加密有个问题:密钥怎么安全地传给对方?

这就矛盾了:非对称加密安全但慢,对称加密快但密钥传不过去。

那怎么办?

二、ECIES 到底是什么

ECIES 不是一种新的加密算法。它是一个组合方案:用非对称算法做密钥协商,生成一个共享密钥,然后用这个共享密钥做对称加密。

说白了就是:非对称加密负责"安全地把密钥传过去",对称加密负责"把真正的数据加密"。

完整流程是这样的:

  1. 双方各生成一对 ECC 密钥对;
  2. 用对方公钥和自己私钥做 Key Agreement,生成一个共享秘密;
  3. 用 KDF 从这个共享秘密派生一个对称密钥;
  4. 用这个对称密钥做 AES-GCM 加密;
  5. 把加密后的临时公钥和密文一起发过去。

这段代码解决什么问题: 完整 ECIES 加密流程。
文件: crypto/EciesManager.ets
用途: 端到端加密
接入位置: 聊天消息发送

import { cryptoFramework } from '@kit.CryptoArchitectureKit';

// 第一步:生成 ECC 密钥对
let ecc = cryptoFramework.createAsyKeyGenerator('ECC256');
let keyPair = await ecc.generateKeyPair();

// 第二步:Key Agreement 生成共享秘密
let keyAgreement = cryptoFramework.createKeyAgreement('ECC');
let sharedSecret = await keyAgreement.generateSecret(keyPair.priKey, peerPubKey);

// 第三步:KDF 派生对称密钥
let kdf = cryptoFramework.createKdfX963KDF('SHA256');
let keyMaterial = await kdf.deriveKey(sharedSecret, 32);

// 第四步:AES-GCM 对称加密
let cipher = cryptoFramework.createCipher('AES256-GCM');
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyMaterial, {
  iv: nonce,
  tagLen: 16
});
let cipherText = await cipher.doFinal(plainText);

系统架构图

三、每一层到底在干嘛

我们一层一层拆,看看为什么需要这么多层。

第一层:ECC 密钥对

为什么用 ECC 不用 RSA?因为 ECC 同样安全强度下,密钥更短,运算更快。ECC 256 位的安全强度,大概相当于 RSA 3072 位。手机上做加密,性能很重要,ECC 更合适。

第二层:Key Agreement

Key Agreement 是什么意思?就是:我用我的私钥和你的公钥,你用你的私钥和我的公钥,算出来一个一样的数。这个数只有我们俩知道,别人算不出来。

这就是共享秘密。它是通过数学运算出来的,不是传过去的。所以安全。

第三层:X963KDF

为什么有了共享秘密还要 KDF?因为共享秘密的长度、格式,不一定正好符合对称密钥的要求。

KDF 的作用就是:把这个共享秘密,派生成一个符合要求的对称密钥。还可以加一些别的信息进去,让密钥更随机更安全。

第四层:AES-GCM

为什么用 GCM 不用 ECB?因为 GCM 不仅加密,还做完整性校验。密文被改了,解密的时候直接就报错了。不用再单独做签名。

四、几个容易踩的坑

第一个坑:把 ECIES 当成"另一种 RSA"。它本质是混合加密,不是单一算法。

第二个坑:直接长期保存派生后的共享密钥。派生出来的密钥用完就该丢,不要存。

第三个坑:重复使用 IV/Nonce。AES-GCM 的 Nonce 重复了,安全性就崩了。每次加密都要新的 Nonce。

第四个坑:公钥来源不可信。公钥是谁的?怎么证明是对方的?这个信任链很重要。

第五个坑:加密和签名混为一谈。加密是防别人看,签名是防别人改。两件事。

五、解密失败怎么处理

解密失败的情况太多了:Nonce 不对、密钥不对、密文被改了、数据传错了。

正确的做法是:解密失败就直接报安全错误,不要猜是什么原因,不要降级处理。安全相关的东西,宁可失败也不要放行。

运行效果图

这次做端到端加密最大的体会是:ECIES 不是一个黑盒算法,是一套组合方案。非对称算法负责安全地传密钥,对称算法负责快速加密数据。每一层都有它存在的理由,不是为了凑数。

真正做的时候,最容易忽略的不是算法本身,而是周边的东西:Nonce 随机、密钥生命周期、公钥信任、错误处理。这些才是安全的关键。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐