[PYTHON] Gründe für die Verwendung der Hybridverschlüsselung (Vergleich der Verschlüsselungs- / Entschlüsselungsgeschwindigkeiten)

Es ist bekannt, dass die Verschlüsselung / Entschlüsselung mit der Public-Key-Methode (RSA) einige Zeit in Anspruch nimmt und eine Hybridverschlüsselung verwendet wird. Ich habe tatsächlich die Geschwindigkeit der Ver- und Entschlüsselung gemessen, auch als Notiz darüber, wie man mit einem Programm (Python) verschlüsselt und entschlüsselt.

1. Arten der Verschlüsselung

1.1. Symmetrische Verschlüsselungsmethode (Common Key)

Eine Methode, die denselben Schlüssel für die Ver- und Entschlüsselung verwendet.

AES (Blockverschlüsselung)

Die Blocklänge ist auf 128 Bit festgelegt, und die Schlüssellänge kann 128 Bit, 192 Bit oder 256 Bit betragen.

Kryptografischer Modus

Eine Methode zum Verschlüsseln von Informationen, die länger als die Blocklänge sind, mit Blockverschlüsselung.

1.2 Asymmetrische Verschlüsselungsmethode (öffentlicher Schlüssel)

Eine Methode zum Verschlüsseln mit einem öffentlichen Schlüssel und zum Entschlüsseln mit einem privaten Schlüssel.

RSA-Verschlüsselung

Kryptographie, die die Schwierigkeit diskreter logarithmischer Zahlen und der Primfaktorisierung großer Zahlen nutzt. "Kryptographisch = (normal ** E)% N" Das Paar {E, N} von ist der öffentliche Schlüssel zum Zeitpunkt der Verschlüsselung. Plain = (verschlüsselt ** D)% N Das Paar {D, N} von ist der private Schlüssel zum Zeitpunkt der Entschlüsselung. Verwenden Sie eine Anzahl von 2048 Bit oder mehr als N. 4096bit oder mehr (Ref. NIST SP800-57) zur neuen Verwendung nach 2031. Selbst bei der Verschlüsselungsmethode mit öffentlichem Schlüssel kann die Kommunikation unterbrochen werden, wenn eine böswillige Person zwischen dem Absender und dem Empfänger der Kommunikation eingeht (MITM-Angriff (Man-in-the-Middle)). Ein Public-Key-Zertifikat wird verwendet, um dies zu verhindern. RSA-OAEP verwendet Zufallszahlen, um jedes Mal unterschiedliche Chiffren für denselben Klartext zu generieren.

Elliptischer Kurvencode

Noch kürzere Schlüssel sind stärker als RSA (der elliptische Kurvencode von 224- bis 225-Bit-Schlüsseln entspricht der gleichen Stärke wie 2048-Bit-RSA).

2. Hybridverschlüsselung (Kombination aus Public-Key-Methode und Common-Key-Methode)

Beim Verschlüsseln einer großen Datei mit mehreren MB oder mehr wird die Common-Key-Methode verwendet, da das Ver- und Entschlüsseln der Public-Key-Methode sehr lange dauert. Die Methode des öffentlichen Schlüssels wird verwendet, um den zu diesem Zeitpunkt verwendeten allgemeinen Schlüssel zu kommunizieren. Es wird gesagt, dass für beide die gleiche Verschlüsselungsstärke vorzuziehen ist NIST Special Publication 800-57 Part 1 In Tabelle 2 von Revision 4, "Empfehlungen für die Schlüsselverwaltung" sind die Sicherheitsstärken aufgeführt, die als Referenz verwendet werden können.

Sicherheitsstärke Algorithmus für privaten Schlüssel (allgemeiner Schlüssel) IFC (zB RSA)
128 AES-128 k = 3072
192 AES-192 k = 7680
256 AES-256 k = 15360

3. Vergleich der tatsächlichen Bearbeitungszeit

Die Verarbeitungszeiten von AES-256 und RSA-2048 wurden verglichen. (Obwohl die Stärke unterschiedlich ist ...)

