Comment vérifier une signature rsa SHA1 en Python?

j'ai une chaîne de caractères, une signature et d'une clé publique, et je veux vérifier la signature sur la chaîne. La clé ressemble à ceci:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----

j'ai lu les docs de pycrypto pendant un moment, mais je ne sais pas comment faire un RSAobj avec ce genre de clé. Si vous connaissez PHP, j'essaie de faire ce qui suit:

openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA1);

aussi, si je suis confus au sujet de toute terminologie, s'il vous plaît faites le moi savoir.

28
demandé sur Andrew Badr 2009-02-13 04:50:48

8 réponses

les données entre les marqueurs sont l'encodage base64 de L'ASN.1 DER-encoding of a PKCS#8 PublicKeyInfo containing an PKCS#1 RSAPublicKey.

qui est un grand nombre de normes, et vous serez mieux servi en utilisant une crypto-bibliothèque pour le décoder (comme M2Crypto comme suggéré par joeforker ). Traitez ce qui suit comme des informations amusantes sur le format:

si vous voulez, vous pouvez le décoder comme ceci:

Base64-décoder la chaîne:

30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001

c'est le DER-encoding de:

   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
            :         }
            :       }
            :   }

pour une clé RSA 1024 bits, vous pouvez traiter "30819f300d06092a864886f70d010101050003818d00308189028181" comme un en-tête constant, suivi d'un 00-byte, suivi des 128 octets du module RSA. Après cela 95% du temps vous obtiendrez 0203010001 , qui signifie un exposant public RSA de 0x10001 = 65537.

Vous pouvez utiliser ces deux valeurs comme n et e dans un tuple pour construire un RSAobj.

24
répondu Rasmus Faber 2017-05-23 11:45:43

Use M2Crypto . Voici comment vérifier pour RSA et tout autre algorithme pris en charge par 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
28
répondu joeforker 2009-03-03 15:10:00

une clé publique contient à la fois un module(nombre très long, peut être 1024bit, 2058bit, 4096bit) et un exposant de clé publique(nombre beaucoup plus petit, généralement égale un plus qu'un deux à une certaine puissance). Vous devez savoir comment diviser cette clé publique en deux composantes avant de pouvoir faire quoi que ce soit avec elle.

Je ne sais pas grand-chose sur pycrypto mais pour vérifier une signature, prenez le hachage de la chaîne. Maintenant nous devons décrypter la signature. Lire la suite modulaire exponentiation ; la formule pour déchiffrer une signature est message^public exponent % modulus . La dernière étape consiste à vérifier si le hachage que vous avez fait et la signature déchiffrée que vous avez reçue sont les mêmes.

2
répondu user64349 2009-02-13 03:44:34

je pense que ezPyCrypto pourrait rendre cela un peu plus facile. Les méthodes de haut niveau de la classe clé comprend ces deux méthodes qui, je l'espère, va résoudre votre problème:

  • verifyString - vérifier une chaîne de contre signature
  • importKey - importer la clé publique (et peut-être aussi clé privée)

Rasmus souligne dans les commentaires que verifyString est difficile à utiliser MD5, dans ce cas, ezPyCryto ne peut pas aider Andrew à moins qu'il n'écrase dans son code. Je m'en remets à la réponse de joeforker : considérer M2Crypto .

1
répondu Garth Kidd 2017-05-23 12:24:33

plus sur le décodage DER.

DER codage suit toujours une TLV triplet de la forme: (Tag, Longueur, Valeur)

  • Balise spécifie le type (structure de données) de la valeur
  • Longueur indique le nombre d'octets que ce champ de valeur occupe
  • valeur est la valeur réelle qui pourrait être un autre triplet

Tag indique essentiellement comment interpréter les octets données dans le champ Valeur. SNA.1 possède un système de type, par exemple 0x02 signifie entier, 0x30 signifie séquence (une collection ordonnée d'une ou plusieurs autres instances de type)

Longueur de la présentation particulière de la logique:

  • si la longueur est < 127, le champ L n'utilise qu'un octet et est codé Longueur nombre valeur directement
  • si la longueur > 127, alors dans le premier octet du champ L, le premier bit doit être 1, et le reste 7 bits représente le nombre d'suivants bytes utilisés pour spécifier la longueur du champ de valeur. Valeur, la en fait octets de la valeur elle-même.

par exemple, disons que je veux encoder un nombre de 256 octets de long, alors ce serait comme ceci

02  82  01  00  1F  2F  3F  4F  …   DE  AD  BE  EF
  • Tag, 0x02 signifie que c'est un nombre
  • de Longueur, 0x82, peu de présentation des elle est de 1000 0010, sens de la suivant deux octets spécifie la longueur réelle de la valeur, qui son 0x0100 signifiant le champ de valeur est de 256 octets de long
  • valeur, de 1F à EF, les 256 octets réels.

je regarde maintenant votre exemple

30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001

il interprète comme juste ce que Rasmus Faber a mis dans sa réponse

1
répondu Allen Geng 2014-07-31 01:14:49

peut-être que ce n'est pas la réponse que vous cherchez, mais si tout ce dont vous avez besoin est de transformer la clé en bits, il semble que C'est base64 encodé. Regardez le module codecs (je pense) dans la bibliothèque standard de Python.

0
répondu David Z 2009-02-13 02:13:10

en utilisant M2Crypto, les réponses ci-dessus ne fonctionnent pas. Voici une testé exemple.

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'

Et c'est à ce sujet

0
répondu pmhoudry 2015-03-27 13:03:19

j'essaie le code donné par joeforker mais ça ne marche pas. Voici mon exemple de code et il fonctionne très bien.

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"
-1
répondu panlilu 2014-08-08 03:59:08