PyCrypto: Verschlüsselt eine Zeichenkette zweimal mit RSA und PKCS#1

Hallo an alle.

Ich Frage mich, ob es möglich ist, führen Sie einen Doppelklick RSA/PKCS#1 Verschlüsselung mit PyCrypto.

Ich habe einen server, der hat seinen eigenen RSA-Schlüssel (erzeugt mit der openssl Befehl, wenn dieser server installiert ist) und einen client kann verlangen, dass der öffentliche Teil des server ' s key. Auch, kann der client kann den server auffordern, ein anderes erzeugen der RSA-Schlüssel (oder das Schlüsselpaar) für Sie. In diesem Fall, der server hält auch das private (oder das "ganze" RSA-Schlüssel) und sendet dem client den öffentlichen Teil seines Schlüssels.

Ich habe das Spiel mit RSA/PKCS-und AES-Verschlüsselung. Habe ich einen test Python-Datei, funktioniert die Verschlüsselung nur mit einem RSA-Schlüssel. Was es tut, ist eine Verschlüsselung der Daten mit dem symmetrischen AES-system (verwendet wird ein zufälliger Schlüssel generiert "on-the-fly"), cyphers das Passwort für die AES mit dem RSA/PKCS#1 system und stellt ihn in der Folge geschickt zu werden:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Interesting links: 
# 1> http://stackoverflow.com/a/9039039/289011
# 2> http://eli.thegreenplace.net/2010/06/25/aes-encryption-of-files-in-python-with-pycrypto/

from Crypto.PublicKey import RSA
import base64
import os
from Crypto.Cipher import AES
import Crypto.Util.number
import random
import struct
import cStringIO
from Crypto.Cipher import PKCS1_OAEP

def encrypt(string):
    #Begin RSA Part to get a cypher that uses the server's public key
    externKeyFilename="/home/borrajax/rsaKeys/server-key.pub"
    externKeyFile = open(externKeyFilename, "r")
    rsaKey= RSA.importKey(externKeyFile, passphrase="F00bAr")
    pkcs1Encryptor=PKCS1_OAEP.new(rsaKey)
    #End RSA Part

    #Begin AES Part
    iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
    thisMessagePassword = os.urandom(16)
    aesEncryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
    chunksize=64*1024
    #End AES Part

    #Begin RSA Encription of the AES Key
    rsaEncryptedPassword = pkcs1Encryptor.encrypt(thisMessagePassword)

    retvalTmp = cStringIO.StringIO()
    retvalTmp.write(struct.pack('<Q', len(string)))
    retvalTmp.write(struct.pack('<Q', len(rsaEncryptedPassword)))
    retvalTmp.write(rsaEncryptedPassword)
    retvalTmp.write(iv)
    while len(string) > 0:
        chunk = string[0:chunksize]
        string = string[chunksize:]
        if len(chunk) % 16 != 0:
            chunk += ' ' * (16 - len(chunk) % 16)
        retvalTmp.write(aesEncryptor.encrypt(chunk))
    return retvalTmp.getvalue()

def decrypt(string):
    stringAsBuffer = cStringIO.StringIO(string)
    retval = str()
    chunksize=64*1024

    externKeyFilename="/home/borrajax/rsaKeys/server-key.pem"
    externKey = open(externKeyFilename, "r")
    rsaKey = RSA.importKey(externKey, passphrase="F00bAr")
    pkcs1Decryptor=PKCS1_OAEP.new(rsaKey)


    origsize = struct.unpack('<Q', stringAsBuffer.read(struct.calcsize('Q')))[0]
    rsaEncryptedPasswordLength = long(struct.unpack('<Q', stringAsBuffer.read(struct.calcsize('Q')))[0])
    rsaEncryptedPassword = stringAsBuffer.read(rsaEncryptedPasswordLength)
    thisMessagePassword = pkcs1Decryptor.decrypt(rsaEncryptedPassword)
    iv = stringAsBuffer.read(16)
    decryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
    while True:
        chunk = stringAsBuffer.read(chunksize)
        if len(chunk) == 0:
            break
        retval += decryptor.decrypt(chunk)
    return retval



