Sök…


Introduktion

Python är ett av de mest populära språken inom dator- och nätverkssäkerhet och har stor potential inom säkerhet och kryptografi. Detta ämne behandlar de kryptografiska funktionerna och implementeringarna i Python från dess användningar inom dator- och nätverkssäkerhet till hash- och krypterings- / dekrypteringsalgoritmer.

Syntax

  • hashlib.new (namn)
  • hashlib.pbkdf2_hmac (namn, lösenord, salt, rundor, dklen = Ingen)

Anmärkningar

Många av metoderna i hashlib kräver att du hashlib värden som kan tolkas som buffertar av byte snarare än strängar. Detta är fallet för hashlib.new().update() samt hashlib.pbkdf2_hmac . Om du har en sträng kan du konvertera den till en byte-buffert genom att förbereda tecknet b till strängens början:

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

Beräkna ett meddelande Digest

hashlib modulen tillåter att skapa meddelandegeneratorgeneratorer via den new metoden. Dessa generatorer kommer att förvandla en godtycklig sträng till en fast längd-uppfattning:

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-='

Observera att du kan ringa update ett godtyckligt antal gånger innan du ringer digest vilket är användbart för att hash en stor filbit av bit. Du kan också få digereringen i hexadecimalt format genom att använda hexdigest :

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

Tillgängliga Hashing-algoritmer

hashlib.new kräver namnet på en algoritm när du kallar den för att producera en generator. För att ta reda på vilka algoritmer som finns tillgängliga i den aktuella Python-tolkaren, använd 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'}

Den returnerade listan kommer att variera beroende på plattform och tolk; se till att du kontrollerar att din algoritm är tillgänglig.

Det finns också några algoritmer som garanterat är tillgängliga på alla plattformar och tolkar, som är tillgängliga med hashlib.algorithms_guaranteed :

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

Secure Password Hashing

PBKDF2-algoritmen som exponeras av hashlib modulen kan användas för att utföra säker lösenord-hashing. Även om denna algoritm inte kan förhindra brute-force attacker för att återställa det ursprungliga lösenordet från den lagrade hash, gör den sådana attacker mycket dyra.

import hashlib
import os

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

PBKDF2 kan fungera med vilken som helst digergalgoritm, exemplet ovan använder SHA256 som vanligtvis rekommenderas. Det slumpmässiga saltet bör lagras tillsammans med hash-lösenordet, du behöver det igen för att jämföra ett inmatat lösenord med det lagrade hashet. Det är viktigt att varje lösenord hashas med ett annat salt. När det gäller antalet omgångar rekommenderas det att ställa in det så högt som möjligt för din ansökan .

Om du vill ha resultatet i hexadecimal kan du använda binascii modulen:

import binascii
hexhash = binascii.hexlify(hash)

Obs : Även om PBKDF2 inte är dåligt, betraktas bcrypt och särskilt scrypt som starkare mot brute-force attacker. Inte heller ingår i Pythons standardbibliotek för tillfället.

File Hashing

En hash är en funktion som konverterar en sekvens med variabel längd av byte till en sekvens med fast längd. Hashing-filer kan vara fördelaktiga av många skäl. Hashes kan användas för att kontrollera om två filer är identiska eller för att kontrollera att innehållet i en fil inte har skadats eller ändrats.

Du kan använda hashlib att generera en hash för en fil:

import hashlib

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

print hasher.hexdigest() 

För större filer kan en buffert med fast längd användas:

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())

Symmetrisk kryptering med pycrypto

Pythons inbyggda kryptofunktionalitet är för närvarande begränsad till hashing. Kryptering kräver en tredjepartsmodul som pycrypto . Till exempel tillhandahåller den AES-algoritmen som anses vara känd för symmetrisk kryptering. Följande kod krypterar ett givet meddelande med en lösenfras:

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)

AES-algoritmen tar tre parametrar: krypteringsnyckel, initialiseringsvektor (IV) och det faktiska meddelandet som ska krypteras. Om du har en slumpmässigt genererad AES-nyckel kan du använda den direkt och bara skapa en slumpmässig initialiseringsvektor. En lösenfras har emellertid inte rätt storlek, och det vore heller inte att rekommendera att använda det direkt med tanke på att det inte är riktigt slumpmässigt och därmed har jämförelsevis liten entropi. Istället använder vi den inbyggda implementeringen av PBKDF2-algoritmen för att generera en 128-bitars initialiseringsvektor och 256-bitars krypteringsnyckel från lösenordet.

Notera det slumpmässiga saltet som är viktigt för att ha en annan initialiseringsvektor och nyckel för varje krypterat meddelande. Detta säkerställer särskilt att två lika meddelanden inte kommer att resultera i identisk krypterad text, men det förhindrar också angripare att återanvända arbete som gett en gissfras på meddelanden som är krypterade med en annan lösenfras. Detta salt måste lagras tillsammans med det krypterade meddelandet för att härleda samma initialiseringsvektor och nyckel för dekryptering.

Följande kod dekrypterar vårt meddelande igen:

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:])

Generera RSA-signaturer med pycrypto

RSA kan användas för att skapa en meddelandesignatur. En giltig signatur kan endast genereras med åtkomst till den privata RSA-nyckeln, validering å andra sidan är möjlig med endast motsvarande offentlig nyckel. Så så länge den andra sidan känner till din offentliga nyckel kan de verifiera meddelandet som ska undertecknas av dig och oförändrat - en metod som används till exempel för e-post. För närvarande krävs en tredjepartsmodul som pycrypto för denna funktion.

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)

Verifiering av signaturen fungerar på liknande sätt men använder den offentliga nyckeln snarare än den privata nyckeln:

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')

Obs : Exemplen ovan använder PKCS # 1 v1.5-signeringsalgoritm som är mycket vanligt. pycrypto implementerar också den nyare PKCS # 1 PSS-algoritmen och ersätter PKCS1_v1_5 av PKCS1_PSS i exemplen bör fungera om du vill använda den. För närvarande verkar det dock finnas liten anledning att använda det .

Asymmetrisk RSA-kryptering med hjälp av pycrypto

Asymmetrisk kryptering har fördelen att ett meddelande kan krypteras utan att byta ut en hemlig nyckel med mottagaren av meddelandet. Avsändaren behöver bara känna till mottagarens offentliga nyckel, detta tillåter att kryptera meddelandet på ett sådant sätt att endast den utsedda mottagaren (som har motsvarande privata nyckel) kan dekryptera det. För närvarande krävs en tredjepartsmodul som pycrypto för denna funktion.

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)

Mottagaren kan dekryptera meddelandet då om de har rätt privat nyckel:

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

Obs : Ovanstående exempel använder PKCS # 1 OAEP-krypteringsschema. pycrypto implementerar också PKCS # 1 v1.5-krypteringsschema, detta rekommenderas inte för nya protokoll men på grund av kända varningar .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow