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