-
-
Save irbull/08339ddcd5686f509e9826964b17bb59 to your computer and use it in GitHub Desktop.
#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; | |
} | |
} |
add
(*base64Text)[(*bufferPtr).length] = '\0';
after line 146
will fix bugs about base64 encoding
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 allEVP_MD_CTX_cleanup()
withEVP_MD_CTX_free()
but this might not be the case.
myEVP_DigestVerifyFinal()
returns 0
ERR_get_error()
andERR_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
Why don't you just use return value of function RSAVerifySignature(...) to indicate verification is successful or failure?
Hi, Thank you for sharing this, great work.
When I run Valgrind it is reporting some memory leaks. I think it comes from *b64 which is created in the heap but never freed. I don't think it is freed internally by libcrypto (on Linux).
I'll investigate more and let you know.
Hi, Thank you for sharing this, great work. When I run Valgrind it is reporting some memory leaks. I think it comes from *b64 which is created in the heap but never freed. I don't think it is freed internally by libcrypto (on Linux). I'll investigate more and let you know.
I fixed this memory leaks. This is my fixed codes.
`#include
#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>
#include <string.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);
BIO_free(keybio);
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);
BIO_free(keybio);
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) {
EVP_PKEY_free(priKey);
return false;
}
if (EVP_DigestSignUpdate(m_RSASignCtx, Msg, MsgLen) <= 0) {
EVP_PKEY_free(priKey);
return false;
}
if (EVP_DigestSignFinal(m_RSASignCtx, NULL, MsgLenEnc) <=0) {
EVP_PKEY_free(priKey);
return false;
}
EncMsg = (unsigned char)malloc(*MsgLenEnc);
if (EVP_DigestSignFinal(m_RSASignCtx, *EncMsg, MsgLenEnc) <= 0) {
EVP_PKEY_free(priKey);
return false;
}
EVP_PKEY_free(priKey);
EVP_MD_CTX_free(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) {
EVP_PKEY_free(pubKey);
return false;
}
if (EVP_DigestVerifyUpdate(m_RSAVerifyCtx, Msg, MsgLen) <= 0) {
EVP_PKEY_free(pubKey);
return false;
}
int AuthStatus = EVP_DigestVerifyFinal(m_RSAVerifyCtx, MsgHash, MsgHashLen);
if (AuthStatus==1) {
*Authentic = true;
EVP_PKEY_free(pubKey);
EVP_MD_CTX_free(m_RSAVerifyCtx);
return true;
} else if(AuthStatus==0){
*Authentic = false;
EVP_PKEY_free(pubKey);
EVP_MD_CTX_free(m_RSAVerifyCtx);
return true;
} else{
*Authentic = false;
EVP_PKEY_free(pubKey);
EVP_MD_CTX_free(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;
(*base64Text)[(*bufferPtr).length] = '\0';
}
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);
free(encMessage);
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;
}
}
`
there are still memory leaks. one of them can be solved by adding free(signature);
as a last line in the main()
and then there is 1 memory leak remaining which i haven't found yet:
==28980== HEAP SUMMARY:
==28980== in use at exit: 32 bytes in 1 blocks
==28980== total heap usage: 11,284 allocs, 11,283 frees, 1,362,954 bytes allocated
==28980==
==28980== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28980== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==28980== by 0x4A2B41D: CRYPTO_zalloc (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==28980== by 0x496AD13: BUF_MEM_new (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==28980== by 0x496AD6C: BUF_MEM_new_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==28980== by 0x4958E99: ??? (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==28980== by 0x494FA13: BIO_new_ex (in /usr/lib/x86_64-linux-gnu/libcrypto.so.3)
==28980== by 0x10AC23: Base64Encode(unsigned char const*, unsigned long, char**) (openssl_example_new.cc:165)
==28980== by 0x10AEF5: signMessage(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (openssl_example_new.cc:211)
==28980== by 0x10B0DA: main (openssl_example_new.cc:232)
==28980==
==28980== LEAK SUMMARY:
==28980== definitely lost: 32 bytes in 1 blocks
==28980== indirectly lost: 0 bytes in 0 blocks
==28980== possibly lost: 0 bytes in 0 blocks
==28980== still reachable: 0 bytes in 0 blocks
==28980== suppressed: 0 bytes in 0 blocks
==28980==
==28980== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
btw. how could we replace 3 deprecated functions?
/home/xyz/abc/cc/openssl/openssl_example_new.cc:59:37: warning: ‘RSA* PEM_read_bio_RSAPrivateKey(BIO*, RSA**, int (*)(char*, int, int, void*), void*)’ is deprecated: Since OpenSSL 3.0 [-Wdeprecated-declarations]
59 | rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, nullptr, nullptr);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/xyz/abc/cc/openssl/openssl_example_new.cc:7:
/usr/include/openssl/pem.h:447:1: note: declared here
447 | DECLARE_PEM_rw_cb_attr(OSSL_DEPRECATEDIN_3_0, RSAPrivateKey, RSA)
| ^~~~~~~~~~~~~~~~~~~~~~
/home/xyz/abc/cc/openssl/openssl_example_new.cc: In function ‘RSA* createPublicRSA(std::string)’:
/home/xzy/abc/cc/openssl/openssl_example_new.cc:87:34: warning: ‘RSA* PEM_read_bio_RSA_PUBKEY(BIO*, RSA**, int (*)(char*, int, int, void*), void*)’ is deprecated: Since OpenSSL 3.0 [-Wdeprecated-declarations]
87 | rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa,nullptr, nullptr);
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/openssl/pem.h:449:1: note: declared here
449 | DECLARE_PEM_rw_attr(OSSL_DEPRECATEDIN_3_0, RSA_PUBKEY, RSA)
| ^~~~~~~~~~~~~~~~~~~
[100%] Linking CXX executable openssl_example_new
[100%] Built target openssl_example_new
Authentic
i've just found last memory leaks. you can fix it by adding free(bufferPtr);
as a last line in the Base64Encode()
but that's not much nice code at all...
It really helped me. i think the part of base64 code can`t peer to current standard. use some other popular base64 open source library can make it more compatible.
It really helped me, i'm using Objective-C
for openssl>=1.1.0 use EVP_MD_CTX_free
instead of EVP_MD_CTX_cleanup
. It works for me on my linux.
#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>
#include <cstring>
/**
g++ b.cpp -o main -lcryptopp -lssl -lcrypto 2>&1 && ./main
*/
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_free(m_RSASignCtx);
EVP_MD_CTX_free(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_free(m_RSAVerifyCtx);
return true;
} else if(AuthStatus==0){
*Authentic = false;
EVP_MD_CTX_free(m_RSAVerifyCtx);
return true;
} else{
*Authentic = false;
EVP_MD_CTX_free(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;
}
}
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()
withEVP_MD_CTX_free()
but this might not be the case.my
EVP_DigestVerifyFinal()
returns 0ERR_get_error()
andERR_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.