diff options
| author | Stefan Suhren <suhren.stefan@fh-swf.de> | 2015-09-19 00:41:04 +0200 |
|---|---|---|
| committer | Stefan Suhren <suhren.stefan@fh-swf.de> | 2015-09-19 01:46:23 +0200 |
| commit | 0a914f5edc5a5981de82c3f63c7ae5061dc6b966 (patch) | |
| tree | 10aafe542b06d6236558ce6b8c44548418e11abc /crypt | |
| parent | aac2957ab6f98d087f8fb9ff68da39fe68c40e3d (diff) | |
| download | src-0a914f5edc5a5981de82c3f63c7ae5061dc6b966.tar.gz src-0a914f5edc5a5981de82c3f63c7ae5061dc6b966.zip | |
Implementiere erste Version von RSA für PEM Keys
Diffstat (limited to 'crypt')
| -rw-r--r-- | crypt/cryptexception.h | 3 | ||||
| -rw-r--r-- | crypt/hybridcrypt.cpp | 208 | ||||
| -rw-r--r-- | crypt/hybridcrypt.h | 18 |
3 files changed, 228 insertions, 1 deletions
diff --git a/crypt/cryptexception.h b/crypt/cryptexception.h index 768e144..513fb8d 100644 --- a/crypt/cryptexception.h +++ b/crypt/cryptexception.h @@ -20,7 +20,8 @@ public: OpenSslError, KeyNotRsa, CsprngNotSeeded, - NoUserKeyCreated + NoUserKeyCreated, + NoRecipients }; /** 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<QString> 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; diff --git a/crypt/hybridcrypt.h b/crypt/hybridcrypt.h index ce8a553..6cf92df 100644 --- a/crypt/hybridcrypt.h +++ b/crypt/hybridcrypt.h @@ -90,6 +90,16 @@ private: EVP_PKEY *userKeypair; // Enthält nur den privaten Schlüssel, da OpenSSL nicht mehr braucht. /** + * @brief encryptAesData + * 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 wird. + * @param data Der AES Key und IV. + * @return Den RSA Verschlüsselten Block. + */ + QByteArray encryptAesData(EVP_PKEY *pkey, QByteArray data); + + /** * @brief isCsprngSeeded * Gibt an, ob der Zufallszahlengenerator von OpenSSL mit ausreichend Entropie initialisiert wurde. * @return Gibt wahr zurück wenn ausreichend intialisert wurde, ansonsten falsch. @@ -97,6 +107,14 @@ private: bool isCsprngSeeded(); /** + * @brief getCsprngData + * Holt Zufallsblöcke aus dem Csprng. + * @param count Die Anzahl der Zufallsbytes die geholt werden sollen. + * @return Ein QByteArray mit den Zufallsblöcken. + */ + QByteArray getCsprngBytes(int count); + + /** * @brief isKeyRsa * Überprüft, ob der Schlüssel vom Typ RSA ist. * @param key Der Schlüssel, der überprüft wird. |
