【问题标题】:How does a public key verify a signature?公钥如何验证签名?
【发布时间】:2013-08-17 21:47:31
【问题描述】:

我正在努力更好地了解公钥/私钥的工作原理。我了解发件人可以使用他/她的私钥向文档添加数字签名,以获取文档的哈希值,但我不明白如何使用公钥来验证该签名。

我的理解是公钥加密,私钥解密......谁能帮我理解?

【问题讨论】:

  • 好问题。 :)
  • 我不想将其添加为答案并冒着随之而来的火焰的风险,但如果您使用“如何”这个词真的意味着“我如何验证签名”,那么一种可能性是下载 gpg4win。安装后,您可以右键单击文件并进行验证。它是一套集成到 Windows shell 中的产品。一个这样的实用程序是 Kleopatra,它将在线查找证书以进行验证。

标签: digital-signature public-key-encryption private-key public-key pki


【解决方案1】:

这是一个使用 Python 验证签名的公钥示例

您需要安装pycryptodome。取自here

# pip install pycryptodome

import binascii
from Crypto.Hash import SHA256
from Crypto.Signature import PKCS1_v1_5
from Crypto.PublicKey import RSA

def generate_keys_and_sign_message(msg_digest):
    private_key = RSA.generate(2048)
    print('\nPrivate Key:', private_key.exportKey("PEM"))
    print("\nPublic Key:", private_key.publickey().exportKey('OpenSSH'))
    
    # create signature using private key and message
    signer = PKCS1_v1_5.new(private_key)
    signature = binascii.b2a_hex(signer.sign(msg_digest))
    print("\nSignature:", signature)

def verify_message(msg_digest, pubkey, signature):
    # verify the message using public key and signature
    pubkey = RSA.importKey(pubkey)
    verifier = PKCS1_v1_5.new(pubkey)
    try:
        verified = verifier.verify(msg_digest, binascii.a2b_hex(signature))
        assert verified, 'Signature verification failed'
        print ('Successfully verified message')
    except binascii.Error:
        print('Invalid Signature')

if __name__=='__main__':
    # create message digest
    message = input('Enter Message: ')
    digest = SHA256.new()
    digest.update(str.encode(message)) # b"tezos")

    generate_keys_and_sign_message(digest)

    pubkey = input('Enter Public Key: ')
    signature = input('Enter Signature: ')
    verify_message(digest, pubkey, signature)

