公钥如何验证签名?

我正在努力更好地了解公钥/私钥是如何工作的。我知道发送方可以使用他/她的私钥向文档添加数字签名,从而实质上获得文档的哈希值,但我不理解的是如何使用公钥来验证该签名。

我的理解是公钥加密,私钥解密…有人能帮我理解一下吗?

135951 次浏览

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

简单来说,数字签名是数据(文件、消息等)的哈希值(SHA1、MD5等),随后使用签名者的私钥进行加密。因为这是只有签名者拥有(或应该拥有)的东西,所以这就是信任的来源。每个人都有(或应该有)访问签名者的公钥的权限。

为了验证数字签名,接收者

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

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

希望有帮助!

键的作用是相反的:

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

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

我想为那些寻找更直观的东西的人提供一个补充解释。

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

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

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

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

然而,对于发送数字签名,角色有点相反:

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

    1. 解锁的信息在旅行途中没有被篡改,

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

    3. 李< / ol > < / >
    4. 最后,整个系统只有在想要验证签名者签名的人有权威的地方可以获得签名者锁的匹配密钥时才能工作。否则,任何人都可以说“嘿,这是某某人的私有锁的钥匙”,假装是他们向你发送消息,但用他们的私有锁锁定它,你执行所有上述步骤,并相信消息实际上一定来自你认为的人,但你被愚弄了,因为你被误导了公钥的真正所有者。

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

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

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

发件人发送:

  1. 的消息

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

接收方:

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

如果它们不相同,这意味着要么消息被篡改了,要么它是用其他密钥签名的,而不是我们认为的那个……

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

发件人发送:

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

接收方:

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

这再次确保消息没有被篡改,并且它来自预期的发送者。

如果我必须根据我的理解重新措辞你的问题,你的问题如下:

如果公钥密码学确保公钥可以是从私钥派生而来,而私钥不能是从公钥派生而来,那么你可能会想,公钥如何解密用私钥签名的消息,而发送方不将签名消息中的私钥暴露给接收方?(重新阅读几次,直到理解为止)

其他答案已经解释了不对称密码学意味着你可以要么:

  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个运动定律一样,而不需要自己推导出它们。

总之,使用椭圆曲线密码学创建了一个公共/私有密钥对,从本质上讲,创建的公钥和私钥在两个方向上都是数学上链接,但在两个方向上不是数学上派生。这使得您可以使用某人的公钥来验证他们是否签署了特定的消息,而不会向您暴露他们的私钥。

关于你的问题,我在看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是消息 假设< / p >

'Data sent' = y

为了检查完整性,我们找到y^e来得到m。因为m ^(d*e) = m ^1 = m

希望这能有所帮助!:)

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

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

你需要安装pycryptodome。取自在这里

# pip install pycryptodome


from Crypto.PublicKey import RSA
from hashlib import sha512


# create RSA key-pair
keyPair = RSA.generate(bits=1024)
public_key = (keyPair.e, keyPair.n)
private_key = (keyPair.d, keyPair.n)


msg = b'A message for signing'
hash = int.from_bytes(sha512(msg).digest(), byteorder='big')


# RSA sign the message using private key
signature = pow(hash, private_key[0], private_key[1])


# RSA verify signature using public key
hashFromSignature = pow(signature, public_key[0], public_key[1])
print("Signature valid:", hash == hashFromSignature)

如果我用我的私钥加密一些文本,那么任何拥有我的公钥的人都可以解密它。公钥是公开的,任何人都可以拥有它(包括小偷和骗子),那么用我的私钥加密文本有什么意义(因为它可以用我的公钥解密,这是公开的)?

它给了我们真实性。我的意思是,如果你能用我的公钥解密一条消息,那么你就可以说这条消息是我发的。但是,有一个但是。假设有人用我的公钥解密了一条消息,并得到了“Hi!”的消息,这是否意味着我说了“Hi!”?有可能使用了其他一些私钥加密消息,碰巧我的私钥将其解密为有意义的文本而不是胡言乱语。

这就是为什么我们还需要用我们的公钥提供确切的消息。因此,接收者可以将其与解密的消息进行比较。

所以,我们提供

  • 公钥
  • 原始消息
  • 加密信息

如果Original Message = Decrypt(Encrypted Message, Public Key),那么里面的消息肯定是我的,因为只有我有私钥。

奖金:

始终发送“原始消息”;不方便。“原始信息”;可以是4GB的ISO文件。最好是计算原始消息的哈希(单向哈希函数,也称为消息摘要,是一种数学函数,它接受可变长度的输入字符串并将其转换为固定长度的二进制序列,该序列在计算上难以反转—即从哈希生成原始字符串)并发送它。

所以,现在我们发送:

  • 公钥
  • 原始消息的散列
  • 原始消息的加密散列

现在如果Hash(Original Message) = Decrypt(Encrypted Message, Public Key),那么里面的消息肯定是我的,因为只有我有私钥。