Betriebsumgebung

3.1 Ver- und Entschlüsselung mit symmetrischer Verschlüsselungsmethode (AES-256)

Lesen Sie diese Site und sehen Sie wie folgt aus: AES256.py (Das Auffüllen muss gelöscht werden, wenn es tatsächlich zur Dateiverschlüsselung / -entschlüsselung verwendet wird.)

Wenn Sie AES256.py ausführen (siehe unten),


$ python3 AES256.py 
File size =  10.0 [MB]
Encode:
AES_encrypt_time:0.12138915061950684[sec]
Decode:
AES_decrypt_time:0.12209415435791016[sec]

Das Ergebnis ist wie folgt. Es ist ersichtlich, dass das Ver- und Entschlüsseln einer 10-MB-Datei etwa 0,12 Sekunden dauert.

AES256.py


import sys,struct,random
from Crypto.Cipher import AES
from hashlib import sha256
import time
import os

def generate_salt(digit_num):
    DIGITS_AND_ALPHABETS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    return "".join(random.sample(DIGITS_AND_ALPHABETS, digit_num))

# AES-256
def derive_key_and_iv(password, salt, bs):
    salted = ''.encode()
    dx = ''.encode()
    #AES vom Passwort-Schlüssel für 256 und Anfangsvektor für CBC(iv)Generieren Sie a
    while len(salted) < 48: # 48 =AES256 Schlüssellänge(32byte)+IV Länge(16byte)
        hash = dx + password.encode() + salt.encode()
        dx = sha256(hash).digest()
        salted = salted + dx
    key = salted[0:32] # 32byte -> AES-256 Schlüssellängen
    iv = salted[32:48] # 16byte (AES.block_Gleiche Größe wie Größe,128 Bit in AES(=16byte)Fest)
    return key, iv

#Verschlüsselung
def encrypt(in_file, out_file, password):
    bs = AES.block_size
    #salt = generate_salt() #Random.new().read(bs - len('Salted__'))
    salt = generate_salt(AES.block_size)
    key, iv = derive_key_and_iv(password, salt, bs)

    cipher = AES.new(key, AES.MODE_CBC, iv) #Stellen Sie den CBC-Modus ein. Holen Sie sich die AESCipher-Klasse.
    out_file.write(('Salted__' + salt).encode()) #Salt schreibt in eine verschlüsselte Datei
    finished = False
    while not finished:
        chunk = in_file.read(1024 * bs)
        orgChunkLen = len(chunk)
        if len(chunk) == 0 or len(chunk) % bs != 0:
            padding_length = (bs - len(chunk) % bs) or bs
            padding = padding_length * chr(padding_length)
            chunk += padding.encode()
            finished = True
        if len(chunk) > 0:
            out_file.write(cipher.encrypt(chunk))

#Entschlüsselung
def decrypt(in_file, out_file, password):
    bs = AES.block_size
    in_file.seek(len('Salted__'))
    salt = in_file.read(16).decode()
    #Schlüssel aus Salz und Passwort,Holen Sie sich iv.
    key, iv = derive_key_and_iv(password, salt, bs)

    cipher = AES.new(key, AES.MODE_CBC, iv) #Stellen Sie den CBC-Modus ein. Holen Sie sich die AESCipher-Klasse.
    finished = False

    while not finished:
        chunk = in_file.read(1024 * bs)
        orgChunkLen = len(chunk)
        if orgChunkLen == 0 or orgChunkLen % bs != 0:
            padding_length = (bs - orgChunkLen % bs) or bs
            padding = padding_length * chr(padding_length)
            chunk += padding.encode()
            finished = True
        if orgChunkLen > 0:
            out_file.write(cipher.decrypt(chunk)[0:orgChunkLen])