【讨论】:

    【解决方案2】:

    我认为误解的最大问题是,当人们阅读“非对称”时,他们的脑海中会认为“好吧,一个密钥加密,另一个解密,因此它们是不对称的”。但如果你理解非对称实际上意味着“如果密钥 A 加密数据,那么它的“姐妹”密钥 B 可以解密数据。如果密钥 B 用于加密数据,那么密钥 A 现在只能解密。”对称意味着用于加密数据的相同密钥可用于解密数据。

    【讨论】:

      【解决方案3】:

      对于您的问题 - 我正在查看 RSA 实现。并且更清楚地了解了使用公钥来验证使用私钥的签名的方式。毫无疑问,私钥没有暴露。这是如何...

      这里的技巧是在函数中隐藏私钥。在这种情况下,(p-1)*(q-1).

      p 视为私钥,将e 视为公钥。 p 被封装在另一个函数中以使其隐藏。

      E.g., `d = (p-1)(q-1); d * e = 1` (d is the inverse of e - public key)
      
      Data sent = [encrypted(hash), message] = [m ^d, message];
      

      m 是消息 假设

      'Data sent' = y
      

      为了检查完整性,我们找到y^e 以获取m。自m ^(d*e) = m ^1 = m.

      希望这会有所帮助! :)

      【讨论】:

      • 这是我在 stackoverflow 上见过的最奇怪的答案。用数学公式回答 OP...
      【解决方案4】:

      如果我不得不根据我的理解重新表述您的问题,您的问题如下:

      如果公钥加密确保公钥可以从私钥派生,但私钥不能从公钥派生,那么您可能想知道, 公钥如何解密使用私钥签名的消息,而发件人不会将签名消息中的私钥暴露给收件人?(重读那几篇直到它有意义)

      其他答案已经解释了非对称加密如何意味着您可以任一

      1. 用公钥加密,用匹配的私钥解密(下面的伪代码)
      var msg = 'secret message';
      
      var encryptedMessage = encrypt(pub_key, msg);
      
      var decryptedMessage = decrypt(priv_key, encryptedMessage);
      
      print(msg == decryptedMessage == 'secret message'); // True
      
      1. 用私钥加密,用匹配的公钥解密(下面的伪代码)
      var msg = 'secret message';
      
      var encryptedMessage = encrypt(priv_key, msg);
      
      var decryptedMessage = decrypt(pub_key, encryptedMessage); // HOW DOES THIS WORK???
      
      print(msg == decryptedMessage == 'secret message'); // True
      

      我们知道示例 #1 和 #2 都有效。示例 #1 具有直观意义,而示例 #2 提出了原始问题

      原来,椭圆曲线密码学(也称为“椭圆曲线乘法”)是原始问题的答案。椭圆曲线密码学是使以下条件成为可能的数学关系:

      1. 公钥可以从私钥数学生成
      2. 私钥不能从公钥数学生成(即“陷门函数”)
      3. 私钥可以由公钥验证

      对于大多数人来说,条件 #1 和 #2 是有道理的,但 #3 呢?

      您有两种选择:

      1. 您可以钻进兔子洞,花几个小时学习椭圆曲线密码学的工作原理 (here is a great starting point)...或者...
      2. 您可以接受上述属性,就像您接受牛顿的 3 条运动定律一样,而无需自己推导它们。

      总之,公钥/私钥对是使用椭圆曲线密码术创建的,本质上,创建的公钥和私钥在两个方向上链接,但不是数学上派生双向。这使您可以使用某人的公钥来验证他们是否签署了特定的消息,而无需他们向您公开他们的私钥。

      【讨论】:

      • 您的 3 个条件说明了一切。我刚读了这个术语“椭圆曲线”,我就像 wtf
      • 所以,这应该是答案?
      • 哇,这是一个很好的答案。非常感谢。
      • 这个答案就是我想要的。在整个互联网上的其他任何地方实际上都没有对此进行解释。
      【解决方案5】:

      键的作用相反:

      公钥加密,私钥解密(加密):

      openssl rsautl -encrypt -inkey public.pem -pubin -in message.txt -out message.ssl
      openssl rsautl -decrypt -inkey private.pem       -in message.ssl -out message.txt
      

      私钥加密,公钥解密(签名):

      openssl rsautl -sign -inkey private.pem       -in message.txt -out message.ssl
      openssl rsautl       -inkey public.pem -pubin -in message.ssl -out message.txt
      

      以下是使用openssl 测试整个流程的示例脚本。

      #!/bin/sh
      # Create message to be encrypted
      echo "Creating message file"
      echo "---------------------"
      echo "My secret message" > message.txt
      echo "done\n"
      
      # Create asymmetric keypair
      echo "Creating asymmetric key pair"
      echo "----------------------------"
      openssl genrsa -out private.pem 1024
      openssl rsa -in private.pem -out public.pem -pubout
      echo "done\n"
      
      # Encrypt with public & decrypt with private
      echo "Public key encrypts and private key decrypts"
      echo "--------------------------------------------"
      openssl rsautl -encrypt -inkey public.pem -pubin -in message.txt         -out message_enc_pub.ssl
      openssl rsautl -decrypt -inkey private.pem       -in message_enc_pub.ssl -out message_pub.txt
      xxd message_enc_pub.ssl # Print the binary contents of the encrypted message
      cat message_pub.txt # Print the decrypted message
      echo "done\n"
      
      # Encrypt with private & decrypt with public
      echo "Private key encrypts and public key decrypts"
      echo "--------------------------------------------"
      openssl rsautl -sign    -inkey private.pem -in message.txt          -out message_enc_priv.ssl
      openssl rsautl -inkey public.pem -pubin    -in message_enc_priv.ssl -out message_priv.txt
      xxd message_enc_priv.ssl
      cat message_priv.txt
      echo "done\n"
      

      此脚本输出以下内容:

      Creating message file
      ---------------------
      done
      
      Creating asymmetric key pair
      ----------------------------
      Generating RSA private key, 1024 bit long modulus
      ...........++++++
      ....++++++
      e is 65537 (0x10001)
      writing RSA key
      done
      
      Public key encrypts and private key decrypts
      --------------------------------------------
      00000000: 31c0 f70d 7ed2 088d 9675 801c fb9b 4f95  1...~....u....O.
      00000010: c936 8cd0 0cc4 9159 33c4 9625 d752 5b77  .6.....Y3..%.R[w
      00000020: 5bfc 988d 19fe d790 b633 191f 50cf 1bf7  [........3..P...
      00000030: 34c0 7788 efa2 4967 848f 99e2 a442 91b9  4.w...Ig.....B..
      00000040: 5fc7 6c79 40ea d0bc 6cd4 3c9a 488e 9913  _.ly@...l.<.H...
      00000050: 387f f7d6 b8e6 5eba 0771 371c c4f0 8c7f  8.....^..q7.....
      00000060: 8c87 39a9 0c4c 22ab 13ed c117 c718 92e6  ..9..L".........
      00000070: 3d5b 8534 7187 cc2d 2f94 0743 1fcb d890  =[.4q..-/..C....
      My secret message
      done
      
      Private key encrypts and public key decrypts
      --------------------------------------------
      00000000: 6955 cdd0 66e4 3696 76e1 a328 ac67 4ca3  iU..f.6.v..(.gL.
      00000010: d6bb 5896 b6fe 68f1 55f1 437a 831c fee9  ..X...h.U.Cz....
      00000020: 133a a7e9 005b 3fc5 88f7 5210 cdbb 2cba  .:...[?...R...,.
      00000030: 29f1 d52d 3131 a88b 78e5 333e 90cf 3531  )..-11..x.3>..51
      00000040: 08c3 3df8 b76e 41f2 a84a c7fb 0c5b c3b2  ..=..nA..J...[..
      00000050: 9d3b ed4a b6ad 89bc 9ebc 9154 da48 6f2d  .;.J.......T.Ho-
      00000060: 5d8e b686 635f b6a4 8774 a621 5558 7172  ]...c_...t.!UXqr
      00000070: fbd3 0c35 df0f 6a16 aa84 f5da 5d5e 5336  ...5..j.....]^S6
      My secret message
      done
      

      【讨论】:

      • 感谢您添加脚本 - 绝对有助于解决问题。
      • 非常感谢,ecample 总是让我更容易理解
      【解决方案6】:

      公钥加密,只有私钥可以解密,反之亦然。它们都加密为不同的哈希值,但每个密钥都可以解密对方的加密。

      有几种不同的方法可以验证消息是否来自某个预期的发件人。例如:

      发件人发送:

      1. 消息

      2. 用他们的私钥加密的消息的哈希

      接收者:

      1. 使用公钥解密签名 (2) 以获得消息,据说与 (1) 相同,但我们还不知道。我们现在有两条消息需要验证是否相同。所以要做到这一点,我们将用我们的公钥加密它们并比较两个哈希值。所以我们会......
      2. 用公钥加密原始消息 (1) 以获得哈希
      3. 加密解密的消息 (3) 以获得第二个哈希值,并与 (4) 进行比较以验证它们是否相同。

      如果它们不相同,则意味着消息被篡改或使用其他密钥而不是我们认为的密钥签名...

      另一个例子是发送者使用接收者可能知道使用的公共散列。例如:

      发件人发送:

      1. 一条消息
      2. 获取消息的已知哈希值,然后使用私钥加密哈希值

      接收者:

      1. 解密 (2) 并获取哈希值
      2. 使用发送方使用的相同哈希值对消息 (1) 进行哈希处理
      3. 比较两个哈希以确保它们匹配

      这再次确保邮件没有被篡改,并且来自预期的发件人。

      【讨论】:

      • 第一个示例中的第 5 步(已散列消息的散列)如何生成与第 4 步相同的散列?
      【解决方案7】:

      我想我会为任何寻找更直观的东西的人提供补充解释。

      这种混淆的很大一部分来自于命名“公钥”和“私钥”,因为这些东西的实际工作方式与“密钥”的理解方式直接不一致。

      以加密为例。它可以被认为是这样工作的:

      • 希望能够读取秘密消息的各方各有一个密钥 隐藏(即私钥)
      • 希望能够发送秘密消息的各方都有能力获得解锁的锁定(即公共锁)
      • 然后发送秘密消息就像使用解锁的锁锁定它一样简单,但之后只能使用隐藏的钥匙之一来解锁它。

      这允许在各方之间发送秘密消息,但从这里直观的角度来看,“公钥”是比“公钥”更合适的名称。

      但是,对于发送数字签名,角色有些颠倒:

      • 想要签署消息的一方是唯一可以访问未锁定的锁(即私人锁)的一方
      • 想要验证签名的各方都有能力获得密钥(即公钥)
      • 然后,签名者所做的是创建两条相同的消息:一条任何人都可以阅读,另一条伴随它,但他们用自己的一把私人锁锁定。
      • 然后当接收者得到消息后,他们就可以读取它,然后使用公钥解锁被锁定的消息,并比较两条消息。如果消息相同,那么他们知道:

        1. 未锁定的消息在旅行期间未被篡改,并且,

        2. 消息必须来自拥有与其公钥匹配的锁的人。

      • 最后,整个系统只有在任何想要验证签名者签名的人有一个权威的地方可以去获取签名者锁的匹配密钥时才有效。否则,任何人都可以说“嘿,这是某某私人锁的钥匙”,冒充他们向您发送消息,但用他们的私人锁将其锁定,您执行上述所有步骤并相信该消息一定是来自您认为的人,但您被愚弄了,因为您在公钥的真正所有者方面被误导了。

      只要有一个值得信赖的来源来检索签名者的公钥,您就会知道谁是公钥的合法所有者,并且能够验证他们的签名。

      【讨论】:

      • 将“钥匙”更改为“解锁锁”只会增加混乱。
      • @EJP 我不会将密钥更改为“解锁锁”。它已更改为“锁定”。 “解锁锁定”仅用于表达物品的用途。不管怎样,这是你的意见,如果你在加密社区有任何长期经验,那可能是非常有偏见的,因为现有术语是你理解这项技术的方式。为什么不让刚开始的人来判断这个类比是否有用?
      • 我认为与锁和钥匙的类比很好地提供了对这个问题的初步理解。一旦您将锁和钥匙可视化,就可以将它们交换为组装成 rsa(或其他类型)钥匙的不同整数。
      • 我个人认为这是我迄今为止读过的最好的见解。并且肯定会看到为私人/公共添加锁而不是密钥如何使整个系统对于普通的新来者来说直观地不言自明。虽然目前根本不是。我们是经验丰富的开发人员(直到现在还没有直接接触到加密),我们争论了一段时间的公共/私人目的。我是说私有用于加密,而他说公共用于加密:D
      【解决方案8】:

      您对“公钥加密,私钥解密”的理解是正确的……对于数据/消息加密。对于数字签名,情况正好相反。使用数字签名,您试图证明您签名的文档来自您。为此,您需要使用只有您拥有的东西:您的私钥。

      数字签名最简单的描述是数据(文件、消息等)的散列(SHA1、MD5 等),随后用签名者的私钥加密。由于这是只有签名者拥有(或应该拥有)的东西,这就是信任的来源。每个人都可以(或应该)访问签名者的公钥。

      因此,为了验证数字签名,收件人

      1. 计算相同数据(文件、消息等)的哈希值,
      2. 使用发件人的公钥解密数字签名,并且
      3. 比较 2 个哈希值。

      如果它们匹配,则认为签名有效。如果它们不匹配,则意味着使用了不同的密钥对其进行签名,或者数据已被更改(有意或无意)。

      希望有帮助!

      【讨论】:

      • 我的理解是密钥不是对称的......也就是说,用公钥加密的对象可以被私钥解密,但是这种关系并没有相反的工作......更具体地说,我认为用私钥加密的对象不能被公钥解密。如果确实如此,那么这肯定回答了我的问题。
      • 这些键的作用相反。用你的公钥加密了一些东西?用你的私钥解密它。相反,如果你用你的私钥加密了一些东西,你就用你的公钥解密它。这就是非对称密码学的本质。
      • 对称只是意味着相同的密钥用于加密/解密。不对称意味着一个密钥加密而另一个密钥解密(反之亦然)。
      • @Jodimoro,从技术上讲,如果使用私钥加密,则消息不是“秘密”。如果它是用私钥加密的,那么任何拥有公开可用“公共”密钥的人都可以解密该消息。
      • @Jodimoro 使用私钥将哈希加密为签名的唯一原因是确保哈希不会更改......而不是确保它是“秘密的”。
      猜你喜欢
      • 2013-05-28
      • 2017-02-18
      • 2023-04-06
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      相关资源
      最近更新 更多