Ricerca…


introduzione

Python, essendo uno dei linguaggi più popolari nella sicurezza di computer e di rete, ha un grande potenziale in sicurezza e crittografia. Questo argomento tratta le funzionalità e le implementazioni crittografiche in Python dai suoi usi in sicurezza di computer e di rete a algoritmi di hashing e crittografia / decrittografia.

Sintassi

  • hashlib.new (nome)
  • hashlib.pbkdf2_hmac (nome, password, sale, colpi, dklen = Nessuno)

Osservazioni

Molti dei metodi in hashlib richiedono il passaggio di valori interpretabili come buffer di byte anziché stringhe. Questo è il caso di hashlib.new().update() e di hashlib.pbkdf2_hmac . Se si dispone di una stringa, è possibile convertirla in un buffer di byte anteponendo il carattere b all'inizio della stringa:

  "This is a string"
 b"This is a buffer of bytes"

Calcolo di un digest di messaggi

Il modulo hashlib consente di creare generatori di digest di messaggi tramite il new metodo. Questi generatori trasformeranno una stringa arbitraria in un digest a lunghezza fissa:

import hashlib

h = hashlib.new('sha256')
h.update(b'Nobody expects the Spanish Inquisition.')
h.digest()
# ==> b'.\xdf\xda\xdaVR[\x12\x90\xff\x16\xfb\x17D\xcf\xb4\x82\xdd)\x14\xff\xbc\xb6Iy\x0c\x0eX\x9eF-='

Nota che puoi chiamare update un numero arbitrario di volte prima di chiamare digest che è utile per cancellare un grosso file di blocco. Puoi anche ottenere il digest in formato esadecimale usando hexdigest :

h.hexdigest()
# ==> '2edfdada56525b1290ff16fb1744cfb482dd2914ffbcb649790c0e589e462d3d'

Algoritmi di hash disponibili

hashlib.new richiede il nome di un algoritmo quando lo chiami per produrre un generatore. Per scoprire quali algoritmi sono disponibili nell'attuale interprete Python, usa hashlib.algorithms_available :

import hashlib
hashlib.algorithms_available
# ==> {'sha256', 'DSA-SHA', 'SHA512', 'SHA224', 'dsaWithSHA', 'SHA', 'RIPEMD160', 'ecdsa-with-SHA1', 'sha1', 'SHA384', 'md5', 'SHA1', 'MD5', 'MD4', 'SHA256', 'sha384', 'md4', 'ripemd160', 'sha224', 'sha512', 'DSA', 'dsaEncryption', 'sha', 'whirlpool'}

L'elenco restituito varierà in base alla piattaforma e all'interprete; assicurati di controllare che l'algoritmo sia disponibile.

Ci sono anche alcuni algoritmi che sono garantiti per essere disponibili su tutte le piattaforme e gli interpreti, che sono disponibili usando hashlib.algorithms_guaranteed :

hashlib.algorithms_guaranteed
# ==> {'sha256', 'sha384', 'sha1', 'sha224', 'md5', 'sha512'}

Hash password sicura

L' algoritmo PBKDF2 esposto dal modulo hashlib può essere utilizzato per eseguire l'hashing della password sicura. Sebbene questo algoritmo non possa impedire attacchi di forza bruta per recuperare la password originale dall'hash memorizzato, rende tali attacchi molto costosi.

import hashlib
import os

salt = os.urandom(16)
hash = hashlib.pbkdf2_hmac('sha256', b'password', salt, 100000)

PBKDF2 può funzionare con qualsiasi algoritmo di digest, l'esempio precedente usa SHA256 che è generalmente raccomandato. Il sale casuale deve essere memorizzato insieme alla password con hash, sarà necessario nuovamente per confrontare una password inserita con l'hash memorizzato. È essenziale che ogni password sia sottoposta a hash con un diverso salt. Per quanto riguarda il numero di round, si consiglia di impostarlo il più alto possibile per la tua applicazione .

Se si desidera il risultato in formato esadecimale, è possibile utilizzare il modulo binascii :

import binascii
hexhash = binascii.hexlify(hash)

Nota : mentre PBKDF2 non è male, bcrypt e soprattutto scrypt sono considerati più forti contro gli attacchi a forza bruta. Al momento non fanno parte della libreria standard Python.

File Hashing

Un hash è una funzione che converte una sequenza di lunghezza variabile di byte in una sequenza di lunghezza fissa. I file di hash possono essere vantaggiosi per molte ragioni. Gli hash possono essere usati per verificare se due file sono identici o per verificare che il contenuto di un file non sia stato corrotto o modificato.

È possibile utilizzare hashlib per generare un hash per un file:

import hashlib

hasher = hashlib.new('sha256')
with open('myfile', 'r') as f:
    contents = f.read()
    hasher.update(contents)

print hasher.hexdigest() 

Per i file più grandi, è possibile utilizzare un buffer di lunghezza fissa:

import hashlib
SIZE = 65536
hasher = hashlib.new('sha256')
with open('myfile', 'r') as f:
    buffer = f.read(SIZE)
    while len(buffer) > 0:
        hasher.update(buffer)
        buffer = f.read(SIZE)
print(hasher.hexdigest())

Crittografia simmetrica usando pycrypto

La funzionalità crittografica incorporata di Python è attualmente limitata all'hashing. La crittografia richiede un modulo di terze parti come pycrypto . Ad esempio, fornisce l' algoritmo AES che è considerato lo stato dell'arte per la crittografia simmetrica. Il seguente codice crittograferà un dato messaggio usando una passphrase:

import hashlib
import math
import os