def main(filename):
    infile = open(filename, "rb")
    outfile = open(filename+"_AES.bin", "wb")

    print("File size = ", os.path.getsize(filename) /1024/1024, "[MB]")
    print("Encode:")
    start = time.time()
    encrypt(infile,outfile,"password")
    # openssl enc -e -aes-256-cbc -salt -k "password" -in practice.bin -out practice_aes.bin
    elapsed_time = time.time() - start
    print ("AES_encrypt_time:{0}".format(elapsed_time) + "[sec]")

    infile.close()
    outfile.close()

    print("Decode:")

    outinfile = open(filename+"_AES.bin", "rb")
    outfile2 = open(filename+"_dec_AES.bin", "wb")

    start = time.time()
    decrypt(outinfile,outfile2,"password")
    elapsed_time = time.time() - start
    print ("AES_decrypt_time:{0}".format(elapsed_time) + "[sec]")

    outinfile.close()
    outfile2.close()

if __name__== "__main__":
  filename = "practice.bin"
  main(filename)

3.2 Verschlüsselung und Entschlüsselung nach der Methode der asymmetrischen Verschlüsselung (öffentlicher Schlüssel) (RSA)

Grundsätzlich sollte RSA nicht zum Verschlüsseln großer Datenmengen verwendet werden. Es wurde in Blöcken zur Geschwindigkeitsmessung implementiert, wird jedoch im Allgemeinen nicht empfohlen. Große Datenmengen werden mit symmetrischer Verschlüsselung wie AES verschlüsselt.

Code geändert mit Bezug auf diese Site und zerlegt 196 Bytes. Geändert, um in Einheiten zu verschlüsseln.

Wenn Sie RSA2048.py ausführen (siehe unten),


$ python3 RSA2048.py 
max_data_len= 196
Generate Key:
privatePem len =  1674
publicPem len =  450
Load Key:
File size =  10.0 [MB]
Encode:
RSA_encrypt_time:46.78378772735596[sec]
Decode:
RSA_decrypt_time:123.22586274147034[sec]

Das Ergebnis ist wie folgt. Sie können sehen, dass das Verschlüsseln einer 10-MB-Datei etwa 47 Sekunden und das Entschlüsseln etwa 123 Sekunden dauert. Da jedes AES ungefähr 0,12 Sekunden dauerte, ist ersichtlich, dass RSA für die Verschlüsselung ungefähr 400-mal langsamer und für die Entschlüsselung ungefähr 1000-mal langsamer ist.

RSA2048.py



from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64
import time
import os

modulus_length = 2048 # bit
max_data_len = int((int(modulus_length/8.0) - 11 )*0.8)  #Die maximale Größe, die mit RSA verschlüsselt werden kann, ist kleiner als die Schlüsselgröße. Hängt davon ab, was Sie zum Auffüllen verwenden.
print("max_data_len=",max_data_len)

def generate_keys():
    key = RSA.generate(modulus_length)
    pub_key = key.publickey()
    return key, pub_key

def encrypt_private_key(a_message, private_key):
    encryptor = PKCS1_OAEP.new(private_key)
    encrypted_msg = encryptor.encrypt(a_message)
    encoded_encrypted_msg = base64.b64encode(encrypted_msg)
    return encoded_encrypted_msg

def decrypt_public_key(encoded_encrypted_msg, public_key):
    encryptor = PKCS1_OAEP.new(public_key)
    decoded_encrypted_msg = base64.b64decode(encoded_encrypted_msg)
    decoded_decrypted_msg = encryptor.decrypt(decoded_encrypted_msg)
    return decoded_decrypted_msg

def encrypt_file(in_file, out_file, key):
    finished =False
    while not finished:
        chunk = in_file.read(max_data_len)
        if len(chunk) == 0 or len(chunk)%max_data_len:
            finished = True
        encdata = encrypt_private_key(chunk, key)
        a_number = len(encdata)
        out_file.write(a_number.to_bytes(4, byteorder='little'))
        out_file.write(encdata)
    out_file.close()

