[ACCEPTED]-How do you verify an RSA SHA1 signature in Python?-signature
Use M2Crypto. Here's how to verify for RSA and any 1 other algorithm supported by OpenSSL:
pem = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----""" # your example key
from M2Crypto import BIO, RSA, EVP
bio = BIO.MemoryBuffer(pem)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
# if you need a different digest than the default 'sha1':
pubkey.reset_context(md='sha1')
pubkey.verify_init()
pubkey.verify_update('test message')
assert pubkey.verify_final(signature) == 1
The data between the markers is the base64 16 encoding of the ASN.1 DER-encoding of a 15 PKCS#8 PublicKeyInfo containing an PKCS#1 14 RSAPublicKey.
That is a lot of standards, and 13 you will be best served with using a crypto-library 12 to decode it (such as M2Crypto as suggested by joeforker). Treat 11 the following as some fun info about the 10 format:
If you want to, you can decode it 9 like this:
Base64-decode the string:
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
This 8 is the DER-encoding of:
0 30 159: SEQUENCE {
3 30 13: SEQUENCE {
5 06 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
16 05 0: NULL
: }
18 03 141: BIT STRING 0 unused bits, encapsulates {
22 30 137: SEQUENCE {
25 02 129: INTEGER
: 00 DF 1B 82 2E 14 ED A1 FC B7 43 36 6A 27 C0 63
: 70 E6 CA D6 9D 41 16 CE 80 6B 3D 11 75 34 CF 0B
: AA 93 8C 0F 8E 45 00 FB 59 D4 D9 8F B4 71 A8 D0
: 10 12 D5 4B 32 24 41 97 C7 43 4F 27 C1 B0 D7 3F
: A1 B8 BA E5 5E 70 15 5F 90 78 79 CE 9C 25 F2 8A
: 9A 92 FF 97 DE 16 84 FD AF F0 5D CE 19 6A E7 68
: 45 F5 98 B3 28 C5 ED 76 E0 F7 1F 6A 6B 74 48 F0
: 86 91 E6 A5 56 F5 F0 D7 73 CB 20 D1 3F 62 9B 63
: 91
157 02 3: INTEGER 65537
: }
: }
: }
For a 1024 bit RSA 7 key, you can treat "30819f300d06092a864886f70d010101050003818d00308189028181"
as a constant header, followed 6 by a 00-byte, followed by the 128 bytes 5 of the RSA modulus. After that 95% of the 4 time you will get 0203010001
, which signifies a RSA 3 public exponent of 0x10001 = 65537.
You can 2 use those two values as n
and e
in a tuple 1 to construct a RSAobj.
A public key contains both a modulus(very 12 long number, can be 1024bit, 2058bit, 4096bit) and 11 a public key exponent(much smaller number, usually 10 equals one more than a two to some power). You 9 need to find out how to split up that public 8 key into the two components before you can 7 do anything with it.
I don't know much about 6 pycrypto but to verify a signature, take 5 the hash of the string. Now we must decrypt 4 the signature. Read up on modular exponentiation; the formula 3 to decrypt a signature is message^public exponent % modulus
. The last step 2 is to check if the hash you made and the 1 decrypted signature you got are the same.
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 3 to use MD5, in which case ezPyCryto can't 2 help Andrew unless he wades into its code. I 1 defer to joeforker's answer: consider M2Crypto.
More on the DER decoding.
DER encoding always 11 follows a TLV triplet format: (Tag, Length, Value)
- Tag specifies the type (i.e. data structure) of the value
- Length specifies the number of byte this value field occupies
- Value is the actual value which could be another triplet
Tag 10 basically tells how to interpret the bytes 9 data in the Value field. ANS.1 does have 8 a type system, e.g. 0x02 means integer, 0x30 7 means sequence (an ordered collection of 6 one or more other type instances)
Length 5 presentation has a special logic:
- If the length < 127, the L field only uses one byte and coded as the length number value directly
- If the length > 127, then in the first byte of L field, the first bit 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 4 I want to encode a number of 256 bytes long, then 3 it would be like this
02 82 01 00 1F 2F 3F 4F … DE AD BE EF
- Tag, 0x02 means it's a number
- Length, 0x82, bit presentation of it is 1000 0010, meaning the following two bytes specifies the actually length of the value, which his 0x0100 meaning the value field is 256 bytes long
- Value, from 1F to EF, the actual 256 bytes.
Now looking at your 2 example
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
It interprets as just what Rasmus 1 Faber put in his reply
Maybe this isn't the answer you're looking 4 for, but if all you need is to turn the 3 key into bits, it looks like it's Base64 2 encoded. Look at the codecs
module (I think) in 1 the standard Python library.
Using M2Crypto, the above answers does not 2 work. Here is a tested example.
import base64
import hashlib
import M2Crypto as m2
# detach the signature from the message if it's required in it (useful for url encoded data)
message_without_sign = message.split("&SIGN=")[0]
# decode base64 the signature
binary_signature = base64.b64decode(signature)
# create a pubkey object with the public key stored in a separate file
pubkey = m2.RSA.load_pub_key(os.path.join(os.path.dirname(__file__), 'pubkey.pem'))
# verify the key
assert pubkey.check_key(), 'Key Verification Failed'
# digest the message
sha1_hash = hashlib.sha1(message_without_sign).digest()
# and verify the signature
assert pubkey.verify(data=sha1_hash, signature=binary_signature), 'Certificate Verification Failed'
And that's 1 about it
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.