试图用加密术语解释签名的整个概念是有缺陷的。它根本行不通。所以让我们解开整个事情,这需要一些形式主义。
形式上,密码签名系统由三种算法组成:
KeyGen:将“安全参数”(例如,我们想要获得的密钥的长度)作为输入,并生成一个新的公钥/私钥对(K p,K s)。
签名:将消息m和私钥K s作为输入;输出是一个签名s。
验证:将消息m、签名s和公钥K p作为输入;输出是一个布尔值(成功时为真,如果签名无效则为假)。
如果算法按照宣传的方式运行(Sign使用KeyGen生成的密钥对生成Verify接受的签名),则称该系统是健全的。如果系统在计算上无法伪造,则称该系统是密码安全的:给定公钥K p,并且在不知道K s _ 的情况下,生成 a ( m , s ) 对使得验证( m , s , K p ) =真的。该定义特别暗示私钥不应仅从公钥计算,否则伪造将很容易。
以上都没有说明算法是如何工作的。已经发明、描述和标准化了各种系统。
RSA是一种非常著名的非对称算法,但这是错误的,因为 RSA 不是一种算法。RSA 是称为陷门置换的内部操作的名称,从中派生出非对称加密系统和签名系统。RSA 操作大致如下:
让n是一个大整数,使得n = pq,其中p和q是两个不同的大素数。p和q的知识是“私钥”。让e是某个(通常是小的)整数,称为“公共指数”;e必须与p-1和q-1 互质。e的传统值是 3 和 65537。
给定一个整数x模n(0到n-1范围内的整数),RSA 前向运算正在计算x e mod n(x被提升为指数e模n)。这很容易做到。碰巧这个操作是整数模n的排列(每个y模n等于x e mod m恰好有一个x)。“神奇”的部分是,由于某种原因,没有人找到一种有效的方法来计算反向操作(得到x从x e mod n ) 不知道p和q。这并不是因为缺乏尝试;2500 多年来,最优秀的人一直在研究整数因式分解。当您知道p和q 时,RSA 反向操作变得容易。p和q的知识因此被称为陷门。
现在我们有了这个陷门置换,我们可以设计一个签名算法,其工作方式如下:
KeyGen:给定目标长度k ,产生两个长度约为k / 2 位的随机素数p和q,使得p-1和q-1都与先验选择的e相对素数(例如e = 3),并且n = pq的长度为k位。公钥是(n,e),私钥是(p,q,e)。
符号:获取消息m,用一些散列函数(例如 SHA-256)对其进行散列,并将散列输出(在 SHA-256 的情况下为 256 位序列)“转换”为整数y模n。该转换就是填充的内容,因为标准方法(如PKCS#1中所述)正在写入带有一些额外字节的散列输出,然后将结果解释为整数(在 PKCS 的情况下采用大端约定#1)。一旦散列消息通过填充转换为整数y,私钥所有者应用陷门(反向 RSA 操作)来计算x使得x e = y modn(这样的x存在并且是唯一的,因为 RSA 操作是一个排列)。签名s是该整数x的字节编码。
验证:给定签名s,将其解码回整数x模n,然后计算y = x e模n。如果此值y等于h ( m ) 的填充(消息m的哈希),则接受签名(返回值为true)。
RSA 加密是另一种独特的系统,它也建立在 RSA 陷门排列之上。加密是通过将整数x提高到指数e模n来完成的;由于知道私钥(p和q因子) ,解密是通过反转该操作来完成的。由于这样的系统只处理大整数,我们想要加密和解密字节,那么在某些时候也必须进行某种转换,因此涉及到填充过程。至关重要的是,加密填充的安全要求与签名填充的安全要求截然不同。例如,加密填充必须包含大量随机性,而签名填充必须包含大量确定性。在实践中,这两种填充系统是完全不同的。
当人们查看 RSA 签名和 RSA 加密时,他们发现将签名描述为一种加密是合适的。如果你看一下,RSA 前向操作(提高到指数e)是为 RSA 加密完成的,也用于 RSA 签名验证。类似地,对 RSA 解密和 RSA 签名生成执行相反的操作。此外,如果天才是为了让其他人感到困惑,那么作为天才的一击,一些人注意到 RSA 逆运算在数学上也可以表示为“将整数提高到某个幂模n",就像正向操作(但指数不同)。因此他们开始将反向操作称为“加密”。此时,RSA加密,RSA解密,RSA签名生成和RSA签名验证都称为“加密” . 由于一些奇怪的心理原因(我责怪后迪斯科流行音乐的有害影响),许多人仍然认为通过首先给它们相同的名称来解释四种不同的操作在教学上是合理的。
我们描述了 RSA;让我们看看另一种完全不同的算法,称为DSA。DSA 不使用陷门排列。在 DSA 中,我们以一个大素数(传统上称为p)和另一个较小素数(称为q)为模进行计算,这样p-1是q的倍数。p和q是众所周知的。
DSA 中有一个单向操作。给定一个整数g模p (严格来说,在p的一个特定子集称为q阶子群)和一个整数x模q,每个人都可以计算g x mod p;然而,从g x mod p中恢复x在计算上是不可行的。
虽然这在某种程度上看起来像 RSA,但有一些关键的区别:
这里,操作是将g提高到指数x,其中实际输入是x(指数),因为g是一个固定的常规值。
这不是一个排列,因为x是一个模q的整数,而g x mod p是一个模p的整数,这是一个完全不同的集合。
这当然不是活板门:没有允许恢复x的“秘密知识” ,除非您已经知道x的确切值。
但是,可以在该操作上构建签名算法。它看起来像这样:
现在祝你好运,试图将其描述为某种“加密”。如果您发现这里加密的内容不清楚,那是因为这里没有加密任何内容。这不是加密。
然而,有一个挥手的概念描述签名,它可以与 RSA、DSA 和许多其他签名算法一起使用。您可以将签名视为一种特定类型的身份验证。
在身份验证中,一个人(证明者)向另一个人(验证者)展示他的身份。证明者通过执行一些只有该人才能执行的操作来做到这一点,但是以这样一种方式,验证者可以确信他见证了真实的事物。例如,一个非常基本的身份验证系统称为“显示密码”:证明者和验证者都知道一个共享秘密(“密码”);证明者通过说出密码向验证者展示他的身份。
对于签名,我们想要一些更复杂的东西:
- 签名是异步的。签字人行动一次;验证是在之后进行的,可能在其他地方进行,并且没有签名者的任何进一步积极帮助。
- 验证者不需要知道任何秘密。签名应该让每个人都信服。
- 签字人不得泄露任何秘密。他的私钥不应该被消费(是的,我知道有一些签名方案可以与消费一起工作;我们不要去那里)。
- 签名应该特定于给定的消息m。
身份验证方案的一个相当通用的结构是基于挑战:验证者向证明者发送一个挑战,证明者只能通过他对他的秘密的了解才能回答。
如果您查看 RSA,那么您可以看到它是一种基于质询的身份验证机制。挑战是散列和填充的消息。签名者通过对该挑战应用 RSA 反向操作来证明他对私钥的掌握程度,这是只有他才能做到的事情;但是每个人都可以应用 RSA 前向操作来查看挑战确实得到了很好的解决。
如果您查看 DSA,您可以再次看到基于质询的身份验证机制。签名者首先通过发布r来提交秘密值k;那么挑战是(再次)消息h与承诺r相结合;签名者只能通过使用他的私钥x来回答这个挑战。在 DSA 中,签名者拥有永久私钥x,生成一次性私有值k,并展示他对x/k mod q的了解。(这不会泄露关于x的信息,因为k只使用一次。)
总结:签名算法不是加密算法,对基于加密的签名的解释充其量只能是完全混乱的。更好的解释是表明签名算法实际上是一种特定类型的身份验证机制,签名者通过该机制证明他对私钥的了解,以响应涉及签名消息的综合挑战。
只要对所述挑战进行了充分明确的说明,以证明它不会对签名者有利,那么这种身份验证对旁观者来说是令人信服的。在 RSA 中,它是确定性散列和填充的结果(并且填充注意避免 RSA 反向操作变得容易的值)。在 DSA 中,挑战是根据签名者的先前承诺计算的。
事实上,任何零知识认证系统都可以通过使其非交互性变成签名机制:由于 ZK 系统通过承诺、挑战和对这些挑战的响应来工作,您可以让签名者计算他的所有承诺,并将它们全部散列与要签名的消息一起,并使用哈希值作为挑战。这并不意味着 ZK 证明潜伏在所有签名算法中;但是,如果您发现 DSA 看起来有点像,那么,这是有充分理由的。