from Crypto.Cipher import AES

IV_SIZE = 16    # 128 bit, fixed for the AES algorithm
KEY_SIZE = 32   # 256 bit meaning AES-256, can also be 128 or 192 bits
SALT_SIZE = 16  # This size is arbitrary

cleartext = b'Lorem ipsum'
password = b'highly secure encryption password'
salt = os.urandom(SALT_SIZE)
derived = hashlib.pbkdf2_hmac('sha256', password, salt, 100000,
                              dklen=IV_SIZE + KEY_SIZE)
iv = derived[0:IV_SIZE]
key = derived[IV_SIZE:]

encrypted = salt + AES.new(key, AES.MODE_CFB, iv).encrypt(cleartext)

L'algoritmo AES accetta tre parametri: chiave di crittografia, vettore di inizializzazione (IV) e il messaggio effettivo da crittografare. Se si dispone di una chiave AES generata casualmente, è possibile utilizzarla direttamente e generare semplicemente un vettore di inizializzazione casuale. Tuttavia una passphrase non ha le dimensioni giuste, né sarebbe raccomandabile utilizzarla direttamente dato che non è veramente casuale e quindi ha un'entropia relativamente piccola. Al contrario, utilizziamo l' implementazione incorporata dell'algoritmo PBKDF2 per generare un vettore di inizializzazione a 128 bit e una chiave di crittografia a 256 bit dalla password.

Si noti il ​​sale casuale che è importante avere un vettore di inizializzazione e una chiave diversi per ogni messaggio crittografato. Ciò garantisce in particolare che due messaggi uguali non determinino un testo crittografato identico, ma impedisce anche agli autori degli attacchi di riutilizzare il lavoro trascorso a indovinare una passphrase sui messaggi crittografati con un'altra passphrase. Questo sale deve essere memorizzato insieme al messaggio crittografato per ricavare lo stesso vettore di inizializzazione e la chiave per decrittografare.

Il seguente codice decodificherà nuovamente il nostro messaggio:

salt = encrypted[0:SALT_SIZE]
derived = hashlib.pbkdf2_hmac('sha256', password, salt, 100000,
                              dklen=IV_SIZE + KEY_SIZE)
iv = derived[0:IV_SIZE]
key = derived[IV_SIZE:]
cleartext = AES.new(key, AES.MODE_CFB, iv).decrypt(encrypted[SALT_SIZE:])

Generazione di firme RSA usando pycrypto

RSA può essere utilizzato per creare una firma del messaggio. Una firma valida può essere generata solo con l'accesso alla chiave RSA privata, la convalida d'altra parte è possibile solo con la chiave pubblica corrispondente. Quindi, se l'altra parte conosce la tua chiave pubblica, può verificare che il messaggio sia firmato da te e invariato, ad esempio un approccio utilizzato per la posta elettronica. Attualmente, per questa funzionalità è richiesto un modulo di terze parti come pycrypto .

import errno

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

message = b'This message is from me, I promise.'

try:
    with open('privkey.pem', 'r') as f:
        key = RSA.importKey(f.read())
except IOError as e:
    if e.errno != errno.ENOENT:
        raise
    # No private key, generate a new one. This can take a few seconds.
    key = RSA.generate(4096)
    with open('privkey.pem', 'wb') as f:
        f.write(key.exportKey('PEM'))
    with open('pubkey.pem', 'wb') as f:
        f.write(key.publickey().exportKey('PEM'))

hasher = SHA256.new(message)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hasher)

La verifica della firma funziona in modo simile ma utilizza la chiave pubblica anziché la chiave privata:

with open('pubkey.pem', 'rb') as f:
    key = RSA.importKey(f.read())
hasher = SHA256.new(message)
verifier = PKCS1_v1_5.new(key)
if verifier.verify(hasher, signature):
    print('Nice, the signature is valid!')
else:
    print('No, the message was signed with the wrong private key or modified')

Nota : gli esempi precedenti utilizzano l'algoritmo di firma PKCS # 1 v1.5 che è molto comune. pycrypto implementa anche il nuovo algoritmo PKCS # 1 PSS, sostituendo PKCS1_v1_5 con PKCS1_PSS negli esempi dovrebbe funzionare se si desidera utilizzare quello. Attualmente sembra che ci siano poche ragioni per usarlo comunque.

Crittografia asimmetrica RSA usando pycrypto

La crittografia asimmetrica ha il vantaggio che un messaggio può essere crittografato senza scambiare una chiave segreta con il destinatario del messaggio. Il mittente ha semplicemente bisogno di conoscere la chiave pubblica dei destinatari, ciò consente di crittografare il messaggio in modo tale che solo il destinatario designato (che ha la chiave privata corrispondente) possa decrittografarlo. Attualmente, per questa funzionalità è richiesto un modulo di terze parti come pycrypto .

from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA

message = b'This is a very secret message.'

with open('pubkey.pem', 'rb') as f:
    key = RSA.importKey(f.read())
cipher = PKCS1_OAEP.new(key)
encrypted = cipher.encrypt(message)

Il destinatario può decifrare il messaggio, se ha la chiave privata giusta:

with open('privkey.pem', 'rb') as f:
    key = RSA.importKey(f.read())
cipher = PKCS1_OAEP.new(key)
decrypted = cipher.decrypt(encrypted)

Nota : gli esempi sopra riportati utilizzano lo schema di crittografia OAEP PKCS # 1. pycrypto implementa anche lo schema di crittografia PKCS # 1 v1.5, questo non è raccomandato per i nuovi protocolli, tuttavia a causa di avvertimenti noti .



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow