From 0a914f5edc5a5981de82c3f63c7ae5061dc6b966 Mon Sep 17 00:00:00 2001 From: Stefan Suhren Date: Sat, 19 Sep 2015 00:41:04 +0200 Subject: Implementiere erste Version von RSA für PEM Keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crypt/hybridcrypt.cpp | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) (limited to 'crypt/hybridcrypt.cpp') diff --git a/crypt/hybridcrypt.cpp b/crypt/hybridcrypt.cpp index 0d56038..63e241e 100644 --- a/crypt/hybridcrypt.cpp +++ b/crypt/hybridcrypt.cpp @@ -42,6 +42,142 @@ HybridCrypt::~HybridCrypt() void HybridCrypt::encrypt(QString infileName, QString outfileName, QVector recipientKeyfileNames) { + if (recipientKeyfileNames.length() < 1) + { + throw CryptException("Keine Empfänger wurden angegeben.", + CryptException::NoRecipients); + } + + throwExceptionIfCsprngIsNotSeeded(); + + 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); + + QByteArray aesKey = getCsprngBytes(EVP_CIPHER_key_length(EVP_aes_256_cbc())); + QByteArray aesIv = getCsprngBytes(EVP_CIPHER_iv_length(EVP_aes_256_cbc())); + + int keyCount = recipientKeyfileNames.length(); + + // Nur wenn ein Nutzerschlüssel existiert wird er auch für die Verschlüsselung verwendet + if (userKeypair != NULL) + { + ++keyCount; + } + + // Schreibe die Anzahl der PublicKeys als erstes in die Datei + outfileStream << (qint64) keyCount; + + EVP_PKEY *tmpKey; + QByteArray tmpData; + FILE *tmpKeyfile; + + for (int i = 0; i < recipientKeyfileNames.length(); i++) + { + tmpKeyfile = fopen(recipientKeyfileNames[i].toStdString().c_str(), "r"); + + // Datei existiert nicht + if (tmpKeyfile == NULL) + { + throw CryptException("Datei nicht gefunden: " + + recipientKeyfileNames[i].toStdString(), CryptException::FileNotFound); + } + + // Ließ den aktuellen Empfängerschlüssel ein + tmpKey = PEM_read_PUBKEY(tmpKeyfile, NULL, NULL, NULL); + + // Räume die Ressourcen auf + fclose(tmpKeyfile); + + // Wirf Fehler, falls der Schlüssel nicht gelesen werden konnte + if (tmpKey == NULL) + { + throwOpenSslException(); + } + + // Schreibe den Header in die Datei + tmpData = encryptAesData(tmpKey, aesKey + aesIv); + outfileStream.writeRawData(tmpData.data(), tmpData.length()); + + // Räume Schlüssel auf + freeEvpKey(&tmpKey); + } + + // Damit der Nutzer selbst die Datei auch entschlüsseln kann, falls er einen Schlüssel hat + if (userKeypair != NULL) + { + tmpData = encryptAesData(userKeypair, aesKey + aesIv); + outfileStream.writeRawData(tmpData.data(), tmpData.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_EncryptInit_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()); + + // Verschlüssele den Block mit AES + if (1 != EVP_EncryptUpdate(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); + } + + // 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)) + { + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); + throwOpenSslException(); + } + + outfileStream.writeRawData(outBuf.data(), len); + + // Räume den symmetrischen Schlüsselkontext ab + freeCipherCtx(&ctx); } @@ -182,11 +318,83 @@ void HybridCrypt::exportPublicUserKey(QString keyfileName) * Private Funktionen */ +QByteArray HybridCrypt::encryptAesData(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_encrypt_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_encrypt(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); + + // Verschlüssele den AES Key und den IV + if (EVP_PKEY_encrypt(ctx, (unsigned char *) out.data(), &outlen, + (unsigned char *) data.data(), data.length()) <= 0) + { + // 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; } +QByteArray HybridCrypt::getCsprngBytes(int count) +{ + QByteArray out(count, 0); + + if (1 != RAND_bytes((unsigned char *) out.data(), count)) + { + throwOpenSslException(); + } + + return out; +} + bool HybridCrypt::isKeyRsa(EVP_PKEY *key) { return EVP_PKEY_type(key->type) == EVP_PKEY_RSA; -- cgit v1.2.3-70-g09d2