Il est connu que le chiffrement / déchiffrement par la méthode de clé publique (RSA) prend du temps et un chiffrement hybride est utilisé. J'ai en fait mesuré la vitesse de cryptage et de décryptage, également comme mémo sur la façon de crypter et de décrypter avec un programme (Python).
Une méthode qui utilise la même clé pour le chiffrement et le déchiffrement.
La longueur du bloc est fixée à 128 bits et la longueur de la clé peut être de 128 bits, 192 bits ou 256 bits.
Une méthode pour crypter des informations plus longues que la longueur de bloc avec un cryptage par bloc.
Mode ECB (Electronic CodeBook) Divisez simplement en blocs et cryptez. Le même texte brut devient le même texte de code. Non recommandé.
Mode CBC (Cipher Block Chaining) Cryptez avec XOR avec le chiffrement du bloc précédent. Le plus souvent utilisé. Puisqu'il est crypté séquentiellement, il ne peut pas être traité en parallèle pendant le cryptage.
Mode CTR (COUNTeR) Le compteur est incrémenté pour chaque bloc à crypter et XOR avec du texte brut pour créer un cryptage par bloc.
Méthode de chiffrement avec une clé publique et de déchiffrement avec une clé privée.
Cryptographie qui utilise la difficulté des nombres logarithmiques discrets et la factorisation de grands nombres premiers.
Cryptographique = (plain ** E)% N
La paire {E, N} de est la clé publique au moment du chiffrement.
Simple = (crypté ** D)% N
La paire {D, N} de est la clé privée au moment du déchiffrement.
Utilisez un nombre de 2048 bits ou plus comme N. 4096 bits ou plus (réf. NIST SP800-57) pour une nouvelle utilisation après 2031.
Même avec la méthode de chiffrement à clé publique, si une personne malveillante entre entre l'expéditeur et le destinataire de la communication, la communication peut être interrompue (attaque MITM (man-in-the-middle)). Un certificat de clé publique est utilisé pour éviter cela.
RSA-OAEP utilise des nombres aléatoires pour générer à chaque fois différents chiffrements pour le même texte brut.
Des clés encore plus courtes sont plus puissantes que RSA (le code de courbe elliptique de clés de 224 à 225 bits équivaut à la même force que RSA 2048 bits).
Lors du chiffrement d'un fichier volumineux de plusieurs Mo ou plus, la méthode de la clé commune est utilisée car le chiffrement et le déchiffrement de la méthode de la clé publique prennent beaucoup de temps. La méthode de la clé publique est utilisée pour communiquer la clé commune utilisée à ce moment. On dit que le même niveau de force de cryptage est préférable pour les deux, Publication spéciale NIST 800-57 Partie 1 Le tableau 2 de la révision 4, «Recommandations pour la gestion des clés» répertorie les points forts de sécurité pouvant être utilisés comme référence.
Force de sécurité | Algorithme de clé privée (clé commune) | IFC (par exemple RSA) |
---|---|---|
128 | AES-128 | k = 3072 |
192 | AES-192 | k = 7680 |
256 | AES-256 | k = 15360 |
Les temps de traitement de l'AES-256 et du RSA-2048 ont été comparés. (Bien que la force soit différente ...)
pip install pycrypto pyOpenSSL
Reportez-vous à ce site et ressemblez à l'AES256.py suivant (Il est nécessaire de supprimer le remplissage lors de son utilisation réelle pour le cryptage / décryptage de fichiers).
Lorsque vous exécutez AES256.py illustré ci-dessous,
$ python3 AES256.py
File size = 10.0 [MB]
Encode:
AES_encrypt_time:0.12138915061950684[sec]
Decode:
AES_decrypt_time:0.12209415435791016[sec]
Le résultat est le suivant. On peut voir qu'il faut environ 0,12 seconde pour crypter et décrypter un fichier de 10 Mo.
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 à partir du mot de passe-Clé pour 256 et vecteur initial pour CBC(iv)Générer un
while len(salted) < 48: # 48 =Longueur de clé AES256(32byte)+Longueur IV(16byte)
hash = dx + password.encode() + salt.encode()
dx = sha256(hash).digest()
salted = salted + dx
key = salted[0:32] # 32byte -> AES-256 longueurs de clé
iv = salted[32:48] # 16byte (AES.block_Même taille que la taille,128 bits en AES(=16byte)Fixé)
return key, iv
#chiffrement
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) #Réglez le mode CBC. Obtenez la classe AESCipher.
out_file.write(('Salted__' + salt).encode()) #salt écrit dans un fichier chiffré
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))
#Décryptage
def decrypt(in_file, out_file, password):
bs = AES.block_size
in_file.seek(len('Salted__'))
salt = in_file.read(16).decode()
#clé de sel et mot de passe,Obtenez iv.
key, iv = derive_key_and_iv(password, salt, bs)
cipher = AES.new(key, AES.MODE_CBC, iv) #Réglez le mode CBC. Obtenez la classe AESCipher.
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)
Fondamentalement, RSA n'est pas censé être utilisé pour crypter des données de grande taille. Il a été implémenté en morceaux pour la mesure de la vitesse, mais il n'est généralement pas recommandé. Les données de grande taille sont cryptées à l'aide d'un cryptage symétrique tel qu'AES.
Code modifié en référence à ce site et fragmenté 196 octets. Changé pour chiffrer en unités.
Lorsque vous exécutez RSA2048.py illustré ci-dessous,
$ 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]
Le résultat est le suivant. Vous pouvez voir qu'il faut environ 47 secondes pour crypter un fichier de 10 Mo et environ 123 secondes pour le décrypter. Étant donné que chaque AES a pris environ 0,12 seconde, on peut voir que RSA est environ 400 fois plus lent pour le cryptage et environ 1000 fois plus lent pour le décryptage.
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) #La taille maximale pouvant être chiffrée avec RSA est inférieure à la taille de la clé. Dépend de ce que vous utilisez pour le rembourrage.
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)
Dans la TSL et PGP (GnuPG), la clé de la méthode de cryptage symétrique (données équivalentes) est échangée par la méthode de clé publique, et le cryptage symétrique est utilisé pour les données réelles, mais cela a une grande différence de vitesse de traitement et est ouvert au public On dit que le cryptage / décryptage de la méthode de clé prend du temps. Ici, afin de confirmer à quel point la vitesse de traitement diffère réellement au niveau de la commande, nous avons créé et comparé le code de test Python pour la méthode de cryptage symétrique (AES) et la méthode de clé publique (RSA). En raison de la mesure réelle, il a fallu environ 0,12 seconde à AES pour crypter / décrypter un fichier de 10 Mo, tandis que RSA prend environ 47 secondes pour crypter, ce qui est environ 400 fois plus lent, et le décryptage est d'environ 123. Il s'est avéré être environ 1000 fois plus lent en quelques secondes.
Recommended Posts