def decrypt_file(in_file, out_file, key):
    finished =False
    while not finished:
        bnum = in_file.read(4)
        inum = int.from_bytes(bnum, byteorder='little')
        chunk = in_file.read(inum)
        if len(chunk) == 0 or len(chunk)%inum:
            finished = True
        if len(chunk) != 0:
          decdata = decrypt_public_key(chunk, key)
          out_file.write(decdata[0:len(chunk)])
    out_file.close()

def main(filename):
    print("Generate Key:")
    private, public = generate_keys()
    privateFile = open("private.pem","wb")
    privatePem = private.exportKey(format='PEM')
    print("privatePem len = ", len(privatePem))
    privateFile.write(privatePem)
    privateFile.close()
    publicFile = open("public.pem","wb")
    publicPem = public.exportKey(format='PEM')
    print("publicPem len = ", len(publicPem))
    publicFile.write(publicPem)
    publicFile.close()
    #print (private)
    #message = b'AES password or key'
    #print(message)
    #encoded = encrypt_private_key(message, public)
    #decrypt_public_key(encoded, private)

    print("Load Key:")
    privateFile = open("private.pem","rb")
    private_pem = privateFile.read()
    privateFile.close()
    private_key = RSA.importKey(private_pem)
    publicFile = open("public.pem","rb")
    public_pem = publicFile.read()
    publicFile.close()
    public_key = RSA.importKey(public_pem)

    print("File size = ", os.path.getsize(filename) /1024/1024, "[MB]")

    print("Encode:")
    infile = open(filename, "rb")
    outfile = open(filename+"_RSA.bin", "wb")
    start = time.time()
    encrypt_file(infile,outfile,public_key)
    elapsed_time = time.time() - start
    print ("RSA_encrypt_time:{0}".format(elapsed_time) + "[sec]")
    infile.close()
    outfile.close()

    print("Decode:")
    infile = open(filename+"_RSA.bin", "rb")
    outfile = open(filename+"_dec_RSA.bin", "wb")
    start = time.time()
    decrypt_file(infile,outfile,private_key)
    elapsed_time = time.time() - start
    print ("RSA_decrypt_time:{0}".format(elapsed_time) + "[sec]")
    infile.close()
    outfile.close()


if __name__== "__main__":
    filename = "practice.bin"
    main(filename)

4. Zusammenfassung

In der tatsächlichen TSL und PGP (GnuPG) wird der Schlüssel (entsprechende Daten) der symmetrischen Verschlüsselungsmethode durch die Methode des öffentlichen Schlüssels ausgetauscht, und die symmetrische Verschlüsselung wird für die tatsächlichen Daten verwendet, dies hat jedoch einen großen Unterschied in der Verarbeitungsgeschwindigkeit und ist für die Öffentlichkeit zugänglich. Es wird gesagt, dass die Ver- / Entschlüsselung der Schlüsselmethode Zeit braucht. Um zu bestätigen, wie stark sich die Verarbeitungsgeschwindigkeit auf Auftragsebene tatsächlich unterscheidet, haben wir Python-Testcode für die symmetrische Verschlüsselungsmethode (AES) und die Public-Key-Methode (RSA) erstellt und verglichen. Als Ergebnis der tatsächlichen Messung dauerte es ungefähr 0,12 Sekunden, bis AES eine 10-MB-Datei verschlüsselt / entschlüsselt hat, während RSA ungefähr 47 Sekunden benötigt, um zu verschlüsseln, was ungefähr 400-mal langsamer ist, und die Entschlüsselung ungefähr 123 ist. Es stellte sich heraus, dass es in Sekunden ungefähr 1000-mal langsamer war.

Nachschlagewerke

Recommended Posts

Gründe für die Verwendung der Hybridverschlüsselung (Vergleich der Verschlüsselungs- / Entschlüsselungsgeschwindigkeiten)
FAQ: Warum ist der Zahlenvergleich inkonsistent?
Warum wird Kreuzentropie für die Zielfunktion des Klassifizierungsproblems verwendet?
Vergleich der Matrixtranspositionsgeschwindigkeit durch Python