2010-11-20 14 views

Odpowiedz

19

To jest uregulowana out wersja example in the 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) 
+0

Dzięki, to bardzo pomocne, tylko jedno pytanie, co znaczy "" w 'signature = RSAkey.sign (hash," ")'? –

+0

Ponadto widzę, że podpis jest krotką, co jest dobrym sposobem przechowywania tego w sposób przenośny? –

+2

@Noah McIlraith: Dla RSA drugi argument "K" nie jest używany. W przypadku ElGamala i DSA należy podać długi łańcuch lub dane losowe "K". Szczegóły można znaleźć w http://www.dlitz.net/software/pycrypto/doc/#crypto-publickey-public-key-algorithms w sekcji zatytułowanej "Algorytmy ElGamal i DSA". – unutbu

11

Zgodnie z dokumentacją pod adresem:

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

nie należy używać funkcji Crypto.PublicKey.RSA.sign z PyCrypto w rzeczywistym kodzie:

Uwaga: ta funkcja działa s zwykły, prymitywny deszyfrator RSA (podręcznik). W prawdziwych aplikacjach zawsze trzeba używać odpowiedniego dopełnienia kryptograficznego i nie należy bezpośrednio podpisywać danych za pomocą tej metody. Nieprzestrzeganie tego może prowadzić do luk w zabezpieczeniach. Zaleca się zamiast tego używać modułów Crypto.Signature.PKCS1_PSS lub Crypto.Signature.PKCS1_v1_5.

Skończyło się na użyciu RSA module, który implementuje PKCS1_v1_5. Model documentation for signing był całkiem prosty. Inne have recommended use M2Crypto.

3

Poniżej helper class stworzyłem, aby wykonać wszystkie niezbędne funkcje RSA (szyfrowanie, deszyfrowanie, podpisywania, weryfikacji podpisu & generując nowe klucze)

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) 

Próbka Wykorzystanie

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) 
+0

Uważam, że jest to mylące. podpis dla RSA.encrypt to '' '(message, pub_key)' '' ale wywołanie w przykładzie użycia jest '' 'rsa.encrypt (msg1, private)' '', sprawiając, że wydaje się, że chce klucza publicznego, ale faktycznie dostaje klucz prywatny . Ponadto, rsa.newkeys() zwraca dwie wartości, z których jedna pochodzi od drugiej (w szczególności '' '(x, x.public_key())' ''), która wydaje się zupełnie inna niż "zwykły angielski" interpretacja '' '(public, private)' '' – mwag

+0

dzięki za wskazanie błędu w Sample Use (teraz zaktualizowany). Aby wykonać szyfrowanie, musisz wywołać 'rsa.encrypt (msg1, public)'. W przypadku RSA potrzebujesz klucza publicznego do szyfrowania i weryfikacji, klucz prywatny jest potrzebny do odszyfrowania i podpisania. Zawsze możesz też uzyskać "klucz publiczny" z "klucza prywatnego", ale nie jest to możliwe z drugiej strony – Dennis

Powiązane problemy