if __name__ == "__main__":
    encryptedThingy=encrypt(base64.b64encode("Toñóooooañjfl凯兰;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凯兰;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凯兰;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凯兰;kañañfjaafafs凱蘭pingüiñoo你好to金玉Toñóooooañjfl凯兰;kañañfjaafafs凱蘭pingüiñoo你好to金玉"))
    print "Decrypted thingy: %s" % base64.b64decode(decrypt(encryptedThingy))

Wie Sie sehen können, wird der AES-Passwort ist verschlüsselt mit dem server RSA-Schlüssel. Nun, ich würde gerne extra paranoid, und verschlüsseln Sie, dass bereits verschlüsselte Passwort mit dem öffentlichen Schlüssel des Kunden, so dass die "encrypt" - Methode wäre so etwas wie:

def encrypt(string):
    #Begin RSA Part to get a cypher that uses the server's public key
    externServerKeyFilename="/home/borrajax/rsaKeys/server-key.pub"
    externServerKeyFile = open(externServerKeyFilename, "r")
    rsaServerKey= RSA.importKey(externServerKeyFile, passphrase="F00bAr")
    pkcs1ServerEncryptor=PKCS1_OAEP.new(rsaServerKey)
    #End RSA Part

    #Begin RSA Part to get a cypher that uses the client's public key
    externClientKeyFilename="/home/borrajax/rsaKeys/client-key.pub"
    externClientKeyFile = open(externClientKeyFilename, "r")
    rsaClientKey= RSA.importKey(externClientKeyFile, passphrase="F00bAr")
    pkcs1ClientEncryptor=PKCS1_OAEP.new(rsaClientKey)
    #End RSA Part


    #Begin AES Part
    iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16))
    thisMessagePassword = os.urandom(16)
    aesEncryptor = AES.new(thisMessagePassword, AES.MODE_CBC, iv)
    chunksize=64*1024
    #End AES Part

    #Begin RSA Encription of the AES Key
    rsaEncryptedPasswordWithServer = pkcs1ServerEncryptor.encrypt(thisMessagePassword)
    rsaEncryptedPasswordWithServerAndClient = pkcs1ClientEncryptor.encrypt(rsaEncryptedPasswordWithServer) #Katacrasssshh here!! 

    retvalTmp = cStringIO.StringIO()
    retvalTmp.write(struct.pack('<Q', len(string)))
    retvalTmp.write(struct.pack('<Q', len(rsaEncryptedPasswordWithServerAndClient)))
    #...Probably some yadda yadda here with key lengths and stuff so it would help re-build the keys in the server's side...
    retvalTmp.write(rsaEncryptedPasswordWithServerAndClient)
    retvalTmp.write(iv)
    while len(string) > 0:
        chunk = string[0:chunksize]
        string = string[chunksize:]
        if len(chunk) % 16 != 0:
            chunk += ' ' * (16 - len(chunk) % 16)
        retvalTmp.write(aesEncryptor.encrypt(chunk))
    return retvalTmp.getvalue()

Aber wenn ich versuche, erneut zu verschlüsseln, der Schlüssel, bekomme ich eine ValueError("Plaintext too large") Ausnahme. Was Sinn macht (zumindest macht Sinn, jemand, der kaum weiß etwas über Verschlüsselung), weil PKCS fügt eine Polsterung, so dass, wenn ich verschlüsseln "thisMessagePassword" mit dem öffentlichen Schlüssel des Servers, bekomme ich einen 256 Byte-Zeichenfolge, die zu lang für die zweite PKCS encryptor (ich mache ein paar "manuelle Prüfung" und die Grenze zu sein scheint, 214 bytes... ich meine... das ist der Letzte Wert, der nicht eine Ausnahme werfen).

Ich mir bewusst bin, dass ist wahrscheinlich eine seltsame Konstrukt und es würde wahrscheinlich mehr Sinn machen, verwenden Sie die server den öffentlichen Schlüssel für Verschlüsselung und Signierung mit dem client-key, aber ich versuche nur zu spielen ein bisschen mit Verschlüsselung die Dinge und versuchen zu verstehen, wie Sie funktionieren und warum. Das ist, warum jeder Hinweis wird dankbar sein.

Vielen Dank im Voraus!

InformationsquelleAutor BorrajaX | 2012-04-18
Schreibe einen Kommentar