added signing and verifying capabilities for keys and certificates
This commit is contained in:
parent
68825c598c
commit
05fbf562c3
3 changed files with 290 additions and 0 deletions
15
QtOpensslEncryption.pri
Normal file
15
QtOpensslEncryption.pri
Normal 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
216
qtoe.cpp
Normal 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
59
qtoe.h
Normal 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
|
Loading…
Reference in a new issue