How do you verify an RSA SHA1 signature in Python?

后端 未结 8 1417
面向向阳花
面向向阳花 2020-11-29 00:35

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-----
MIGf         


        
相关标签:
8条回答
  • 2020-11-29 00:53

    I try the code given by joeforker but it does not work. Here is my example code and it works fine.

    from Crypto.Signature import PKCS1_v1_5
    from Crypto.PublicKey import RSA 
    from Crypto.Hash import SHA
    
    pem = """-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
    nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
    XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
    VvXw13PLINE/YptjkQIDAQAB
    -----END PUBLIC KEY-----""" # your example key
    
    key = RSA.importKey(pem)
    h = SHA.new(self.populateSignStr(params))
    verifier = PKCS1_v1_5.new(key)
    if verifier.verify(h, signature):
      print "verified"
    else:
      print "not verified"
    
    0 讨论(0)
  • 2020-11-29 00:57

    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 signature
    • importKey - 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.

    0 讨论(0)
  • 2020-11-29 00:58

    More on the DER decoding.

    DER encoding always 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 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:

    • 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 I want to encode a number of 256 bytes long, then 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 example

    30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
    6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
    32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
    196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
    0001
    

    It interprets as just what Rasmus Faber put in his reply

    0 讨论(0)
  • 2020-11-29 01:00

    Using M2Crypto, the above answers does not 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 about it

    0 讨论(0)
  • 2020-11-29 01:01

    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:

    30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
    6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
    32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
    196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
    0001
    

    This 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 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 get 0203010001, which signifies a RSA public exponent of 0x10001 = 65537.

    You can use those two values as n and e in a tuple to construct a RSAobj.

    0 讨论(0)
  • 2020-11-29 01:04

    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.

    0 讨论(0)
提交回复
热议问题