如何在 Python 中验证 RSA SHA1 签名?
我有一个字符串、一个签名和一个公钥,我想验证字符串上的签名。 密钥看起来像这样:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----
我已经阅读 pycrypto 文档有一段时间了,但我不知道如何使用这种密钥制作 RSAobj。 如果您了解 PHP,我会尝试执行以下操作:
openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA1);
另外,如果我对任何术语感到困惑,请告诉我。
I've got a string, a signature, and a public key, and I want to verify the signature on the string. The key looks like this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----
I've been reading the pycrypto docs for a while, but I can't figure out how to make an RSAobj with this kind of key. If you know PHP, I'm trying to do the following:
openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA1);
Also, if I'm confused about any terminology, please let me know.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
使用M2Crypto。 以下是验证 RSA 和 OpenSSL 支持的任何其他算法的方法:
Use M2Crypto. Here's how to verify for RSA and any other algorithm supported by OpenSSL:
标记之间的数据是包含 PKCS#1 RSAPublicKey 的 PKCS#8 PublicKeyInfo 的 ASN.1 DER 编码的 base64 编码。
这是很多标准,最好使用加密库对其进行解码(例如 M2Crypto 由 joeforker 建议)。 将以下内容视为有关格式的一些有趣信息:
如果需要,您可以像这样解码它:
Base64 解码字符串:
这是 DER 编码:
对于 1024 位 RSA 密钥,您可以将
视为“30819f300d06092a864886f70d010101050003818d00308189028181”作为常量头,后面跟着一个00字节,后面跟着128字节的RSA模数。 此后 95% 的时间您将得到
0203010001
,这表示 RSA 公共指数为 0x10001 = 65537。您可以将这两个值用作
n
和e
在元组中构造 RSAobj。The data between the markers is the base64 encoding of the ASN.1 DER-encoding of a PKCS#8 PublicKeyInfo containing an PKCS#1 RSAPublicKey.
That is a lot of standards, and you will be best served with using a crypto-library to decode it (such as M2Crypto as suggested by joeforker). Treat the following as some fun info about the format:
If you want to, you can decode it like this:
Base64-decode the string:
This is the DER-encoding of:
For a 1024 bit RSA key, you can treat
"30819f300d06092a864886f70d010101050003818d00308189028181"
as a constant header, followed by a 00-byte, followed by the 128 bytes of the RSA modulus. After that 95% of the time you will get0203010001
, which signifies a RSA public exponent of 0x10001 = 65537.You can use those two values as
n
ande
in a tuple to construct a RSAobj.公钥包含模数(非常长的数字,可以是 1024 位、2058 位、4096 位)和公钥指数(小得多的数字,通常等于 2 的某次幂)。 您需要先了解如何将该公钥拆分为两个部分,然后才能对其执行任何操作。
我对 pycrypto 不太了解,但要验证签名,请获取字符串的哈希值。 现在我们必须解密签名。 阅读模幂; 解密签名的公式是
message^public exponent % modulus
。 最后一步是检查您创建的哈希值和解密后的签名是否相同。A public key contains both a modulus(very long number, can be 1024bit, 2058bit, 4096bit) and a public key exponent(much smaller number, usually equals one more than a two to some power). You need to find out how to split up that public key into the two components before you can do anything with it.
I don't know much about pycrypto but to verify a signature, take the hash of the string. Now we must decrypt the signature. Read up on modular exponentiation; the formula to decrypt a signature is
message^public exponent % modulus
. The last step is to check if the hash you made and the decrypted signature you got are the same.我认为 ezPyCrypto 可能会让这变得更容易一些。 key 类的高级方法包括以下两个方法,我希望它们能够解决您的问题:verifyString - 根据签名验证字符串importKey - 导入公钥(也可能是私钥)Rasmus 在评论中指出
verifyString
被硬编码为使用 MD5,在这种情况下,ezPyCryto 无法帮助 Andrew,除非他深入了解其代码。 我遵循 joeforker 的回答:考虑M2Crypto。I think ezPyCrypto might make this a little easier. The high-level methods of the key class includes these two methods which I hope will solve your problem:verifyString - verify a string against a signatureimportKey - import public key (and possibly private key too)Rasmus points out in the comments that
verifyString
is hard-coded to use MD5, in which case ezPyCryto can't help Andrew unless he wades into its code. I defer to joeforker's answer: consider M2Crypto.有关 DER 解码的更多信息。
DER编码始终遵循TLV三元组格式:(标签,长度,值)
基本上可以是另一个三元组标签告诉如何解释值字段中的字节数据。 ANS.1 确实有一个类型系统,例如 0x02 表示整数,0x30 表示序列(一个或多个其他类型实例的有序集合)
表示有一个特殊的逻辑:
直接取长度数值
必须为1,其余7位代表后面的个数
用于指定值字段长度的字节。 价值,
实际上是值本身的字节。
比如说我要编码一个256字节长的数字,那么就会像这样的
接下来的两个字节指定了该值的实际长度,即
他的0x0100表示value字段是256字节长的
现在看看你的例子
它解释为拉斯穆斯·法伯在他的回复中所说的
More on the DER decoding.
DER encoding always follows a TLV triplet format: (Tag, Length, Value)
Tag basically tells how to interpret the bytes data in the Value field. ANS.1 does have a type system, e.g. 0x02 means integer, 0x30 means sequence (an ordered collection of one or more other type instances)
Length presentation has a special logic:
length number value directly
must be 1, and the rest 7 bits represents the number of following
bytes used to specifies the length of the Value field. Value, the
actually bytes of the value itself.
For example, say I want to encode a number of 256 bytes long, then it would be like this
following two bytes specifies the actually length of the value, which
his 0x0100 meaning the value field is 256 bytes long
Now looking at your example
It interprets as just what Rasmus Faber put in his reply
也许这不是您正在寻找的答案,但如果您需要的只是将密钥转换为位,那么看起来它是 Base64 编码的。 看看标准 Python 库中的
codecs
模块(我认为)。Maybe this isn't the answer you're looking for, but if all you need is to turn the key into bits, it looks like it's Base64 encoded. Look at the
codecs
module (I think) in the standard Python library.使用 M2Crypto,上述答案不起作用。 这是一个经过测试的示例。
就是这样
Using M2Crypto, the above answers does not work. Here is a tested example.
And that's about it
我尝试了 joeforker 给出的代码,但它不起作用。
这是我的示例代码,它工作正常。
I try the code given by joeforker but it does not work.
Here is my example code and it works fine.