公钥如何验证签名?

时间:2013-08-15 16:29:20

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

我正在努力更好地解决公钥/私钥的工作方式。我知道发件人可以使用他/她的私钥向文档添加数字签名,以基本上获取文档的哈希值,但我不明白的是如何使用公钥来验证签名。

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

8 个答案:

答案 0 :(得分:156)

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

最简单描述中的数字签名是数据(文件,消息等)的散列(SHA1,MD5等),随后使用签名者的私钥加密。因为这只是签名者拥有(或应该拥有)信任来自的地方。每个人都有(或应该)访问签名者的公钥。

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

  1. 计算相同数据(文件,消息等)的哈希值,
  2. 使用发件人的PUBLIC密钥解析数字签名,
  3. 比较2个哈希值。
  4. 如果匹配,则签名有效。如果它们不匹配,则表示使用了不同的密钥对其进行签名,或者数据已被更改(无论是有意还是无意)。

    希望有所帮助!

答案 1 :(得分:51)

正如atn's answer所指出的那样,这些键反向运作。

  

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

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 :(得分:6)

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

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

发件人发送:

  1. 消息

  2. 使用其私钥加密的邮件的哈希

接收方:

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

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

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

发件人发送:

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

接收方:

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

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

答案 3 :(得分:2)

我想我会为那些寻找更直观透露的人提供补充说明。

这种混淆的很大一部分来自于命名公共密钥&#39;和私人密钥&#39;因为这些东西实际上是如何工作的,直接与一个关键的方式不一致。被理解为。

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

  • 希望能够阅读秘密消息的各方都保持密钥 隐藏(即私钥)
  • 希望能够发送秘密消息的各方都能够获得解锁锁定(即公共锁定)
  • 然后发送一条秘密消息就像锁定解锁一样简单,但之后只能使用其中一个隐藏密钥解锁。

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

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

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

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

    2. 邮件必须来自具有匹配锁定权限的人的公钥。

  • 最后,如果任何想要验证签名者签名的人都有权威地去获取签名者锁的匹配密钥,那么整个系统才有效。否则,任何人都可以说&#34;嘿,这是某某某私人锁定的钥匙&#34;,给你发一条假装是他们的信息,但用他们的私人锁锁住它,你执行上述所有步骤,并认为该消息实际上必须来自你认为的人,但你被愚弄了,因为你误导了公钥的真正所有者。

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

答案 4 :(得分:0)

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

  

如果公钥密码学确保可以从私钥派生公钥 ,但是不能从公钥派生私钥 ,那么您可能会想知道,公钥如何解密用私钥签名的消息,而发件人不将签名消息中的私钥暴露给收件人?(请重新阅读一些时间直到有意义为止)

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

  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. 您可以接受上面的属性,就像接受牛顿的三个运动定律一样,而无需自己推导

总而言之,使用椭圆曲线密码学创建了一个公共/私有密钥对,而本质上,它创建了一个在数学上链接但在数学上不是两个链接的公共和私有密钥。 em>双向 。这样一来,您便可以使用某人的公钥来验证他们是否签名了特定的消息,而无需他们向您公开其私钥。

答案 5 :(得分: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起。

希望这会有所帮助! :)

答案 6 :(得分:0)

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

答案 7 :(得分:0)

这里是一个使用 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)