web-dev-qa-db-fra.com

Signature et vérification des données à l'aide de pycrypto (RSA)

J'essaie de me familiariser avec le module pycrypto, mais le manque de documentation claire rend les choses difficiles.

Pour commencer, je voudrais comprendre la signature et la vérification des données. Quelqu'un pourrait-il donner un exemple de la façon dont cela serait écrit?

21
Noah McIlraith

Ceci est une version étoffée de la exemple dans la documentation:

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)
20
unutbu

Ci-dessous se trouve le classe d'assistance que j'ai créé pour effectuer toutes les fonctions RSA nécessaires (cryptage, décryptage, signature, vérification de signature et génération de nouvelles clés)

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)

Exemple d'utilisation

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)
13
Dennis

Selon la documentation à:

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

vous ne devez pas utiliser la fonction Crypto.PublicKey.RSA.sign de PyCrypto en code réel:

Attention: cette fonction effectue le décryptage RSA simple et primitif (manuel). Dans les applications réelles, vous devez toujours utiliser un remplissage cryptographique approprié et vous ne devez pas signer directement les données avec cette méthode. Ne pas le faire peut entraîner des failles de sécurité. Il est recommandé d'utiliser à la place les modules Crypto.Signature.PKCS1_PSS ou Crypto.Signature.PKCS1_v1_5.

J'ai fini par utiliser le module RSA qui implémente PKCS1_v1_5. Le documentation pour la signature était assez simple. Autres ont recommandé d'utiliser M2Crypto .

13
jeffmax