added signing and verifying capabilities for keys and certificates

This commit is contained in:
Dorian Zedler 2020-07-18 18:46:06 +02:00
parent 68825c598c
commit 05fbf562c3
Signed by: dorian
GPG Key ID: D3B255CB8BC7CD37
3 changed files with 290 additions and 0 deletions

15
QtOpensslEncryption.pri Normal file
View File

@ -0,0 +1,15 @@
QT += core
QT -= GUI
CONFIG += c++11
LIBS += -lssl -lcrypto
HEADERS += \
$$PWD/qtoe.h
SOURCES += \
$$PWD/qtoe.cpp
INCLUDEPATH += $$PWD

216
qtoe.cpp Normal file
View File

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

59
qtoe.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef QTOE_H
#define QTOE_H
#include <QObject>
#include <QtDebug>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <assert.h>
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