Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Code signing and verification with OpenSSL
#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;
}
}
@radj

This comment has been minimized.

Copy link

@radj radj commented Jan 24, 2017

Thank you so much for this sample code! Made my life easier. Had a hard time resolving private key sign and public key verify codes in other sources. And this just works.

@joysher

This comment has been minimized.

Copy link

@joysher joysher commented May 27, 2017

I am getting the below error while compiling:
In function ‘void Base64Decode(const char*, unsigned char**, size_t*)’:
testverify2.cpp:166:39: error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]
bio = BIO_new_mem_buf(b64message, -1);
^
In file included from /usr/include/openssl/evp.h:75:0,
from testverify2.cpp:3:
/usr/include/openssl/bio.h:668:6: error: initializing argument 1 of ‘BIO* BIO_new_mem_buf(void*, int)’ [-fpermissive]
BIO *BIO_new_mem_buf(void *buf, int len);
Please help me to resolve.

@mgibson91

This comment has been minimized.

Copy link

@mgibson91 mgibson91 commented Jul 4, 2017

This is great! Thanks for taking the time to put this together

@Mathadon

This comment has been minimized.

Copy link

@Mathadon Mathadon commented Jan 18, 2018

I am getting the same error as @joysher . I fixed it by changing

void Base64Decode(const char* b64message, unsigned char** buffer, size_t* length) {

to

void Base64Decode(char* b64message, unsigned char** buffer, size_t* length) {
@Mathadon

This comment has been minimized.

Copy link

@Mathadon Mathadon commented Jan 19, 2018

@irbull Thank you for sharing this example. After two days of trying to get other code to work, this was up and running in half an hour.. What is the license for using this code please?

@pbraga

This comment has been minimized.

Copy link

@pbraga pbraga commented Jul 11, 2018

@irbull +1, thanks for this very useful code, would like to know how you license this code.

@chiffacff

This comment has been minimized.

Copy link

@chiffacff chiffacff commented Oct 29, 2018

hello. if i sign text line in php and then verify it if c++ (using this example) I get Not Authentic. Can any one help, what is problem?

@LeMoussel

This comment has been minimized.

Copy link

@LeMoussel LeMoussel commented Dec 27, 2018

EVP_MD_CTX_cleanup() has removed. I replaced it with EVP_MD_CTX_free()
Ref : https://www.openssl.org/news/cl110.txt

@tawmoto

This comment has been minimized.

Copy link

@tawmoto tawmoto commented Aug 29, 2019

Great thanks for the example, probably the best example on the internet.

@nicraMarcin

This comment has been minimized.

Copy link

@nicraMarcin nicraMarcin commented Sep 16, 2019

I've problem with compile. Debian 9, gcc version 8.3.0, libssl-dev installed

$ g++ -lssl -lcrypto  -std=c++11  verifyrsa.cpp 
verifyrsa.cpp: In function ‘bool RSASign(RSA*, const unsigned char*, size_t, unsigned char**, size_t*)’:
verifyrsa.cpp:94:3: error: ‘EVP_MD_CTX_cleanup’ was not declared in this scope
   EVP_MD_CTX_cleanup(m_RSASignCtx);
   ^~~~~~~~~~~~~~~~~~
verifyrsa.cpp:94:3: note: suggested alternative: ‘EVP_MD_CTX_create’
   EVP_MD_CTX_cleanup(m_RSASignCtx);
   ^~~~~~~~~~~~~~~~~~
   EVP_MD_CTX_create
verifyrsa.cpp: In function ‘bool RSAVerifySignature(RSA*, unsigned char*, size_t, const char*, size_t, bool*)’:
verifyrsa.cpp:118:5: error: ‘EVP_MD_CTX_cleanup’ was not declared in this scope
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
verifyrsa.cpp:118:5: note: suggested alternative: ‘EVP_MD_CTX_create’
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
     EVP_MD_CTX_create
verifyrsa.cpp:122:5: error: ‘EVP_MD_CTX_cleanup’ was not declared in this scope
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
verifyrsa.cpp:122:5: note: suggested alternative: ‘EVP_MD_CTX_create’
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
     EVP_MD_CTX_create
verifyrsa.cpp:126:5: error: ‘EVP_MD_CTX_cleanup’ was not declared in this scope
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
verifyrsa.cpp:126:5: note: suggested alternative: ‘EVP_MD_CTX_create’
     EVP_MD_CTX_cleanup(m_RSAVerifyCtx);
     ^~~~~~~~~~~~~~~~~~
     EVP_MD_CTX_create

This is beacause of changes in openSSL v1.1
https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes

@abcdef123ghi

This comment has been minimized.

Copy link

@abcdef123ghi abcdef123ghi commented Nov 22, 2019

I tried this code within VS 2019 on Windows,there are some issues:
#1 the funtionalities which are Base64Encode , Base64Decode doesn't work ,you have to replace them with something else
#2 you have to replace all the EVP_MD_CTX_cleanup with EVP_MD_CTX_free as well
beside the issue above anything else works fine so far

@programonauta

This comment has been minimized.

Copy link

@programonauta programonauta commented Jan 20, 2020

Hi,

Your code is exactly what I as looking for. Thanks for that.

But I'm facing some problems to find some symbols.

I'm using Ubuntu subsytem on Windows 10. As it came with an old version of openssl I updated it:

wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar -zxf openssl-1.1.1a.tar.gz && cd openssl-1.1.1a
./config
make
make test # Verify possible erros
sudo mv /usr/bin/openssl ~/tmp # backup current version
sudo make install
sudo ln -s /usr/local/bin/openssl /usr/bin/openssl # create symbolic link
sudo ldconfig # update de symlinks and rebuild library caches

Follow @abcdef123ghi comment, I replaced all EVP_MD_CTX_cleanup with EVP_MD_CTX_free.

I noticed that strlen and padding functions produced errors as well, that I solved including the #include <string.h>

But, there was another error, it's not possible find EVP_MD_CTX_new and EVP_MD_CTX_free:

$ g++ signVerify.cpp -o signVerify -I/usr/include/openssl/ -L/usr/bin/openssl -lssl -lcry
pto
/tmp/ccqw7GSo.o: In function `RSASign(rsa_st*, unsigned char const*, unsigned long, unsigned char**, unsigned long*)':
signVerify.cpp:(.text+0x139): undefined reference to `EVP_MD_CTX_new'
signVerify.cpp:(.text+0x231): undefined reference to `EVP_MD_CTX_free'
/tmp/ccqw7GSo.o: In function `RSAVerifySignature(rsa_st*, unsigned char*, unsigned long, char const*, unsigned long, bool*)':
signVerify.cpp:(.text+0x282): undefined reference to `EVP_MD_CTX_new'
signVerify.cpp:(.text+0x31b): undefined reference to `EVP_MD_CTX_free'
signVerify.cpp:(.text+0x33b): undefined reference to `EVP_MD_CTX_free'
signVerify.cpp:(.text+0x355): undefined reference to `EVP_MD_CTX_free'
collect2: error: ld returned 1 exit status

Any suggestion? How can I find the exactly library where this functions must be?

Thanks

@programonauta

This comment has been minimized.

Copy link

@programonauta programonauta commented Jan 20, 2020

Hey guys,

I'v just found the error, and just to register here:

It was necessary remove libssl-dev

sudo apt-get remove libssl-dev
@gauravrathi85

This comment has been minimized.

Copy link

@gauravrathi85 gauravrathi85 commented Feb 12, 2020

Maybe a dumb question , but I do not see a free after malloc. Did I miss something?

@gauravrathi85

This comment has been minimized.

Copy link

@gauravrathi85 gauravrathi85 commented Feb 21, 2020

I want to say that this code is helpful and does work. But be careful as there are memory leaks here (I had to check all openssl functions used here and find the function used to free the allocated memory and then verify that there were no memory leaks). Apart from openssl functions the malloc is never freed, so keep that in mind

@supriya1658

This comment has been minimized.

Copy link

@supriya1658 supriya1658 commented Mar 30, 2020

I am getting access violation exception at EVP_DigestVerifyFinal api. Not able to understand why as pointer its data and memory pointing is correct

@supriya1658

This comment has been minimized.

Copy link

@supriya1658 supriya1658 commented Mar 31, 2020

can please anybody suggest anything

@Tarasus

This comment has been minimized.

Copy link

@Tarasus Tarasus commented Apr 2, 2020

I don't know what am I doing wrong, but
bool authentic = verifySignature(publicKey, "My secret message.\n", signature);
always returns false
I have replaced all EVP_MD_CTX_cleanup() with EVP_MD_CTX_free() but this might not be the case.
my EVP_DigestVerifyFinal() returns 0
ERR_get_error() and ERR_error_string() called after it returns "err 67108983 = error:04000077:rsa routines::wrong signature length"

Update: I got rid of all base64 encoding-decoding in my code, and signature-text verification worked like a charm!
BIO_read(bio, *buffer, strlen(b64message)); was returning 0, so EVP_DigestVerifyFinal() returned errors.

@0xGhost

This comment has been minimized.

Copy link

@0xGhost 0xGhost commented May 13, 2020

add
(*base64Text)[(*bufferPtr).length] = '\0';
after line 146
will fix bugs about base64 encoding

@0xGhost

This comment has been minimized.

Copy link

@0xGhost 0xGhost commented May 13, 2020

I don't know what am I doing wrong, but
bool authentic = verifySignature(publicKey, "My secret message.\n", signature);
always returns false
I have replaced all EVP_MD_CTX_cleanup() with EVP_MD_CTX_free() but this might not be the case.
my EVP_DigestVerifyFinal() returns 0
ERR_get_error() and ERR_error_string() called after it returns "err 67108983 = error:04000077:rsa routines::wrong signature length"

Update: I got rid of all base64 encoding-decoding in my code, and signature-text verification worked like a charm!
BIO_read(bio, *buffer, strlen(b64message)); was returning 0, so EVP_DigestVerifyFinal() returned errors.

this encoder forget to add '\0' at the end of the char* string
see my comment for fixing

@SFTCP1

This comment has been minimized.

Copy link

@SFTCP1 SFTCP1 commented Aug 4, 2020

If you want to skip conversion errors just use the "-fpermissive" flag

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment