From c69cbcc54549f1733eefd8c275d083c6fa44cc26 Mon Sep 17 00:00:00 2001 From: Stefan Suhren Date: Sat, 19 Sep 2015 14:46:39 +0200 Subject: Implementiere decrypt und passe keyCount Länge an MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crypt/hybridcrypt.cpp | 177 +++++++++++++++++++++++++++++++++++++++++++++++++- crypt/hybridcrypt.h | 9 +++ 2 files changed, 183 insertions(+), 3 deletions(-) (limited to 'crypt') diff --git a/crypt/hybridcrypt.cpp b/crypt/hybridcrypt.cpp index 63e241e..a9b410d 100644 --- a/crypt/hybridcrypt.cpp +++ b/crypt/hybridcrypt.cpp @@ -80,7 +80,7 @@ void HybridCrypt::encrypt(QString infileName, QString outfileName, } // Schreibe die Anzahl der PublicKeys als erstes in die Datei - outfileStream << (qint64) keyCount; + outfileStream << (qint32) keyCount; EVP_PKEY *tmpKey; QByteArray tmpData; @@ -166,8 +166,7 @@ void HybridCrypt::encrypt(QString infileName, QString outfileName, } // Nun bekommen wir den letzten Block, falls die Datei nicht ein Vielfaches der AES Blöckgröße war - if (1 != EVP_EncryptFinal_ex(ctx, (unsigned char *)outBuf.data(), - &len)) + if (1 != EVP_EncryptFinal_ex(ctx, (unsigned char *) outBuf.data(), &len)) { // Räume den symmetrischen Schlüsselkontext ab freeCipherCtx(&ctx); @@ -183,7 +182,107 @@ void HybridCrypt::encrypt(QString infileName, QString outfileName, void HybridCrypt::decrypt(QString infileName, QString outfileName) { + throwExceptionIfUserKeyIsNull(); + + QFile infile(infileName); + QFile outfile(outfileName); + + if (!infile.open(QFile::ReadOnly)) + { + throw CryptException("Datei nicht gefunden: " + infileName.toStdString(), + CryptException::FileNotFound); + } + + if (!outfile.open(QFile::ReadWrite | QFile::Truncate)) + { + throw CryptException("Konnte Datei nicht schreiben: " + + outfileName.toStdString(), CryptException::FileNotWritable); + } + + QDataStream infileStream(&infile); + QDataStream outfileStream(&outfile); + + qint32 keyCount = 0; + + // Lese die Anzahl der Schlüssel aus der Datei + infileStream >> keyCount; + + QByteArray tmpData; + QByteArray aesKey(EVP_CIPHER_key_length(EVP_aes_256_cbc()), 0); + QByteArray aesIv(EVP_CIPHER_iv_length(EVP_aes_256_cbc()), 0); + + // Versuche alle Header zu entschlüsseln + for (qint32 i = 0; i < keyCount && tmpData.length() == 0; i++) + { + tmpData.resize(256); + infileStream.readRawData(tmpData.data(), tmpData.length()); + tmpData = decryptAesData(userKeypair, tmpData); + } + + // Wenn kein Header entschlüsselt werden konnte, wirf eine Excption + if (tmpData.length() == 0) + { + throw CryptException("Fehler beim Entschlüsseln des RSA Blockes", + CryptException::DecryptionErrorRsa); + } + + // Ließ die Aes Daten aus + aesKey = tmpData.left(aesKey.length()); + aesIv = tmpData.mid(aesKey.length(), aesIv.length()); + + // Erzeuge den symmetrischen Kontext + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + + // Überprüfe den Schlüssel + if (!ctx) + { + throwOpenSslException(); + } + + // Setze den Verschlüsselungsalgorithmus, sowie den Schlüssel und den IV + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, + (unsigned char *) aesKey.data(), (unsigned char *) aesIv.data())) + { + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); + throwOpenSslException(); + } + + QByteArray inBuf(EVP_CIPHER_block_size(EVP_aes_256_cbc()), 0); + QByteArray outBuf(EVP_CIPHER_block_size(EVP_aes_256_cbc()), 0); + int bufRead; + int len; + + while (!infileStream.atEnd()) + { + // Hole jeweils einen Block an Daten aus der Datei + bufRead = infileStream.readRawData(inBuf.data(), inBuf.size()); + + // Entschlüssele den Block mit AES + if (1 != EVP_DecryptUpdate(ctx, (unsigned char *) outBuf.data(), &len, + (unsigned char *) inBuf.data(), bufRead)) + { + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); + throwOpenSslException(); + } + + // Schreibe den Block in die Ausgabedatei + outfileStream.writeRawData(outBuf.data(), len); + } + // Wirft Fehler, falls Padding falsch oder der letzte Block unvollständig war + if (1 != EVP_DecryptFinal_ex(ctx, (unsigned char *) outBuf.data(), &len)) + { + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); + throwOpenSslException(); + } + + outfileStream.writeRawData(outBuf.data(), len); + + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); } void HybridCrypt::createKeypair() @@ -378,6 +477,78 @@ QByteArray HybridCrypt::encryptAesData(EVP_PKEY *pkey, QByteArray data) return out; } +QByteArray HybridCrypt::decryptAesData(EVP_PKEY *pkey, QByteArray data) +{ + // Das QByteArray das zurück gegeben wird + QByteArray out; + + // Wird benutzt um die Länge von out zu bestimmen + size_t outlen; + + // Lege Schlüsselkontext an + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); + + // Überprüfe erflogreiche Schlüsselkontexterzeugung + if (!ctx) + { + throwOpenSslException(); + } + + // Initialisiere den Schlüsselkontext + if (EVP_PKEY_decrypt_init(ctx) <= 0) + { + // Räume den Schlüsselkontext ab + freePkeyCtx(&ctx); + throwOpenSslException(); + } + + // Setze für den Schlüsselkontext das RSA Padding + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) + { + // Räume den Schlüsselkontext ab + freePkeyCtx(&ctx); + throwOpenSslException(); + } + + // Finde die Blockgröße für RSA raus + if (EVP_PKEY_decrypt(ctx, NULL, &outlen, (unsigned char *) data.data(), + data.length()) <= 0) + { + // Räume den Schlüsselkontext ab + freePkeyCtx(&ctx); + throwOpenSslException(); + } + + // Setze out auf RSA Blockgröße + out.resize(outlen); + + // Entschlüssele den AES Key und den IV + if (EVP_PKEY_decrypt(ctx, (unsigned char *) out.data(), &outlen, + (unsigned char *) data.data(), data.length()) <= 0) + { + // Wenn der Fehler von OAEP kommt, ignoriere fürs erste + if (ERR_GET_LIB(ERR_peek_error()) == 4 && + ERR_GET_FUNC(ERR_peek_error()) == 161 && + ERR_GET_REASON(ERR_peek_error()) == 121) + { + // Lösche Error aus der Schlange + ERR_get_error(); + out.resize(0); + } + else + { + // Räume den Schlüsselkontext ab + freePkeyCtx(&ctx); + throwOpenSslException(); + } + } + + // Räume den Schlüsselkontext ab + freePkeyCtx(&ctx); + + return out; +} + bool HybridCrypt::isCsprngSeeded() { return RAND_status() == 1; diff --git a/crypt/hybridcrypt.h b/crypt/hybridcrypt.h index a9d9dc2..d0c7202 100644 --- a/crypt/hybridcrypt.h +++ b/crypt/hybridcrypt.h @@ -99,6 +99,15 @@ private: */ QByteArray encryptAesData(EVP_PKEY *pkey, QByteArray data); + /** + * @brief Verschlüsselt den IV und den Key vom AES mit RSA. + * Und nutzt als Padding RSA_OAEP_PADDING. + * @param pkey Der EVP_PKEY mit dem Verschlüsselt wurde. + * @param data Der RSA Verschlüsselte Block. + * @return Der Aes Key and IV. (Länge is null, falls OAEP Fehler auftrat. + */ + QByteArray decryptAesData(EVP_PKEY *pkey, QByteArray data); + /** * @brief Gibt an, ob der Zufallszahlengenerator von OpenSSL mit ausreichend Entropie initialisiert wurde. * @return Gibt wahr zurück wenn ausreichend intialisert wurde, ansonsten falsch. -- cgit v1.2.3-70-g09d2