diff --git a/QtOpensslEncryption.pri b/QtOpensslEncryption.pri new file mode 100644 index 0000000..be0f1c7 --- /dev/null +++ b/QtOpensslEncryption.pri @@ -0,0 +1,15 @@ +QT += core +QT -= GUI + +CONFIG += c++11 + +LIBS += -lssl -lcrypto + +HEADERS += \ + $$PWD/qtoe.h + +SOURCES += \ + $$PWD/qtoe.cpp + +INCLUDEPATH += $$PWD + diff --git a/qtoe.cpp b/qtoe.cpp new file mode 100644 index 0000000..9c0301a --- /dev/null +++ b/qtoe.cpp @@ -0,0 +1,216 @@ +#include "qtoe.h" + +using namespace std; + +QtOE::QtOE(QObject *parent) : QObject(parent) +{ +} + +RSA* QtOE::createPrivateRSA(QString key, QString passphrase) { + RSA *rsa = NULL; + BIO *keybio; + keybio = BIO_new(BIO_s_mem()); + BIO_puts(keybio, key.toStdString().c_str()); + + if(passphrase != "") + rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, 0, (void*)passphrase.toStdString().c_str()); + else + rsa = PEM_read_bio_RSAPrivateKey(keybio, NULL, &QtOE::pem_password_callback, NULL); + + if(rsa == NULL || rsa == 0) + qDebug() << "[ERROR][QtOE] There was a problem rading the private key!"; + + return rsa; +} + +RSA* QtOE::createPublicRSA(QString key) { + RSA *rsa = NULL; + BIO *keybio; + keybio = BIO_new(BIO_s_mem()); + BIO_puts(keybio, key.toStdString().c_str()); + + rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); + return rsa; +} + +RSA* QtOE::createPublicRSA(X509* cert) { + if(cert == NULL) + return 0; + + EVP_PKEY * pubkey; + pubkey = X509_get_pubkey(cert); + + RSA * rsa; + rsa = EVP_PKEY_get1_RSA(pubkey); + return rsa; +} + +X509* QtOE::createX509(QString cert) { + X509 *x509 = NULL; + BIO *certbio; + certbio = BIO_new(BIO_s_mem()); + BIO_puts(certbio, cert.toStdString().c_str()); + x509 = PEM_read_bio_X509(certbio, &x509, NULL, NULL); + return x509; +} + +bool QtOE::RSASign( RSA* rsa, + const unsigned char* Msg, + size_t MsgLen, + unsigned char** EncMsg, + size_t* MsgLenEnc) { + EVP_MD_CTX* m_RSASignCtx = EVP_MD_CTX_create(); + EVP_PKEY* priKey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(priKey, rsa); + if (EVP_DigestSignInit(m_RSASignCtx,NULL, EVP_sha256(), NULL,priKey)<=0) { + return false; + } + if (EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0) { + return false; + } + if (EVP_DigestSignFinal(m_RSASignCtx, NULL, MsgLenEnc) <=0) { + return false; + } + *EncMsg = (unsigned char*)malloc(*MsgLenEnc); + if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0) { + return false; + } + //EVP_MD_CTX_cleanup(m_RSASignCtx); + return true; +} + +bool QtOE::RSAVerifySignature( RSA* rsa, + unsigned char* MsgHash, + size_t MsgHashLen, + const char* Msg, + size_t MsgLen, + bool* Authentic) { + *Authentic = false; + EVP_PKEY* pubKey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pubKey, rsa); + EVP_MD_CTX* m_RSAVerifyCtx = EVP_MD_CTX_create(); + + if (EVP_DigestVerifyInit(m_RSAVerifyCtx,NULL, EVP_sha256(),NULL,pubKey)<=0) { + return false; + } + if (EVP_DigestVerifyUpdate(m_RSAVerifyCtx, Msg, MsgLen) <= 0) { + return false; + } + int AuthStatus = EVP_DigestVerifyFinal(m_RSAVerifyCtx, MsgHash, MsgHashLen); + if (AuthStatus==1) { + *Authentic = true; + //EVP_MD_CTX_cleanup(m_RSAVerifyCtx); + return true; + } else if(AuthStatus==0){ + *Authentic = false; + //EVP_MD_CTX_cleanup(m_RSAVerifyCtx); + return true; + } else{ + *Authentic = false; + //EVP_MD_CTX_cleanup(m_RSAVerifyCtx); + return false; + } +} + +void QtOE::Base64Encode( const unsigned char* buffer, + size_t length, + char** base64Text) { + BIO *bio, *b64; + BUF_MEM *bufferPtr; + + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new(BIO_s_mem()); + bio = BIO_push(b64, bio); + + BIO_write(bio, buffer, length); + BIO_flush(bio); + BIO_get_mem_ptr(bio, &bufferPtr); + BIO_set_close(bio, BIO_NOCLOSE); + BIO_free_all(bio); + + *base64Text=(*bufferPtr).data; +} + +size_t QtOE::calcDecodeLength(const char* b64input) { + size_t len = strlen(b64input), padding = 0; + + if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are = + padding = 2; + else if (b64input[len-1] == '=') //last char is = + padding = 1; + return (len*3)/4 - padding; +} + +void QtOE::Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) { + BIO *bio, *b64; + + int decodeLen = calcDecodeLength(b64message); + *buffer = (unsigned char*)malloc(decodeLen + 1); + (*buffer)[decodeLen] = '\0'; + + bio = BIO_new_mem_buf(b64message, -1); + b64 = BIO_new(BIO_f_base64()); + bio = BIO_push(b64, bio); + + *length = BIO_read(bio, *buffer, strlen(b64message)); + BIO_free_all(bio); +} + +QString QtOE::signMessage(RSA* privateKey, QString plainText) { + if(privateKey == 0 || privateKey == NULL || privateKey == nullptr) { + qDebug() << "[ERROR][QtOE] private key must not be NULL!"; + return ""; + } + + unsigned char* encMessage; + char* base64Text; + size_t encMessageLength; + RSASign(privateKey, (unsigned char*) plainText.toStdString().c_str(), plainText.length(), &encMessage, &encMessageLength); + Base64Encode(encMessage, encMessageLength, &base64Text); + free(encMessage); + return base64Text; +} + +bool QtOE::verifySignature(RSA* publicKey, QString plainText, QString signatureBase64) { + if(publicKey == 0 || publicKey == NULL || publicKey == nullptr) { + qDebug() << "[ERROR][QtOE] public key must not be NULL!"; + return false; + } + unsigned char* encMessage; + size_t encMessageLength; + bool authentic; + Base64Decode(signatureBase64.toStdString().c_str(), &encMessage, &encMessageLength); + bool result = RSAVerifySignature(publicKey, encMessage, encMessageLength, plainText.toStdString().c_str(), plainText.length(), &authentic); + return result & authentic; +} + +void QtOE::printCertBio(X509 *cert) { + X509_NAME *subject = X509_get_subject_name(cert); + + // Print the subject into a BIO and then get a string + BIO * bio = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(bio, subject, 0, 0); + + // Create a buffer and zero it out + const int& max_len = 4096; + char buffer[max_len]; + memset(buffer, 0, max_len); + // Read one smaller than the buffer to make sure we end up with a null + // terminator no matter what + BIO_read(bio, buffer, max_len - 1); + + std::string cert_subject = buffer; + + qDebug() << QString::fromStdString(cert_subject); +} + +int QtOE::pem_password_callback(char *buf, int max_len, int flag, void *ctx) +{ + Q_UNUSED(buf); + Q_UNUSED(max_len); + Q_UNUSED(flag); + Q_UNUSED(ctx); + + qDebug() << "[ERROR][QtOE] A passphrase was required for this key, but none was given!"; + return 0; +} diff --git a/qtoe.h b/qtoe.h new file mode 100644 index 0000000..3fa349b --- /dev/null +++ b/qtoe.h @@ -0,0 +1,59 @@ +#ifndef QTOE_H +#define QTOE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QtOE : public QObject +{ + Q_OBJECT +public: + explicit QtOE(QObject *parent = nullptr); + + RSA* createPrivateRSA(QString key, QString passphrase = ""); + RSA* createPublicRSA(QString key); + RSA* createPublicRSA(X509* cert); + X509* createX509(QString cert); + + QString signMessage(RSA* privateKey, QString plainText); + bool verifySignature(RSA* publicKey, QString plainText, QString signatureBase64); + + void printCertBio(X509* cert); +private: + bool RSASign( RSA* rsa, + const unsigned char* Msg, + size_t MsgLen, + unsigned char** EncMsg, + size_t* MsgLenEnc); + bool RSAVerifySignature( RSA* rsa, + unsigned char* MsgHash, + size_t MsgHashLen, + const char* Msg, + size_t MsgLen, + bool* Authentic); + void Base64Encode( const unsigned char* buffer, + size_t length, + char** base64Text); + size_t calcDecodeLength(const char* b64input); + void Base64Decode(const char* b64message, unsigned char** buffer, size_t* length); + static int pem_password_callback(char *buf, int max_len, int flag, void *ctx); + +signals: + +}; + +#endif // QTOE_H