公钥如何验证签名?


172

我试图更好地解决公钥/私钥的工作方式。我知道发件人可以使用他/她的私钥将数字签名添加到文档中,以本质上获取文档的哈希值,但是我不了解的是如何使用公钥来验证该签名。

我的理解是公钥加密,私钥解密...有人可以帮助我理解吗?


3
好问题。:)
Suraj Jain

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

Answers:


210

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

在最简单的描述中,数字签名是数据(文件,消息等)的哈希(SHA1,MD5等),随后使用签名者的私钥对其进行加密。由于那是只有签名者拥有(或应该拥有)的东西,而信任才是来源。每个人都可以(或应该)访问签名者的公钥。

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

  1. 计算相同数据(文件,消息等)的哈希,
  2. 使用发送者的PUBLIC密钥解密数字签名,然后
  3. 比较两个哈希值。

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

希望有帮助!


13
我的理解是,密钥不是对称的……也就是说,用公钥加密的对象可以被私钥解密,但是这种关系并不是相反的……更具体地说,我不认为对象用私钥加密的可以通过公钥解密。如果确实如此,那绝对可以回答我的问题。
jcampos8782

63
按键彼此相反。用您的公钥加密了什么?用您的私钥解密。相反,如果您使用私钥加密了某些内容,则会使用您的公共密钥对其解密。这就是非对称密码学的本质。
Shadowman

20
对称只是意味着使用相同的密钥进行加密/解密。非对称性意味着一个密钥加密而另一个密钥解密(相反也是如此)。
gtrig

8
@Jodimoro,从技术上讲,如果消息是用私钥加密的,则该消息不是“秘密”。如果使用私钥加密,则具有公开可用的“公钥”的任何人都可以解密该消息。
RayLoveless

4
@Jodimoro使用专用密钥将哈希加密为签名的唯一原因是确保哈希未更改……不确保哈希是“秘密的”。
RayLoveless

71

这些键的作用相反:

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

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

2
感谢您添加脚本-绝对有助于清除问题。
专利

非常感谢,对我而言,总能比以往更容易理解
Simon

16

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

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

发件人发送:

  1. 讯息

  2. 使用其私钥加密的消息的哈希

收件人:

  1. 用公钥对签名(2)解密以获取一条消息,该消息应该与(1)相同,但我们尚不知道。现在,我们有两个需要验证的消息是相同的。因此,为此,我们将使用我们的公钥对它们进行加密,并比较两个哈希。所以我们会....
  2. 用公钥加密原始消息(1)以获取哈希
  3. 加密解密后的消息(3),以获得第二个哈希值,然后与(4)比较以验证它们是否相同。

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

另一个示例是发送方使用接收方可能也知道要使用的公用哈希。例如:

发件人发送:

  1. 一个消息
  2. 获取消息的已知哈希,然后使用私钥对哈希进行加密

收件人:

  1. 解密(2)并获取哈希值
  2. 使用发件人使用的散列对消息(1)进行散列
  3. 比较两个散列以确保它们匹配

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


6

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

如果公钥密码术确保可以从私钥派生公钥,但是不能从公钥派生私钥,那么您可能会想,公钥如何在没有发送者的情况下解密用私钥签名的消息?将签名消息中的私钥暴露给收件人?(重复阅读几次直到有意义为止)

其他答案已经解释了非对称加密意味着你可以

  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. 您可以钻一个兔子洞,花几个小时学习椭圆曲线密码学的工作原理(这是一个很好的起点)...或者...
  2. 您可以接受上面的属性-就像您接受牛顿的三个运动定律一样,而无需自己导出它们。

总之,使用椭圆曲线加密,它创建了一个公钥/私钥对自然,创建了以数学公钥和私钥连接在两个方向,但不是数学推导在两个方向上。这样一来,您便可以使用某人的公钥来验证他们是否签名了特定的消息,而无需他们向您暴露其私钥。


您的3个条件可以解释一切。我刚刚读过这个术语“椭圆曲线”,就像wtf
Simon

5

我想我会为任何寻找更直观揭示的东西的人提供补充说明。

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

以加密为例。可以这样认为:

  • 希望能够读取秘密消息的各方各自隐藏了一个密钥(即私钥)
  • 希望能够发送秘密消息的各方都有能力获得未锁定的锁定(即公共锁定)
  • 然后发送秘密消息就像使用解锁的锁将其锁定一样容易,但是之后只能使用其中一个隐藏键将其解锁。

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

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

  • 想要签名的一方是唯一可以访问解锁锁(即私人锁)的一方。
  • 想要验证签名的各方都具有获取密钥(即公共密钥)的能力
  • 然后,签名者要做的是创建两个相同的消息:一个任何人都可以阅读的消息,以及一个伴随它的消息,但是他们使用自己的私人锁之一进行了锁定。
  • 然后,当接收者收到消息时,他们可以阅读该消息,然后使用公共密钥来解锁锁定的消息并比较这两个消息。如果消息相同,那么他们知道:

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

    2. 该消息必须来自与他们的公钥具有匹配锁的人。

  • 最后,只有希望验证签名人签名的人有授权去签名人锁的匹配密钥的地方,整个系统才起作用。否则,任何人都可以说“嘿,这是某某某人的私人锁的钥匙”,向您发送一条消息,假装是他们,但使用其私人锁将其锁定,您执行上述所有步骤,并认为该消息实际上必须是从您认为的人那里获得,但您因为被误认为是公钥的真正所有者而被骗了。

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


4
将“密钥”更改为“未锁定”只会增加混乱。
罗恩侯爵

@EJP我不会将密钥更改为“解锁锁”。它已更改为“锁定”。“解锁未锁定”仅用于表示该物品的用途。顺便说一句,这是您的意见,如果您在加密社区有任何长期经验,则可能会非常有偏见,因为现有术语是您逐渐了解该技术的方式。您为什么不让刚开始的人们确定类比是否有用?

1
我认为与锁和钥匙的类比可以很好地提供对此问题的初步了解。一旦您看到了锁和钥匙,便可以交换组装成rsa(或其他类型)钥匙的不同整数。
安德烈亚斯·隆格伦

我个人到目前为止认为,这种见解是最好的。并且肯定会看到如何为私有/公共部门添加锁而不是密钥,从而使整个系统对于常规的新手而言直观地不言自明。虽然目前还不是。我们是经验丰富的开发人员(直到现在还没有直接接触过加密技术),并且一段时间以来我们一直在争论公共/私有用途。我说的是private用于加密,而他说的public用于加密:D
jayarjo 19-4-10

0

对于您的问题-我正在研究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)

发送的数据= [已加密(哈希),消息] = [m ^ d,消息];其中m是消息,假设“已发送数据” = y为了检查完整性,我们找到y ^ e以获取m。自从m ^(d*e) = m ^1 = m

希望这可以帮助!:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.