#include "hybridcrypt.h" HybridCrypt::HybridCrypt() { // Initialisiere Nutzerschlüssel mit NULL userKeypair = NULL; // Lade die menschenlesbaren Fehlerstrings für LibCrypto ERR_load_crypto_strings(); // Lade alle Hash- und Verschlüsselungsalgorithmen OpenSSL_add_all_algorithms(); // Lade Konfigurationsdatei und andere wichtige Initialisierungen OPENSSL_config(NULL); // Zeige ob der Zufallszahlengenerator initialisiert wurde qDebug() << "Zufallszahlengenerator erfolgreich initialisiert: " << isCsprngSeeded(); } HybridCrypt::~HybridCrypt() { // Räume Nutzerschlüssel auf freeEvpKey(&userKeypair); // Räume OpenSSL auf // Entferne alle Hash- und Verschlüsselungsalgorithmen EVP_cleanup(); // Falls das nächste Ausgelassen wird, könnte ein Speicherleck auftreten, // wenn die BIO Api verwendet wurde (Base64 transformationen) CRYPTO_cleanup_all_ex_data(); // Lösche den CSPRNG sicher RAND_cleanup(); // Entferne Fehlerstrings ERR_free_strings(); } void HybridCrypt::encrypt(QString infileName, QString outfileName, QVector recipientKeyfileNames) { } void HybridCrypt::decrypt(QString infileName, QString outfileName) { } void HybridCrypt::createKeypair() { throwExceptionIfCsprngIsNotSeeded(); // Räume den alten Schlüssel vorher ab freeEvpKey(&userKeypair); // Lege Schlüsselkontextvariable an EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); // Erzeuge den Schlüsselkontext if (!ctx) { throwOpenSslException(); } // Initialisiere den Schlüsselgenerator if (EVP_PKEY_keygen_init(ctx) <= 0) { freePkeyCtx(&ctx); throwOpenSslException(); } // Lege den Schlüssel mit 2048 Bit an if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0) { freePkeyCtx(&ctx); throwOpenSslException(); } // Erzeuge den Schlüssel if (EVP_PKEY_keygen(ctx, &userKeypair) <= 0) { freePkeyCtx(&ctx); throwOpenSslException(); } // Räume den Schlüsselkontext ab freePkeyCtx(&ctx); } void HybridCrypt::importUserKeypair(QString keyfileName, QString password) { // Räume den alten Schlüssel vorher ab freeEvpKey(&userKeypair); FILE *keyfile = fopen(keyfileName.toStdString().c_str(), "r"); // Datei existiert nicht if (keyfile == NULL) { throw CryptException("Datei nicht gefunden: " + keyfileName.toStdString(), CryptException::FileNotFound); } // Ließ den Schlüssel des Nutzers ein userKeypair = PEM_read_PrivateKey(keyfile, NULL, NULL, (void *) password.toStdString().c_str()); // Räume die Ressourcen auf fclose(keyfile); // Wirf einen Fehler, falls OpenSSL ein Problem hatte if (userKeypair == NULL) { throwOpenSslException(); } // Wirf Exception, falls kein RSA Schlüssel importiert wurde throwExceptionIfEvpKeyIsNotRsa(&userKeypair); } void HybridCrypt::exportUserKeypair(QString keyfileName, QString password) { throwExceptionIfCsprngIsNotSeeded(); throwExceptionIfUserKeyIsNull(); FILE *keyfile = fopen(keyfileName.toStdString().c_str(), "w+"); // Teste, ob die Datei zum Schreiben geöffnet werden konnte if (keyfile == NULL) { throw CryptException("Konnte Datei nicht schreiben: " + keyfileName.toStdString(), CryptException::FileNotWritable); } // Wenn password ein Leerstring ist, verschlüssele den privaten Schlüssel nicht int opensslReturnError = PEM_write_PKCS8PrivateKey(keyfile, userKeypair, (password.isEmpty()) ? NULL : EVP_aes_256_cbc(), NULL, 0, NULL, (void *) password.toStdString().c_str()); // Räume die Ressourcen auf fclose(keyfile); // Wirf einen Fehler, falls OpenSSL ein Problem hatte if (!opensslReturnError) { throwOpenSslException(); } } void HybridCrypt::exportPublicUserKey(QString keyfileName) { throwExceptionIfUserKeyIsNull(); FILE *keyfile = fopen(keyfileName.toStdString().c_str(), "w+"); // Teste, ob die Datei zum Schreiben geöffnet werden konnte if (keyfile == NULL) { throw CryptException("Konnte Datei nicht schreiben: " + keyfileName.toStdString(), CryptException::FileNotWritable); } int opensslReturnError = PEM_write_PUBKEY(keyfile, userKeypair); // Räume die Ressourcen auf fclose(keyfile); // Wirft einen Fehler, falls OpenSSL ein Problem hatte if (!opensslReturnError) { throwOpenSslException(); } } /* * Private Funktionen */ bool HybridCrypt::isCsprngSeeded() { return RAND_status() == 1; } bool HybridCrypt::isKeyRsa(EVP_PKEY *key) { return EVP_PKEY_type(key->type) == EVP_PKEY_RSA; } void HybridCrypt::throwOpenSslException() { QString errorMsg("OpenSSL Fehler. Fehlermeldung: "); errorMsg.append(ERR_error_string(ERR_get_error(), NULL)); throw CryptException(errorMsg.toStdString(), CryptException::OpenSslError); } void HybridCrypt::throwExceptionIfEvpKeyIsNotRsa(EVP_PKEY **key) { if (!isKeyRsa(*key)) { freeEvpKey(key); throw CryptException("Nur RSA Schlüssel werden unterstüzt.", CryptException::KeyNotRsa); } } void HybridCrypt::throwExceptionIfCsprngIsNotSeeded() { if (!isCsprngSeeded()) { throw new CryptException("Zufallszahlengenerator ist nicht initialisiert", CryptException::CsprngNotSeeded); } } void HybridCrypt::throwExceptionIfUserKeyIsNull() { if (userKeypair == NULL) { throw CryptException("Kein Schlüssel wurde angelegt", CryptException::NoUserKeyCreated); } } void HybridCrypt::freeEvpKey(EVP_PKEY **key) { EVP_PKEY_free(*key); *key = NULL; } void HybridCrypt::freeCipherCtx(EVP_CIPHER_CTX **ctx) { EVP_CIPHER_CTX_free(*ctx); *ctx = NULL; } void HybridCrypt::freePkeyCtx(EVP_PKEY_CTX **ctx) { EVP_PKEY_CTX_free(*ctx); *ctx = NULL; }