首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
非对称加密公式详解:RSA、ECC、ElGamal密钥生成与签名验签
📅 2026/10/17 1:28:37
✍️ 爱科研究院
👁 阅读 3,247
搞密码学相关开发或者面试时被问过非对称加密细节的朋友应该都有过这种体验RSA、ECC这些词张口就来但真让你把公钥加密、私钥解密、签名验签的公式完整写出来能写对的人不多。很多人背过 ( c m^e \bmod n )但对 ( e )、( d )、( n ) 到底怎么选出来的( \lambda(n) ) 和 ( \phi(n) ) 哪个该用ECC 里的点加、点乘到底怎么算心里没底。这篇文章就把常见公钥算法的加解密公式一次性讲透。覆盖 RSA、ElGamal、ECC含 ECDH、ECDSA、ECIES三套主流体系从密钥生成、加解密、签名验签的完整公式链到每个参数背后的安全约束和工程取舍再到实际开发中容易踩的坑全部拆开揉碎。适合刚接触非对称加密的开发者、准备面试的候选人以及需要在工程里选型或排查加解密问题的从业者。读完你至少能自己手推一遍密钥生成过程也能说清楚为什么某些参数是红线。1. 公钥算法加解密的核心思路与通用模型1.1 为什么统一看“密钥生成、加密解密、签名验签”三件套公钥算法虽然数学形态各不相同但几乎所有方案都可以拆成三件事密钥生成、加解密、签名验签。密钥生成做的事是构造一个有“陷门”的数学结构——陷门信息就是私钥公开的信息就是公钥。加密方拿公钥把消息“锁”进这个结构里解密方用私钥当作钥匙打开。签名则是反过来私钥生成一段别人无法伪造的“印记”公钥负责验证印记是否真的对应某条消息。用生活化的类比公钥就像一个上了锁的邮箱任何人都能把信投进去加密但只有持有私钥的人能打开邮箱取信解密。签名则是私钥持有者给文件盖一个私章别人用公钥验证章是真的。公式本身并不难难点在于理解每一步为什么要有这些参数、每个参数的大小和关系决定了什么安全等级、哪些参数一旦选错会导致算法直接被攻破。RSA 的数学地基是大整数分解难题ElGamal 的地基是有限域上的离散对数难题ECC 的地基是椭圆曲线群上的离散对数难题。这三个难题的共同点是正向计算很容易逆向计算极难。正因为这个“易算难逆”的不对称性才撑起了非对称加密的整个安全模型。1.2 三种常见公钥算法的“数学地基”与选型逻辑RSA 是最早被广泛商用的公钥算法公式直观开发者接受度最高但密钥长度要求长推荐 2048 位以上加解密性能相对慢。ElGamal 在国内实际工程中不如 RSA 和 ECC 常见但它是理解离散对数体系的最佳入门而且它的变体如 Cramer-Shoup和一些隐私计算协议里经常出现。ECC 是目前综合性价比最高的选择——256 位左右的密钥能提供与 3072 位 RSA 相当的安全强度密钥短、运算快、带宽占用低适合移动端、物联网、区块链等场景。选型时不能只看“哪个更安全”还要看生态、标准合规要求、性能预算和现有系统的兼容性。比如很多政企系统要求使用 RSA-SHA256 签名金融行业对 ECC 曲线参数有明确推荐标准。我在实际项目里见过团队为了“追新”直接上 ECC结果业务系统里对接的老网关只支持 RSA最后不得不做双算法兼容成本和风险都翻倍。选型的第一原则是先看对接方和合规要求支持什么再谈技术偏好。2. RSA 加解密公式拆解与实操参数2.1 RSA 密钥生成的完整公式链RSA 密钥生成的第一步是选择两个大素数 ( p ) 和 ( q )。这两个素数要求随机且长度接近实际工程中通常用 Miller-Rabin 素性检测来生成。计算出 ( n p \times q )( n ) 的二进制长度就是 RSA 的密钥长度比如 2048 位。接下来关键的一步是计算 ( \phi(n) (p-1)(q-1) )也就是欧拉函数——在 1 到 ( n ) 之间与 ( n ) 互素的整数个数。然后选择一个公钥指数 ( e )要求 ( 1 e \phi(n) ) 且 ( \gcd(e, \phi(n)) 1 )。工程上 ( e ) 经常取 65537即 ( 2^{16}1 )它是个素数计算速度快且保证与绝大多数 ( \phi(n) ) 互素。接着用扩展欧几里得算法求出私钥指数 ( d )满足 ( e \times d \equiv 1 \pmod{\phi(n)} )。这个 ( d ) 就是私钥的核心一旦泄露任何人都能还原明文。需要特别说明一个容易混的点现代 RSA 标准如 PKCS#1 v2.2实际使用的是卡迈克尔函数 ( \lambda(n) \operatorname{lcm}(p-1, q-1) ) 而不是 ( \phi(n) )。用 ( \lambda(n) ) 求出的 ( d ) 可能更小而且 ( \phi(n) ) 求出的 ( d ) 也满足加密解密互逆因为 ( \phi(n) ) 是 ( \lambda(n) ) 的整数倍。绝大多数教程用 ( \phi(n) ) 是为了推导简单实现时两种都能跑通但按标准实现建议使用 ( \lambda(n) )。2.2 RSA 加解密与签名验签公式及常见陷阱RSA 加密公式是 ( c m^e \bmod n )解密公式是 ( m c^d \bmod n )。其中 ( m ) 是明文经过填充后的整数表示( c ) 是密文整数。为什么能还原因为 ( m^{ed} \equiv m \pmod{n} )这个等式由 ( ed \equiv 1 \pmod{\lambda(n)} ) 保证。这里有个严重的工程陷阱不能拿原始消息直接做模幂运算。直接 RSA教科书式 RSA存在大量攻击面比如选择密文攻击、小指数攻击、共模攻击。实际实现必须使用填充方案比如 RSA-OAEP最优非对称加密填充或 PKCS#1 v1.5。OAEP 会把消息加盐、加哈希、做两轮 Feistel 置换再送入模幂运算这样同一明文每次加密的密文都不同抵抗已知明文攻击的能力大幅提升。RSA 签名公式是 ( s m^d \bmod n )验签公式是 ( m s^e \bmod n )。签名其实是用私钥做“加密”用公钥做“解密”。但真实实现里不会直接签原始消息的整数表示而是先对消息做哈希再对哈希值做填充如 EMSA-PKCS1-v1_5 或 PSS最后才做模幂。PSS 是随机化填充每次签名结果不同安全性优于传统 v1.5新系统建议直接用 RSA-PSS。我遇到过最典型的 RSA 问题是两端明明用同一个密钥对加密解密却失败。排查下来发现是填充模式不匹配——一方用 OAEP-SHA256另一方用 PKCS#1 v1.5结果密文长度和结构对不上。另一个高发问题是密钥长度不匹配一端生成的是 1024 位密钥另一端按 2048 位解析直接报错。RSA 这块的教训就一句话参数协商比算法本身更容易出问题密钥位数、填充模式、哈希算法必须在两端的配置里完全一致。3. ElGamal 加解密公式与关键工程要点3.1 ElGamal 密钥生成与加解密公式ElGamal 算法的数学基础是有限域 ( \mathbb{Z}_p ) 上的离散对数问题。密钥生成时选择一个大的素数 ( p )再选择一个生成元 ( g )( g ) 是模 ( p ) 乘法群的一个生成元实际中常选一个阶为大素数的元素。私钥 ( x ) 是从 ( [1, p-2] ) 中随机选的整数公钥是 ( y g^x \bmod p )。安全性的核心在于给定 ( y, g, p )求 ( x ) 是困难的。加密过程有个与众不同的地方它需要临时选取一个随机数 ( k )且 ( 1 \le k \le p-2 )( k ) 与 ( p-1 ) 互素。密文是一对值( c_1 g^k \bmod p )( c_2 m \times y^k \bmod p )。解密时计算 ( m c_2 \times (c_1^x)^{-1} \bmod p )。为什么能还原因为 ( c_1^x g^{kx} )而 ( y^k g^{xk} )两者相等所以 ( c_2 ) 除以 ( c_1^x ) 就能恢复出 ( m )。这个公式展现了一个特别重要的特性密文是概率性的。同一个明文 ( m )每次加密用不同的 ( k )得到的 ( c_1, c_2 ) 完全不同但解密结果一致。这在密码学上叫语义安全意思是敌手无法通过观察密文推断出明文之间的任何关系。相比之下教科书式 RSA 是确定性加密同一明文两次加密密文一样这在很多场景下是缺陷。3.2 随机数与密文膨胀的工程处理ElGamal 在实际工程中最大的痛点有三个随机数质量、密文膨胀、参数验证。随机数 ( k ) 是生命线。如果 ( k ) 被泄露攻击者能用 ( m c_2 \times y^{-k} ) 直接恢复明文如果两次加密用了同一个 ( k )且攻击者已知其中一条明文另一条明文也能被还原。这就是著名的“随机数重用攻击”。所以 ( k ) 必须来自密码学安全随机数生成器CSPRNG绝对不能用random()这类伪随机函数生成。密文膨胀指 ElGamal 的密文长度是明文的两倍左右两个 ( p ) 长度的大整数而明文短得多。这意味着如果明文是长数据直接 ElGamal 加密的带宽开销极高。实践中 ElGamal 基本只用来加密对称密钥比如 AES 的会话密钥真正的业务数据用对称加密这就是混合加密的标准做法。公钥算法加密小块密钥对称算法加密大块数据性能和安全性都能兼顾。参数验证也不能忽略。解密端拿到 ( c_1 ) 后要先检查它是否在 ( [1, p-1] ) 区间内且 ( c_1^x ) 不为 0否则可能出现无效密文攻击或信息泄露。很多实现只做“算出来再判断”结果在异常输入时会报错泄露密文结构信息。我在做安全审计时见过一个 ElGamal Demo完全没有对密文做有效性校验攻击者可以通过构造特殊密文探测私钥信息。正确做法是解密前先验证 ( c_1, c_2 ) 的取值域。4. ECC 椭圆曲线加解密公式与工程落地4.1 椭圆曲线群运算基础ECC 的数学对象不是有限域上的整数乘法而是椭圆曲线上的点构成的群。一个典型曲线形式是 ( y^2 x^3 ax b )实际使用中会在有限域 ( \mathbb{F}_p ) 上取点所有坐标都是模 ( p ) 的整数。曲线上的点之间存在“加法”运算两点 ( P, Q ) 连线与曲线交于第三点 ( R )( R ) 关于 x 轴对称的点 ( R P Q ) 即为和。点与自身相加叫倍点( P P 2P )。有了点加和倍点就能定义标量乘法 ( kP P P ... P)( k ) 次。这个运算就是 ECC 的核心——给定 ( k ) 和 ( P )算 ( Q kP ) 很容易给定 ( Q ) 和 ( P )求 ( k ) 极难这就是椭圆曲线离散对数问题ECDLP。ECC 的私钥就是一个随机整数 ( d )公钥是曲线上的点 ( Q dG )其中 ( G ) 是公开的基点。理解 ( kP ) 的关键在于它不是一个“乘法”的直觉而是“连加”的缩写。工程实现中会用双倍与相加算法Double-and-Add把 ( kP ) 拆成若干次倍点和点加复杂度是 ( O(\log k) ) 而不是 ( O(k) )。如果你要手算验证最笨的办法就是不断做点加但实际代码里没人这么干OpenSSL、Java、Go 标准库都已经实现好了这些运算。4.2 ECDH、ECIES 加解密公式与签名验签公式ECDH椭圆曲线 Diffie-Hellman不是直接加解密而是密钥协商协议。双方各自生成私钥 ( d_A, d_B )公钥是 ( Q_A d_A G, Q_B d_B G )。交换公钥后A 计算 ( S d_A Q_B )B 计算 ( S d_B Q_A )因为 ( d_A Q_B d_A d_B G d_B d_A G d_B Q_A )双方得到同一个共享点 ( S )再把 ( S ) 的 x 坐标过哈希函数导出为对称密钥。ECIES椭圆曲线集成加密方案是在 ECDH 基础上构造的公钥加密方案。加密时A 临时生成一个随机私钥 ( r )计算临时公钥 ( R rG )并用 ( r ) 与接收方公钥 ( Q_B ) 算出共享点 ( S rQ_B )。然后用 KDF密钥导出函数从 ( S ) 派生出对称密钥 ( k_{enc} ) 和 ( k_{mac} )用 ( k_{enc} ) 加密消息用 ( k_{mac} ) 生成认证标签最终密文包含 ( R )、密文体和标签三部分。解密时接收方用自己的私钥 ( d_B ) 计算 ( S d_B R )因为 ( d_B R d_B rG rQ_B )得到的共享点与加密方一致。ECDSA椭圆曲线数字签名算法的公式是这样的签名方有私钥 ( d )公钥 ( Q dG )消息哈希为 ( z )。签名第一步随机选整数 ( k )计算 ( R kG )取 ( R ) 的 x 坐标得到 ( r )再算 ( s k^{-1}(z r \times d) \bmod n )其中 ( n ) 是基点 ( G ) 的阶。签名结果是 ( (r, s) )。验签时计算 ( w s^{-1} \bmod n )( u_1 z \times w \bmod n )( u_2 r \times w \bmod n )再算点 ( P u_1G u_2Q )如果 ( P ) 的 x 坐标模 ( n ) 等于 ( r )签名有效。ECDSA 有一个著名的坑随机数 ( k ) 绝对不能泄露或重用。如果同一个私钥签两条消息用了同一个 ( k )攻击者能直接算出私钥 ( d )。2010 年 PlayStation 3 的签名密钥被破解就是因为索尼在签名时用了固定的 ( k )。所以实现 ECDSA 时要么使用 RFC 6979 规定的确定性随机数从私钥和消息哈希派生 ( k )要么确保 CSPRNG 质量过硬。5. 安全性分析与参数避坑5.1 参数选择失败的典型场景小密钥、小指数、弱随机数RSA 的 ( p, q ) 必须足够大且相互独立。从同一个随机种子生成的两个“随机”素数如果恰好相等( n ) 就能被平方根分解整个密钥直接失效。这在实际中真发生过——某些老旧实现用弱随机数生成器批量生成密钥导致大量 RSA 公钥共享同一个因子攻击者通过批量计算最大公约数就能批量分解。ElGamal 的 ( p ) 和 ( g ) 也有讲究。如果 ( p-1 ) 包含小因子离散对数可以用 Pohlig-Hellman 算法降维打击计算复杂度大幅下降。同理如果 ( g ) 的阶太小私钥空间就被压缩了。安全参数选型的核心原则是所有参数都必须落在算法标准推荐的域内不要自己“发明”参数。以 ECC 为例直接用 NIST P-256、secp256k1 或者国产 SM2 标准曲线即可自己造曲线极容易引入子群攻击或异常曲线攻击。另一个高频问题是私钥长度和公开参数的位数不匹配。我看到过有人把 512 位 RSA 当作对称加密的密钥级别来用理由是“反正攻击成本也不低”。这个思路是错的RSA 512 位在现代算力下已经可以被轻松分解2016 年就有研究团队在约 540 天内分解过 768 位 RSA 模数。2024 年之后1024 位 RSA 也不该再用于任何新系统最低 2048 位起步合规要求高的场景直接上 3072 位。5.2 填充方案与密文长度对照表算法典型密钥长度密文长度填充方案安全强度比特RSA2048 位256 字节与密钥等长OAEP / PSS~112RSA3072 位384 字节OAEP / PSS~128ElGamal2048 位群参数512 字节两个群元素概率性加密~112ECCECIES256 位曲线约 32密文16 字节KDFHMAC~128ECDSA 签名256 位曲线约 64 字节r 和 s 各 32哈希前置~128注意 RSA 密文长度始终等于模数长度和明文长度无关这也是 RSA 不适合直接加密长数据的另一个原因。ECC 加密的密文长度优势很明显尤其适合物联网设备这种低带宽场景。ElGamal 的密文膨胀比是 2 倍是三者里最不经济的但它在一些特殊协议比如同态加密、门限解密里有不可替代的表达能力。填充方案的选择直接决定算法是否满足 IND-CCA选择密文攻击下不可区分安全。RSA 必须用 OAEP 或至少 PKCS#1 v1.5ECDSA 使用哈希后再签名ECIES 使用 KDFMAC 组合ElGamal 直接形态只满足 IND-CPA工程上需要叠加其他机制才能达到更高安全属性。如果真的要做高安全等级的系统建议直接采用标准库的高层接口而不是自己组装原语。6. 常见问题速查表与排查心得6.1 问题速查表加解密失败时的第一反应清单现象可能原因排查方向解密得到乱码或长度不对填充模式不一致密钥位数不匹配对比两端算法的填充、哈希算法、密钥长度RSA 加密报“数据过长”明文超过密钥长度减去填充开销改用混合加密公钥只加密对称密钥ECDSA 验签失败哈希算法不一致签名 DER 编码解析错误确认签名哈希与验签哈希一致确认编码格式ECDH 协商出的共享密钥不同曲线参数不一致坐标未压缩/压缩格式不一致确认双方使用同一条曲线公钥格式统一ElGamal 密文解密为负数或 0密文参数超出合法区间先验证 ( c_1 ) 在 ( [1, p-1] ) 内再解密签名每次结果不同是 bug 吗不是ECDSA/PSS 是概率性签名验签逻辑不应比较签名原文应验签而非比对RSA 私钥文件解析失败PEM/DER 格式不匹配PKCS#1 与 PKCS#8 混用明确私钥封装格式转 PKCS#8 兼容更好这些问题是跨语言的我在 Go、Java、Python、Node.js 里都见过。最常见的“解密失败”不是算法算错了而是编码、压缩格式、填充参数不一致。调试的时候不要一上来就觉得是数学公式写错了先检查两端配置。6.2 实测中的独家经验根据我自己踩过几次坑之后的体会处理公钥加解密问题有三个优先级极高的经验。第一条直接用标准库别自己实现算法公式。RSA、ECC、ElGamal 的公式本身不难但安全实现涉及常数时间运算、侧信道防护、随机数管理标准库里这些细节都已经处理好了。自己实现很容易在指数运算的计时差异上泄露私钥信息。我做安全测试时用一台普通笔记本就能在简单实现上测出私钥恢复的时序侧信道标准库反而不会有这个问题。第二条加解密与签名验签的“填充”概念不要混。加解密填充为了抵抗密文分析签名填充为了抵抗伪造和哈希值欺骗。RSA-OAEP 和 RSA-PSS 虽然都叫填充实现细节完全不同签名时用 OAEP 是错的解密时用 PSS 也是错的。很多新人把公钥加密和数字签名当成“同一个操作正反着用”这在 RSA 里勉强成立但真实填充语境下是不对的。第三条密钥轮换与版本兼容要提前设计。生产环境里密钥到期轮换时经常出现旧数据用旧密钥加密、新系统只配新密钥导致无法解密的情况。我的做法是系统里保留密钥版本号密文结构里带上密钥 ID解密时按 ID 选择对应密钥。签名验签同理验签时尝试多个版本的公钥保证历史签名仍然可用。这个设计在金融、政务系统里尤其重要因为数据生命周期往往长达数年甚至十几年。最后再分享一点不管用哪套公钥算法密钥生成时必须用密码学安全随机数密钥存储必须加密且做访问控制私钥丢失后要靠密钥备份或托管机制恢复否则历史密文将永久不可解密。公式只是入门钥匙真正的工程安全体现在密钥管理、协议交互和异常处理的每一个细节上。把这几条刻在脑子里比记住任何一条公式都更能保护你的系统。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/17 1:23:36
战地6启动失败、闪退、进不去?从驱动到BIOS的保姆级排查指南
2026/10/17 1:23:36
鸢尾花识别全拆解:机器学习分类的完整实践链路
2026/10/17 1:23:36
动态规划六题全解:从状态定义到转移方程,附滚动数组优化
2026/10/17 2:23:40
基于YOLOv11全系列的简牍文字检测系统实践
2026/10/17 2:23:40
Flink State Backend选型与keyBy状态分区实战解析
2026/10/17 2:23:40
prompt-optimizer 完整指南:把粗糙初稿变成可测试的提示词模板
2026/10/17 2:23:40
VideoChat-Flash-Qwen2_5-2B_res448 完整使用指南:多轮视频对话、抽帧设置与生成参数调优清单
2026/10/17 2:23:40
BiliTools 哔哩哔哩视频下载器:一个免费开源工具搞定 4K 番剧整季、无损音乐与弹幕
2026/10/17 2:18:40
32 层混合注意力架构拆解:Qwen3.5-9B_gpuep_1.0_gpu_128 如何用线性注意力撑起 256K 上下文
2026/10/17 0:02:58
NetSpot 实战:用信道分析与频宽优化解决 Wi-Fi 卡顿
2026/10/17 0:02:58
C++ split() 字符串分割的五种实现与性能实测
2026/10/17 0:02:58
R语言坐标轴范围设置:从xlim/ylim到coord_cartesian的完整指南
2026/10/16 1:17:36
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/16 1:17:35
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/16 1:17:35
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/16 1:17:35
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/16 18:46:48
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/16 18:46:46
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)