Created
August 11, 2016 18:32
-
-
Save irbull/08339ddcd5686f509e9826964b17bb59 to your computer and use it in GitHub Desktop.
Code signing and verification with OpenSSL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#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 <assert.h> | |
std::string privateKey ="-----BEGIN RSA PRIVATE KEY-----\n"\ | |
"MIIEowIBAAKCAQEAy8Dbv8prpJ/0kKhlGeJYozo2t60EG8L0561g13R29LvMR5hy\n"\ | |
"vGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+vw1HocOAZtWK0z3r26uA8kQYOKX9\n"\ | |
"Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQApfc9jB9nTzphOgM4JiEYvlV8FLhg9\n"\ | |
"yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68i6T4nNq7NWC+UNVjQHxNQMQMzU6l\n"\ | |
"WCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoVPpY72+eVthKzpMeyHkBn7ciumk5q\n"\ | |
"gLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUywQIDAQABAoIBADhg1u1Mv1hAAlX8\n"\ | |
"omz1Gn2f4AAW2aos2cM5UDCNw1SYmj+9SRIkaxjRsE/C4o9sw1oxrg1/z6kajV0e\n"\ | |
"N/t008FdlVKHXAIYWF93JMoVvIpMmT8jft6AN/y3NMpivgt2inmmEJZYNioFJKZG\n"\ | |
"X+/vKYvsVISZm2fw8NfnKvAQK55yu+GRWBZGOeS9K+LbYvOwcrjKhHz66m4bedKd\n"\ | |
"gVAix6NE5iwmjNXktSQlJMCjbtdNXg/xo1/G4kG2p/MO1HLcKfe1N5FgBiXj3Qjl\n"\ | |
"vgvjJZkh1as2KTgaPOBqZaP03738VnYg23ISyvfT/teArVGtxrmFP7939EvJFKpF\n"\ | |
"1wTxuDkCgYEA7t0DR37zt+dEJy+5vm7zSmN97VenwQJFWMiulkHGa0yU3lLasxxu\n"\ | |
"m0oUtndIjenIvSx6t3Y+agK2F3EPbb0AZ5wZ1p1IXs4vktgeQwSSBdqcM8LZFDvZ\n"\ | |
"uPboQnJoRdIkd62XnP5ekIEIBAfOp8v2wFpSfE7nNH2u4CpAXNSF9HsCgYEA2l8D\n"\ | |
"JrDE5m9Kkn+J4l+AdGfeBL1igPF3DnuPoV67BpgiaAgI4h25UJzXiDKKoa706S0D\n"\ | |
"4XB74zOLX11MaGPMIdhlG+SgeQfNoC5lE4ZWXNyESJH1SVgRGT9nBC2vtL6bxCVV\n"\ | |
"WBkTeC5D6c/QXcai6yw6OYyNNdp0uznKURe1xvMCgYBVYYcEjWqMuAvyferFGV+5\n"\ | |
"nWqr5gM+yJMFM2bEqupD/HHSLoeiMm2O8KIKvwSeRYzNohKTdZ7FwgZYxr8fGMoG\n"\ | |
"PxQ1VK9DxCvZL4tRpVaU5Rmknud9hg9DQG6xIbgIDR+f79sb8QjYWmcFGc1SyWOA\n"\ | |
"SkjlykZ2yt4xnqi3BfiD9QKBgGqLgRYXmXp1QoVIBRaWUi55nzHg1XbkWZqPXvz1\n"\ | |
"I3uMLv1jLjJlHk3euKqTPmC05HoApKwSHeA0/gOBmg404xyAYJTDcCidTg6hlF96\n"\ | |
"ZBja3xApZuxqM62F6dV4FQqzFX0WWhWp5n301N33r0qR6FumMKJzmVJ1TA8tmzEF\n"\ | |
"yINRAoGBAJqioYs8rK6eXzA8ywYLjqTLu/yQSLBn/4ta36K8DyCoLNlNxSuox+A5\n"\ | |
"w6z2vEfRVQDq4Hm4vBzjdi3QfYLNkTiTqLcvgWZ+eX44ogXtdTDO7c+GeMKWz4XX\n"\ | |
"uJSUVL5+CVjKLjZEJ6Qc2WZLl94xSwL71E41H4YciVnSCQxVc4Jw\n"\ | |
"-----END RSA PRIVATE KEY-----\n\0"; | |
std::string publicKey ="-----BEGIN PUBLIC KEY-----\n"\ | |
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8Dbv8prpJ/0kKhlGeJY\n"\ | |
"ozo2t60EG8L0561g13R29LvMR5hyvGZlGJpmn65+A4xHXInJYiPuKzrKUnApeLZ+\n"\ | |
"vw1HocOAZtWK0z3r26uA8kQYOKX9Qt/DbCdvsF9wF8gRK0ptx9M6R13NvBxvVQAp\n"\ | |
"fc9jB9nTzphOgM4JiEYvlV8FLhg9yZovMYd6Wwf3aoXK891VQxTr/kQYoq1Yp+68\n"\ | |
"i6T4nNq7NWC+UNVjQHxNQMQMzU6lWCX8zyg3yH88OAQkUXIXKfQ+NkvYQ1cxaMoV\n"\ | |
"PpY72+eVthKzpMeyHkBn7ciumk5qgLTEJAfWZpe4f4eFZj/Rc8Y8Jj2IS5kVPjUy\n"\ | |
"wQIDAQAB\n"\ | |
"-----END PUBLIC KEY-----\n"; | |
RSA* createPrivateRSA(std::string key) { | |
RSA *rsa = NULL; | |
const char* c_string = key.c_str(); | |
BIO * keybio = BIO_new_mem_buf((void*)c_string, -1); | |
if (keybio==NULL) { | |
return 0; | |
} | |
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL); | |
return rsa; | |
} | |
RSA* createPublicRSA(std::string key) { | |
RSA *rsa = NULL; | |
BIO *keybio; | |
const char* c_string = key.c_str(); | |
keybio = BIO_new_mem_buf((void*)c_string, -1); | |
if (keybio==NULL) { | |
return 0; | |
} | |
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,NULL, NULL); | |
return rsa; | |
} | |
bool 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 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 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 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 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); | |
} | |
char* signMessage(std::string privateKey, std::string plainText) { | |
RSA* privateRSA = createPrivateRSA(privateKey); | |
unsigned char* encMessage; | |
char* base64Text; | |
size_t encMessageLength; | |
RSASign(privateRSA, (unsigned char*) plainText.c_str(), plainText.length(), &encMessage, &encMessageLength); | |
Base64Encode(encMessage, encMessageLength, &base64Text); | |
free(encMessage); | |
return base64Text; | |
} | |
bool verifySignature(std::string publicKey, std::string plainText, char* signatureBase64) { | |
RSA* publicRSA = createPublicRSA(publicKey); | |
unsigned char* encMessage; | |
size_t encMessageLength; | |
bool authentic; | |
Base64Decode(signatureBase64, &encMessage, &encMessageLength); | |
bool result = RSAVerifySignature(publicRSA, encMessage, encMessageLength, plainText.c_str(), plainText.length(), &authentic); | |
return result & authentic; | |
} | |
int main() { | |
std::string plainText = "My secret message.\n"; | |
char* signature = signMessage(privateKey, plainText); | |
bool authentic = verifySignature(publicKey, "My secret message.\n", signature); | |
if ( authentic ) { | |
std::cout << "Authentic" << std::endl; | |
} else { | |
std::cout << "Not Authentic" << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
for openssl>=1.1.0 use
EVP_MD_CTX_free
instead ofEVP_MD_CTX_cleanup
. It works for me on my linux.