Pregunta

Tengo una cadena, una firma y una clave pública, y quiero verificar la firma en la cadena.La clave parece a esto:

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

He estado leyendo el pycrypto docs por un tiempo, pero no puedo averiguar cómo hacer que un RSAobj con este tipo de clave.Si sabes PHP, estoy tratando de hacer lo siguiente:

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

También, si estoy confundido acerca de cualquier terminología, por favor hágamelo saber.

¿Fue útil?

Solución

Los datos entre los marcadores es la codificación base64 de la ASN.1 DER-codificación de un PKCS # 8 PublicKeyInfo que contiene un PKCS # 1 RSAPublicKey.

Esto es una gran cantidad de normas, y se le sirve mejor con el uso de un cripto-biblioteca para descodificarlo (como M2Crypto como sugerido por joeforker ). El tratamiento de los siguientes como algo de información sobre el formato de la diversión:

Si desea, puede decodificar esta manera:

Base 64-decodificar la cadena:

30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001

Esta es la DER-codificación 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
            :         }
            :       }
            :   }

Para obtener una clave RSA de 1024 bits, se puede tratar como una cabecera "30819f300d06092a864886f70d010101050003818d00308189028181" constante, seguido de un 00 bytes, seguido por los 128 bytes del módulo RSA. Después de que el 95% de las veces obtendrá 0203010001, lo que significa un exponente público RSA de 0x10001 = 65537.

Puede usar esos dos valores como n y e en una tupla para construir un RSAobj.

Otros consejos

M2Crypto . Aquí es cómo comprobar para RSA y cualquier otro algoritmo apoyado por 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

Una clave pública contiene un módulo (número muy largo, puede ser 1024bit, 2058bit, 4096bit) y un exponente de clave pública (número mucho menor, por lo general es igual a uno más de dos a alguna potencia). Es necesario averiguar cómo dividir esa clave pública en los dos componentes antes de poder hacer nada con ella.

No sé mucho acerca de pycrypto sino para verificar una firma, tomo el hash de la cadena. Ahora hay que descifrar la firma. Lea sobre exponenciación modular ; la fórmula para descifrar una firma es message^public exponent % modulus. El último paso es comprobar si el hash que ha hecho y la firma descifrada que tienes son los mismos.

Creo ezPyCrypto podría hacer esto un poco más fácil. Los métodos de alto nivel de la tecla clase comprende estos dos métodos que espero va a resolver su problema:

  • verifyString - verificar una cadena contra una firma
  • importkey - importación de clave pública (y la clave privada, posiblemente, también)

Rasmus señala en los comentarios que verifyString es modificable a utilizar MD5, en cuyo caso puede ezPyCryto 't ayudar a Andrew a menos que se adentra en su código. Delego en :. M2Crypto

Más sobre el DER de decodificación.

DER codificación de siempre sigue un TLV triplete formato:(Etiqueta, Longitud, Valor)

  • Etiqueta especifica el tipo (es decir,estructura de datos) del valor
  • Longitud especifica el número de bytes que este valor de campo ocupa
  • Valor es el valor real que podría ser otro triplete

Etiqueta básicamente le dice cómo interpretar los bytes de datos en el campo Valor.ANS.1 tiene un sistema de tipo, por ejemplo,0x02 significa entero, 0x30 medio de la secuencia (una colección ordenada de uno o más de otro tipo de instancias)

La longitud de presentación tiene una lógica particular:

  • Si la longitud < 127, el L campo sólo se utiliza un byte y se codificaron como el la longitud del número de valor directamente
  • Si la longitud > 127, en el primer byte de L campo, el primer bit debe ser 1, y el resto 7 bits que representa el número de la siguiente bytes utilizados para especifica la longitud del campo de Valor.El valor, la en realidad bytes del valor en sí mismo.

Por ejemplo, supongamos que queremos codificar un número de 256 bytes, entonces sería como este

02  82  01  00  1F  2F  3F  4F  …   DE  AD  BE  EF
  • Etiqueta, 0x02 significa que es un número
  • Longitud, 0x82, bits de presentación de la misma es de 1000 0010, es decir, la siguientes dos bytes especifica la longitud del valor, que su 0x0100 significado el valor del campo es de 256 bytes de largo
  • El valor, desde 1F de la EF, el real 256 bytes.

Ahora mirando su ejemplo

30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001

Se interpreta como sólo lo Rasmus Faber poner en su respuesta

Tal vez esta no es la respuesta que está buscando, pero si todo lo que necesita es a su vez la clave en bits, que parece que está codificado en Base64. Mira el módulo codecs (creo) en la biblioteca estándar de Python.

El uso de M2Crypto, las respuestas anteriores no funciona. Este es un ejemplo probado.

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'

Y eso es todo

Trato el código dado por joeforker pero no funciona. Aquí está mi código de ejemplo y funciona 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"
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top