#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; }