how - ¿Cómo se verifica una firma RSA SHA1 en Python?
how to use sha1 in python (8)
Intento 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"
Tengo una cadena, una firma y una clave pública, y quiero verificar la firma en la cadena. La clave se ve así:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfG4IuFO2h/LdDNmonwGNw5srW
nUEWzoBrPRF1NM8LqpOMD45FAPtZ1NmPtHGo0BAS1UsyJEGXx0NPJ8Gw1z+huLrl
XnAVX5B4ec6cJfKKmpL/l94WhP2v8F3OGWrnaEX1mLMoxe124Pcfamt0SPCGkeal
VvXw13PLINE/YptjkQIDAQAB
-----END PUBLIC KEY-----
He estado leyendo pycrypto docs por un tiempo, pero no puedo entender cómo hacer un RSAobj con este tipo de clave. Si conoces PHP, estoy tratando de hacer lo siguiente:
openssl_verify($data, $signature, $public_key, OPENSSL_ALGO_SHA1);
Además, si estoy confundido acerca de cualquier terminología, hágamelo saber.
Tal vez esta no sea la respuesta que está buscando, pero si todo lo que necesita es convertir la clave en bits, parece que está codificada en Base64. Mira el módulo de codecs
(creo) en la biblioteca estándar de Python.
Una clave pública contiene un módulo (número muy largo, puede ser de 1024 bits, 2058 bits, 4096 bits) y un exponente de clave pública (un número mucho más pequeño, por lo general equivale a uno más de dos a cierta potencia). Debe averiguar cómo dividir esa clave pública en los dos componentes antes de poder hacer algo con ella.
No sé mucho sobre pycrypto, pero para verificar una firma, tome el hash de la cadena. Ahora debemos descifrar la firma. Lea sobre la 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 creado y la firma descifrada que obtuvo son iguales.
Use M2Crypto . A continuación, le mostramos cómo verificar RSA y cualquier otro algoritmo admitido 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
Más sobre la decodificación DER.
La codificación DER siempre sigue un formato de triplete TLV: (Etiqueta, Longitud, Valor)
- Tag especifica el tipo (es decir, la estructura de datos) del valor
- Longitud especifica el número de byte que ocupa este campo de valor
- El valor es el valor real que podría ser otro triplete
La etiqueta básicamente dice cómo interpretar los datos de los bytes en el campo Valor. ANS.1 tiene un sistema de tipo, por ejemplo 0x02 significa entero, 0x30 significa secuencia (una colección ordenada de una o más instancias de otro tipo)
La presentación de longitud tiene una lógica especial:
- Si la longitud es <127, el campo L solo usa un byte y se codifica como el valor del número de longitud directamente
- Si la longitud es> 127, entonces en el primer byte del campo L, el primer bit debe ser 1, y el resto 7 bits representa el número de bytes siguientes utilizados para especificar la longitud del campo Valor. Valor, los bytes reales del valor en sí.
Por ejemplo, digamos que quiero codificar un número de 256 bytes de longitud, entonces sería como esto
02 82 01 00 1F 2F 3F 4F … DE AD BE EF
- Tag, 0x02 significa que es un número
- La longitud, 0x82, presentación en bits de la misma es 1000 0010, lo que significa que los dos bytes siguientes especifican la longitud real del valor, que su 0x0100, que significa que el campo de valor tiene 256 bytes de longitud.
- Valor, de 1F a EF, los 256 bytes reales.
Ahora mirando tu ejemplo
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
Interpreta como lo que Rasmus Faber puso en su respuesta
Al usar M2Crypto, las respuestas anteriores no funcionan. Aquí hay 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
Los datos entre los marcadores son la codificación base64 de la codificación DER de ASN.1 de PublicKeyInfo PKCS # 8 que contiene una PKCS # 1 RSAPublicKey.
Esa es una gran cantidad de estándares, y lo mejor será utilizar una biblioteca de cifrado para decodificarlo (como M2Crypto como lo sugiere joeforker ). Trate lo siguiente como información divertida sobre el formato:
Si quieres, puedes decodificarlo así:
Base64-decodificar la cadena:
30819f300d06092a864886f70d010101050003818d0030818902818100df1b822e14eda1fcb74336
6a27c06370e6cad69d4116ce806b3d117534cf0baa938c0f8e4500fb59d4d98fb471a8d01012d54b
32244197c7434f27c1b0d73fa1b8bae55e70155f907879ce9c25f28a9a92ff97de1684fdaff05dce
196ae76845f598b328c5ed76e0f71f6a6b7448f08691e6a556f5f0d773cb20d13f629b6391020301
0001
Esta es la codificación DER 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 una clave RSA de 1024 bits, puede tratar "30819f300d06092a864886f70d010101050003818d00308189028181"
como un encabezado constante, seguido de un byte de 00, seguido de los 128 bytes del módulo de RSA. Después de eso, el 95% de las veces obtendrá 0203010001
, lo que significa un exponente público de RSA de 0x10001 = 65537.
Puede usar esos dos valores como nye en una tupla para construir un RSAobj.
Creo que ezPyCrypto podría hacer esto un poco más fácil. Los métodos de alto nivel de la clase clave incluyen estos dos métodos, que espero que resuelvan su problema:
verifyString - verifica una cadena contra una firmaimportKey - importar clave pública (y posiblemente también clave privada)
Rasmus señala en los comentarios que verifyString
está codificado para usar MD5, en cuyo caso ezPyCryto no puede ayudar a Andrew a menos que ingrese en su código. Aplaudo la respuesta de joeforker : considere M2Crypto .