Firma y verificación de datos usando pycrypto (RSA)

Estoy tratando de familiarizarme con el módulo pycrypto, pero la falta de documentación clara dificulta las cosas.

Para empezar, me gustaría entender cómo firmar y verificar datos. ¿Podría alguien dar un ejemplo de cómo se escribiría esto?

Esta es una versión completa del ejemplo en la documentación:

import Crypto.Hash.MD5 as MD5 import Crypto.PublicKey.RSA as RSA import Crypto.PublicKey.DSA as DSA import Crypto.PublicKey.ElGamal as ElGamal import Crypto.Util.number as CUN import os plaintext = 'The rain in Spain falls mainly on the Plain' # Here is a hash of the message hash = MD5.new(plaintext).digest() print(repr(hash)) # '\xb1./J\xa883\x974\xa4\xac\x1e\x1b!\xc8\x11' for alg in (RSA, DSA, ElGamal): # Generates a fresh public/private key pair key = alg.generate(384, os.urandom) if alg == DSA: K = CUN.getRandomNumber(128, os.urandom) elif alg == ElGamal: K = CUN.getPrime(128, os.urandom) while CUN.GCD(K, key.p - 1) != 1: print('K not relatively prime with {n}'.format(n=key.p - 1)) K = CUN.getPrime(128, os.urandom) # print('GCD({K},{n})=1'.format(K=K,n=key.p-1)) else: K = '' # You sign the hash signature = key.sign(hash, K) print(len(signature), alg.__name__) # (1, 'Crypto.PublicKey.RSA') # (2, 'Crypto.PublicKey.DSA') # (2, 'Crypto.PublicKey.ElGamal') # You share pubkey with Friend pubkey = key.publickey() # You send message (plaintext) and signature to Friend. # Friend knows how to compute hash. # Friend verifies the message came from you this way: assert pubkey.verify(hash, signature) # A different hash should not pass the test. assert not pubkey.verify(hash[:-1], signature) 

Según la documentación en:

https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html

no debe usar la función Crypto.PublicKey.RSA.sign de PyCrypto en código real:

Atención: esta función realiza el descifrado RSA simple y primitivo (libro de texto). En aplicaciones reales, siempre debe usar el relleno criptográfico adecuado, y no debe firmar directamente los datos con este método. De lo contrario, se pueden producir vulnerabilidades de seguridad. Se recomienda utilizar los módulos Crypto.Signature.PKCS1_PSS o Crypto.Signature.PKCS1_v1_5 en su lugar.

Terminé usando el módulo RSA que implementa PKCS1_v1_5. La documentación para la firma fue bastante sencilla. Otros han recomendado usar M2Crypto .

A continuación se muestra la clase de ayuda que creé para realizar todas las funciones RSA necesarias (cifrado, descifrado, firma, verificación de firmas y generación de nuevas claves)

rsa.py

 from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP from Crypto.Signature import PKCS1_v1_5 from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5 from Crypto import Random from base64 import b64encode, b64decode hash = "SHA-256" def newkeys(keysize): random_generator = Random.new().read key = RSA.generate(keysize, random_generator) private, public = key, key.publickey() return public, private def importKey(externKey): return RSA.importKey(externKey) def getpublickey(priv_key): return priv_key.publickey() def encrypt(message, pub_key): #RSA encryption protocol according to PKCS#1 OAEP cipher = PKCS1_OAEP.new(pub_key) return cipher.encrypt(message) def decrypt(ciphertext, priv_key): #RSA encryption protocol according to PKCS#1 OAEP cipher = PKCS1_OAEP.new(priv_key) return cipher.decrypt(ciphertext) def sign(message, priv_key, hashAlg="SHA-256"): global hash hash = hashAlg signer = PKCS1_v1_5.new(priv_key) if (hash == "SHA-512"): digest = SHA512.new() elif (hash == "SHA-384"): digest = SHA384.new() elif (hash == "SHA-256"): digest = SHA256.new() elif (hash == "SHA-1"): digest = SHA.new() else: digest = MD5.new() digest.update(message) return signer.sign(digest) def verify(message, signature, pub_key): signer = PKCS1_v1_5.new(pub_key) if (hash == "SHA-512"): digest = SHA512.new() elif (hash == "SHA-384"): digest = SHA384.new() elif (hash == "SHA-256"): digest = SHA256.new() elif (hash == "SHA-1"): digest = SHA.new() else: digest = MD5.new() digest.update(message) return signer.verify(digest, signature) 

Uso de la muestra

 import rsa from base64 import b64encode, b64decode msg1 = "Hello Tony, I am Jarvis!" msg2 = "Hello Toni, I am Jarvis!" keysize = 2048 (public, private) = rsa.newkeys(keysize) encrypted = b64encode(rsa.encrypt(msg1, public)) decrypted = rsa.decrypt(b64decode(encrypted), private) signature = b64encode(rsa.sign(msg1, private, "SHA-512")) verify = rsa.verify(msg1, b64decode(signature), public) print(private.exportKey('PEM')) print(public.exportKey('PEM')) print("Encrypted: " + encrypted) print("Decrypted: '%s'" % decrypted) print("Signature: " + signature) print("Verify: %s" % verify) rsa.verify(msg2, b64decode(signature), public)