OpenSSL RSA Encryption/Decryption with EVP Methods - c++

I´ve created a rsa class with Openssl EVP (OpenSSL Ref) Methods.
rsa.h
#ifndef RSA_RSA_H
#define RSA_RSA_H
#include <string>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "utils.h"
#define PADDING RSA_PKCS1_OAEP_PADDING
#define LOGGING
namespace tools
{
class CryptoRSA
{
private:
int _keysize;
char *_rsaPrivateKeyStr, *_privateKeyStr, *_publicKeyStr;
unsigned char* _encryptedKey, *_iv;
EVP_PKEY *_pkey;
EVP_CIPHER_CTX *rsaEncryptContext, *rsaDecryptContext;
static std::string getOpenSSLError();
bool generateRSAKey();
bool loadKeyFromFile(const std::string &filepath);
bool loadKeyFromStr(const std::string &str);
public:
explicit CryptoRSA(int keysize);
explicit CryptoRSA(const std::string &key);
virtual ~CryptoRSA();
inline unsigned char* getRSAIV() const { return _iv; }
inline unsigned char* getRSAEncryptedKey() const { return _encryptedKey; }
inline EVP_PKEY *getEvpPkey() { return _pkey; }
inline int getEvpPkeySize(EVP_PKEY *key) { return EVP_PKEY_size(key); }
char *getRSAPrivateKeyStr();
char *getPrivateKeyStr();
char *getPublicKeyStr();
int encryptEVP(EVP_PKEY *key, const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage, unsigned char **encryptedKey, size_t *encryptedKeyLength, unsigned char **iv);
int decryptEVP(EVP_PKEY *key, unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char *encryptedKey, size_t encryptedKeyLength, unsigned char *iv, unsigned char **decryptedMessage);
};
} // namespace tools
#endif //RSA_RSA_H
and rsa.cpp
#include "rsa.h"
namespace tools
{
CryptoRSA::CryptoRSA(int keysize) : _keysize(keysize), _pkey(nullptr)
{
// Initalize contexts
rsaEncryptContext = EVP_CIPHER_CTX_new();
rsaDecryptContext = EVP_CIPHER_CTX_new();
// Generate the RSA Key
if ( !generateRSAKey() )
{
#ifdef LOGGING
std::cerr << "Error at generating the RSA key!" << std::endl;
#endif
throw std::runtime_error("Error at generating the RSA key!");
}
}
CryptoRSA::CryptoRSA(const std::string &key) : _keysize(-1), _pkey(nullptr)
{
// Initalize contexts
rsaEncryptContext = EVP_CIPHER_CTX_new();
rsaDecryptContext = EVP_CIPHER_CTX_new();
// Load pkey from file or string
if ( !loadKeyFromFile(key) )
{
#ifdef LOGGING
std::cerr << "Could not load key from file/string!" << std::endl;
#endif
}
}
CryptoRSA::~CryptoRSA()
{
EVP_PKEY_free(_pkey);
EVP_CIPHER_CTX_free(rsaEncryptContext);
EVP_CIPHER_CTX_free(rsaDecryptContext);
}
std::string CryptoRSA::getOpenSSLError()
{
char *buf;
BIO *bio = BIO_new(BIO_s_mem());
ERR_print_errors(bio);
size_t len = static_cast<size_t >(BIO_get_mem_data(bio, &buf));
std::string err(buf, len);
BIO_free(bio);
return err;
}
bool CryptoRSA::generateRSAKey()
{
EVP_PKEY_CTX *context = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if(EVP_PKEY_keygen_init(context) <= 0)
{
return false;
}
if(EVP_PKEY_CTX_set_rsa_keygen_bits(context, _keysize) <= 0)
{
return false;
}
if(EVP_PKEY_keygen(context, &_pkey) <= 0)
{
return false;
}
EVP_PKEY_CTX_free(context);
return true;
}
bool CryptoRSA::loadKeyFromFile(const std::string &filepath)
{
if ( existsFile(filepath) )
{
if ( loadKeyFromStr(readBinFile(filepath)) )
{
#ifdef LOGGING
std::cerr << "Loaded successfully rsa key from file " << filepath << std::endl;
#endif
return true;
}
} else
{
if ( loadKeyFromStr(filepath) )
{
#ifdef LOGGING
std::cerr << "Loaded successfully rsa key from string!" << std::endl;
#endif
return true;
}
}
return false;
}
bool CryptoRSA::loadKeyFromStr(const std::string &str)
{
std::string fLine;
std::istringstream f(str);
std::getline(f, fLine);
BIO *bioPrivate = BIO_new(BIO_s_mem());
BIO_write(bioPrivate, str.c_str(), static_cast<int>(str.length()));
if (fLine == "-----BEGIN RSA PRIVATE KEY-----")
{
_pkey = PEM_read_bio_PrivateKey(bioPrivate, nullptr, nullptr, nullptr);
} else if (fLine == "-----BEGIN PUBLIC KEY-----")
{
_pkey = PEM_read_bio_PUBKEY(bioPrivate, nullptr, nullptr, nullptr);
} else
{
#ifdef LOGGING
std::cerr << "Unsupported file provided with file header: " << fLine << std::endl;
#endif
BIO_free(bioPrivate);
return false;
}
BIO_free(bioPrivate);
return true;
}
char* CryptoRSA::getRSAPrivateKeyStr()
{
RSA *rsaPrivateKey = EVP_PKEY_get0_RSA(_pkey);
BIO *bioPrivate = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(bioPrivate, rsaPrivateKey, nullptr, nullptr, 0, nullptr, nullptr);
BIO_flush(bioPrivate);
BIO_get_mem_data(bioPrivate, &_rsaPrivateKeyStr);
return _rsaPrivateKeyStr;
}
char* CryptoRSA::getPrivateKeyStr()
{
BIO *bioPrivate = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(bioPrivate, _pkey, NULL, NULL, 0, 0, NULL);
BIO_flush(bioPrivate);
BIO_get_mem_data(bioPrivate, &_privateKeyStr);
return _privateKeyStr;
}
char* CryptoRSA::getPublicKeyStr()
{
BIO *bioPublic = BIO_new(BIO_s_mem());
PEM_write_bio_PUBKEY(bioPublic, _pkey);
BIO_flush(bioPublic);
BIO_get_mem_data(bioPublic, &_publicKeyStr);
return _publicKeyStr;
}
int CryptoRSA::encryptEVP(EVP_PKEY *key, const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage,
unsigned char **encryptedKey, size_t *encryptedKeyLength, unsigned char **iv)
{
// Allocate memory for everything
size_t encryptedMessageLength = 0;
size_t blockLength = 0;
*encryptedKey = (unsigned char*)malloc(EVP_PKEY_size(key));
*iv = (unsigned char*)malloc(EVP_MAX_IV_LENGTH);
*encryptedMessage = (unsigned char*)malloc(messageLength + EVP_MAX_IV_LENGTH);
if(!EVP_SealInit(rsaEncryptContext, EVP_aes_256_cbc(), encryptedKey, (int*)encryptedKeyLength, *iv, &key, 1))
{
#ifdef LOGGING
std::cerr << "Error during EVP_SealInit in RSA encrypt: " << getOpenSSLError() << std::endl;
#endif
return -1;
}
if(!EVP_SealUpdate(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength, (const unsigned char*)message, (int)messageLength))
{
#ifdef LOGGING
std::cerr << "Error during EVP_SealUpdate in RSA encrypt: " << getOpenSSLError() << std::endl;
#endif
return -1;
}
encryptedMessageLength += blockLength;
if(!EVP_SealFinal(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength))
{
#ifdef LOGGING
std::cerr << "Error during EVP_SealFinal in RSA encrypt: " << getOpenSSLError() <<std::endl;
#endif
return -1;
}
encryptedMessageLength += blockLength;
return (int)encryptedMessageLength;
}
int CryptoRSA::decryptEVP(EVP_PKEY *key, unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char *encryptedKey,
size_t encryptedKeyLength, unsigned char *iv, unsigned char **decryptedMessage)
{
// Allocate memory for everything
size_t decryptedMessageLength = 0;
size_t blockLength = 0;
*decryptedMessage = (unsigned char*)malloc(encryptedMessageLength + EVP_MAX_IV_LENGTH);
// Decrypt it!
if(!EVP_OpenInit(rsaDecryptContext, EVP_aes_256_cbc(), encryptedKey, getEvpPkeySize(key), iv, key))
{
#ifdef LOGGING
std::cerr << "Error during EVP_OpenInit in RSA decrypt: " << getOpenSSLError() << std::endl;
#endif
return -1;
}
if(!EVP_OpenUpdate(rsaDecryptContext, (unsigned char*)*decryptedMessage + decryptedMessageLength, (int*)&blockLength, encryptedMessage, (int)encryptedMessageLength))
{
#ifdef LOGGING
std::cerr << "Error during EVP_OpenUpdate in RSA decrypt: " << getOpenSSLError() << std::endl;
#endif
return -1;
}
decryptedMessageLength += blockLength;
if(!EVP_OpenFinal(rsaDecryptContext, (unsigned char*)*decryptedMessage + decryptedMessageLength, (int*)&blockLength))
{
#ifdef LOGGING
std::cerr << "Error during EVP_OpenFinal in RSA decrypt: " << getOpenSSLError() << std::endl;
#endif
return -1;
}
decryptedMessageLength += blockLength;
return (int)decryptedMessageLength;
}
} // namespace tools
main.cpp
#include <iostream>
#include <memory>
#include <cstring>
#include "rsa.h"
bool writeBinFile(const std::string &filepath, const char* content, long contentLength, bool append=false)
{
std::fstream out;
if (append)
{
out.open(filepath, std::ios::out | std::ios::app | std::ios::binary);
} else
{
out.open(filepath, std::ios::out | std::ios::binary);
}
if (out.is_open())
{
out.write(content, contentLength);
return true;
} else
{
return false;
}
}
void encrypt_decrypt_with_evp(std::string msg_to_encrypt)
{
std::unique_ptr<tools::CryptoRSA> cryptoRSA = std::unique_ptr<tools::CryptoRSA>(new tools::CryptoRSA(2048));
unsigned char *encryptedMessage = nullptr;
char *decryptedMessage = nullptr;
unsigned char *encryptedKey;
unsigned char *iv;
size_t encryptedKeyLength;
std::string priv = cryptoRSA->getRSAPrivateKeyStr();
std::string pub = cryptoRSA->getPublicKeyStr();
// Save RSA KeyPair
writeBinFile("RSAPrivateKey.pem", priv.c_str(), priv.length());
writeBinFile("PublicKey.pem", pub.c_str(), pub.length());
// Start RSA Encryption
int encryptedMessageLength = cryptoRSA->encryptEVP(cryptoRSA->getEvpPkey(), (const unsigned char*)msg_to_encrypt.c_str(), msg_to_encrypt.size()+1,
&encryptedMessage, &encryptedKey, &encryptedKeyLength, &iv);
if(encryptedMessageLength == -1)
{
std::cerr << "Encryption failed" << std::endl;
exit(1);
}
std::cout << "Encrypted message: " << encryptedMessage << std::endl;
writeBinFile("enc_msg.bin", reinterpret_cast<const char *>(encryptedMessage), encryptedMessageLength);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Start RSA Decryption
int decryptedMessageLength = cryptoRSA->decryptEVP(cryptoRSA->getEvpPkey(), encryptedMessage, (size_t)encryptedMessageLength,
encryptedKey, encryptedKeyLength, iv, (unsigned char**)&decryptedMessage);
if(decryptedMessageLength == -1)
{
std::cerr << "Decryption failed" << std::endl;
exit(1);
}
std::cout << "Decrypted message: " << decryptedMessage << std::endl;
}
int main(int argc, char* argv[])
{
encrypt_decrypt_with_evp("abcdef");
return 0;
}
The RSA Encryption and Decryption with the implemented class works completely fine.
What i would like to achieve is the following:
Encrypt a message like abcdef with my implemented solution and save the content in a file enc_msg.bin
Using the openssl command line interface (for instance: openssl rsautl) to decrypt the message
Or:
Encrypt the message abcdef with the openssl command line interface
Decrypt the created file with my implemented solution
As you can see the EVP_SealInit uses the EVP_aes_256_cbc with an encryptedKey and an IV. But i didn´t find a possibility to provide those parameters to the openssl rsautl cli.
Does anyone know how to decrypt messages (with Openssl cli) which were created with the EVP methods (EVP_SealInit, EVP_SealUpdate, EVP_SealFinal)?
Every help is highly appreciated!

With the help of #Topaco i found the solution. It is a Hybrid Encryption
I saved also the EncryptedKey and the IV to rsa_ek.bin and rsa_iv.txt file.
Decrypt the rsa_ek.bin with the openssl rsautl cli
openssl rsautl -decrypt -inkey RSAPrivateKey.pem -in rsa_ek.bin -out rsa_ek.txt
Decrypt the enc_msg.bin file with the AES-256-CBC Cipher
openssl enc -aes-256-cbc -d -in enc_msg.bin -K $(xxd -p -c 256 rsa_ek.txt) -iv $(xxd -p -c 256 rsa_iv.txt) -out enc_msg.dec.txt

Related

OpenSSL RSA_sign C++ - Different sign than the command line

I am trying to develop a Digital Signature tool using OpenSSL's libs but the created sign from my code is different than the one I get from the command line.
I checked and validated that the SHA256 digest is correct.
This is an example of the command I use to validate the signatures:
openssl rsautl -sign -inkey privateKey.pem -in hash.txt > signature
Based on my code below, is there something obvious that I am doing wrong?
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
using namespace std;
RSA * generateKeys()
{
RSA *rsa = RSA_new();
BIGNUM *bignum = NULL;
bignum = BN_new();
BN_set_word(bignum, RSA_F4);
FILE *file;
bool exists;
if ((file = fopen("privateKey.pem", "r")))
{
exists = true;
fclose(file);
}
if (!exists)
{
FILE *pkey = fopen("privateKey.pem", "wb");
RSA_generate_key_ex(rsa, 2048, bignum, NULL);
PEM_write_RSAPrivateKey(pkey, rsa, NULL, NULL, 0, NULL, NULL);
fclose(pkey);
}else{
FILE *pkey = fopen("privateKey.pem", "rb");
PEM_read_RSAPrivateKey(
pkey,
&rsa,
NULL,
NULL);
fclose(pkey);
}
return rsa;
}
// Sign document
void sign(const char *filepath)
{
FILE *file = fopen(filepath, "r");
// SHA256 digest
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
char *buffer[1024];
int bytesRead = 0;
while ((bytesRead = fread(buffer, 1, 1024, file)))
{
SHA256_Update(&sha256, buffer, bytesRead);
}
fclose(file);
SHA256_Final(hash, &sha256);
// Retrieve keys (create keys if it does not exist)
RSA *rsa = generateKeys();
// Sign
const int size = RSA_size(rsa);
unsigned char *sign = new unsigned char[size];
unsigned int outlen = 0;
RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, sign, &outlen, rsa);
FILE *signedDoc = fopen("signedDocument.signed","wb");
fputs((const char *) sign,signedDoc);
fclose(signedDoc);
}
// Validate document
// int validate(FILE *file){
// return 0;
// }
int main(int argc, char *argv[])
{
// Input validation
if (argc == 1)
{
cout << "Usage: sign -sv document" << endl
<< "-s sign document" << endl
<< "-v validate document signature" << endl;
return 0;
}
if (argc > 3 || (string(argv[1]) != "-s" && string(argv[1]) != "-v"))
{
cout << "Error: Wrong arguments given." << endl
<< "sign for help" << endl;
return -1;
}
FILE *document = fopen(argv[2], "r");
if (document == NULL)
{
cout << "File open error.." << endl;
return -1;
}
// Sign document
if ((string(argv[1]) == "-s"))
{
sign(argv[2]);
}
// // Validate signature
// if((string(argv[1]) == "-v")){
// validate(document);
// }
}
And these are the flags I use to compile it:
-Wall -Werror -Wextra -pedantic -lcrypto -std=c++11 -g
Thanks in advance.
I have implemented the RSA_verify function and based on the sign my code does, RSA_verify works and it returns that it is valid. I have also added the code to save the public key as well.
My best guess is that my code doesn't represent exactly the command.

Incorrect signature with RSA and SHA256

I have the following string:ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=
I want to apply SHA256 to it and obtain its hash.
Then I want to sign that hash with RSA and a private key.
This is the signature I'm suppose to be obtaining (without line breaks):
Zg8ftxJqRyoreMQtMKAZNrjHHcD/rOSkU29Ty8zV9aItwHBDO0WpzaaPrqnX6/vdayUAndDVvSBoOc9g0WBkFHQHtB/auLlq+ABeBP4jxy
d7ypPxBbJFecfZiBDaGCq4jAxUnhQ2HjT5R23DHOOcf/i50TrWXr2G5k8enqa754TUn1JiDOJJT2JkfnKmgM7EPpCjHV/eCJsOQFXNaxht
h7zHz5hZ4aOfy6EGGveOggzIjKSLeo0pIE8jBc1wy9V8vZkhPTpkeLguCxnwvpMIV1X7zF3m5OoM0PbC5yXgPUYPrz0JNSlvCKR9q5CsFm
rnit5vBfi5el1ZmevP2MgyEA==
This is the signature I get:
AR1X19H5wyb9IEi9WHrhatkR1jtTc7TovX23tdx8yID5CEWz+DF5kBNCXZxttJ8v
ctsbOL0rrQ0b4Gqa2ld00+nfzZJNg1osWwKb+sj6yNLy1XLqxFvfn1wrZ9Y8yOwS
oqJ0tTCpYbbbMo1mSVO4YuD18GbZJEDBUhBYY5D8H0MoHCSWLXsAjThAImyxw4ch
Hr2d1Sli4n6OA+CckGOQ15uLk6JiO6rNzNWfbbSb8a9trJ7bAdVPiKoln1X9tnWF
s3HK6fnfro9jlRQQ/Z0bCpF+FQrWrLouvLk+mjuTeiC+86HeeqzqlReAtpqtcO5/
9lWmrxXV2qZIqfuPYMovcA==
The code I'm using:
#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 <string.h>
#include <cstring>
std::string privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"\
"MIIEogIBAAKCAQEAjdKXiqYHzi++YmEb9X6qvqFWLCz1VEfxom2JhinPSJxxcuZW\n"\
"Bejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvYJumKO4R5zg0QSA7qdxiEhcwf/ekf\n"\
"SvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ7EgEcWUTvCs/GZJLI9s6XmKY2SMm\n"\
"v9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/yJ4vZwXvXGFqNDJyqG+ww7f77HYu\n"\
"bQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/BeZlL1YJHHM7CIBnb3/bzED0n944wo\n"\
"io+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/JRQIDAQABAoIBAG2AzvWE4L346z02\n"\
"0cmptdhe5hRR2lLrAc1yWh83JQ9hi881vfHuMtRql+3cZ218SV4nRNarIo6612NJ\n"\
"JFfM3SaeZ9cwoIPSXmHk8nBmg9xzEbiRSVIzA09uPZB4t9EB+sNYQvDkPMuPn0b3\n"\
"EWaq+LWRnayYaLZ/hccOx+m1mcnJnIs27+EPnufrUKVniCguburQoU3VEXSFCzBk\n"\
"23rhSu20vUOikLuuU4gcvWfnfUoOwdhb2iBhjgMbsjTTmg3+GQuPtblCSTKjk11F\n"\
"YX2MJHEDFfwVzSurmbqAZC9rjr7PbflC8GMmPfa1LCb7IG5s9AIM4v9Fea0SyZP+\n"\
"/pM9mzkCgYEAyjLPU7ieqly9+mgeb2fmWh7pYgO49KuFIqqHnP+LaXXYK/TvCJ8X\n"\
"zJ3PxBgwVMOT94nXSDNjzNLzp0hl8OWWBH0tN0fiq1OEyySM3Mlji6o8KpGcU1k4\n"\
"jFkXMK1rVQcW8ckLmzMrQF3SphQi4UiEpLX1Zba4YQ4fNHK8NHHHaEMCgYEAs48m\n"\
"Oe4iEZcVDnag+Mp0Zjgu4mYJeeeGtVUZFCJOeyLDsQVmnt5mJIgGwrxg4o3qljut\n"\
"aAUXzf8aYZ0fURAsLcwnQg03THFKeIt94Rw/72n2UWT+AZTU3GQtuwf+osZHUfS3\n"\
"XTLaQE+A1JBC4XLJ99j/95sxt6xZy5YyfhfY09cCgYAbqyhDxJexqE823NiNViJn\n"\
"YqN9DhVZJb9qJvu3uCBTphSWr0WmYF7ZWR79LnIupzSwQuR6tM2LUbKVyYpplIEa\n"\
"zCZL0kJqP1uEkNPVwpkkm37wNEy3+xWJ3wcVWiW91OKG44P7EN1ySWRx5X+AZHQC\n"\
"NgQGjyJb5ZrPioPGiWtIEQKBgE/0B/N3o9ftTET6cccWbootDkNlaAbOH1+TGu2q\n"\
"MQQHgNfMLdvD7/uITmpb81AuHSz0Ocy9p9HkK90XV6CC8QkbhMeWlu8E60It6slY\n"\
"COgUaMfpjmkp2nagbPSBJNNaMtu9egCX6jMEs7ry2bUFpgUkrSWWB1df+UP8B1O6\n"\
"TqRVAoGAVQoCUPVm6C6h6V5dgPvsJMxJ8EjOCgwkXNucAHWcpBV3/LlxLiCGRuEL\n"\
"B+epYxqwKLpSQBhldasKmmKB0M6MFTwxXwxCmCi80+DBdP5A7GIK52ZGth63i22t\n"\
"FI8MeDIzA5HqAI24P7ltozoEYAB7GIdJQXq9oT/DRagTwQUzQ8E=\n"\
"-----END RSA PRIVATE KEY-----\n";
/*std::string privateKey ="-----BEGIN PRIVATE KEY-----\n"\
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN0peKpgfOL75i\n"\
"YRv1fqq+oVYsLPVUR/GibYmGKc9InHFy5lYF6OTYjnIIvmkOdRobbGlCUxORX/tL\n"\
"sl8Ya9gm6Yo7hHnODRBIDup3GISFzB/96R9K/MzYQOcscMIoBDARaycnLvy7FlMv\n"\
"O7/rlVnsSARxZRO8Kz8Zkksj2zpeYpjZIya/369+oGqQk1cTRkHo59JvJ4Tfbk/3\n"\
"iIyf4H/Ini9nBe9cYWo0MnKob7DDt/vsdi5tA8mMtA953LapNyCZIDCRQQlUGNgD\n"\
"qY9/8F5mUvVgkcczsIgGdvf9vMQPSf3jjCiKj7j6ucxl1+FwJWmbvgNmiaUR/0q4\n"\
"m2rm78lFAgMBAAECggEAbYDO9YTgvfjrPTbRyam12F7mFFHaUusBzXJaHzclD2GL\n"\
"zzW98e4y1GqX7dxnbXxJXidE1qsijrrXY0kkV8zdJp5n1zCgg9JeYeTycGaD3HMR\n"\
"uJFJUjMDT249kHi30QH6w1hC8OQ8y4+fRvcRZqr4tZGdrJhotn+Fxw7H6bWZycmc\n"\
"izbv4Q+e5+tQpWeIKC5u6tChTdURdIULMGTbeuFK7bS9Q6KQu65TiBy9Z+d9Sg7B\n"\
"2FvaIGGOAxuyNNOaDf4ZC4+1uUJJMqOTXUVhfYwkcQMV/BXNK6uZuoBkL2uOvs9t\n"\
"+ULwYyY99rUsJvsgbmz0Agzi/0V5rRLJk/7+kz2bOQKBgQDKMs9TuJ6qXL36aB5v\n"\
"Z+ZaHuliA7j0q4Uiqoec/4tpddgr9O8InxfMnc/EGDBUw5P3iddIM2PM0vOnSGXw\n"\
"5ZYEfS03R+KrU4TLJIzcyWOLqjwqkZxTWTiMWRcwrWtVBxbxyQubMytAXdKmFCLh\n"\
"SISktfVltrhhDh80crw0ccdoQwKBgQCzjyY57iIRlxUOdqD4ynRmOC7iZgl554a1\n"\
"VRkUIk57IsOxBWae3mYkiAbCvGDijeqWO61oBRfN/xphnR9RECwtzCdCDTdMcUp4\n"\
"i33hHD/vafZRZP4BlNTcZC27B/6ixkdR9LddMtpAT4DUkELhcsn32P/3mzG3rFnL\n"\
"ljJ+F9jT1wKBgBurKEPEl7GoTzbc2I1WImdio30OFVklv2om+7e4IFOmFJavRaZg\n"\
"XtlZHv0uci6nNLBC5Hq0zYtRspXJimmUgRrMJkvSQmo/W4SQ09XCmSSbfvA0TLf7\n"\
"FYnfBxVaJb3U4objg/sQ3XJJZHHlf4BkdAI2BAaPIlvlms+Kg8aJa0gRAoGAT/QH\n"\
"83ej1+1MRPpxxxZvKi0OQ2VoBs4fX5Ma7aoxBAeA18wt28Pv+4hOalvzUC4dLPQ5\n"\
"zL2n0eQr3RdXoILxCRuEx5aW7wTrQi3qyVgI6BRox+mOaSnadqBs9IEk01oy2716\n"\
"AJfqMwSzuvLZtQWmBSStJZYHV1/5Q/wHU7pOpFUCgYBVCgJQ9WboLqHpXl2A++wk\n"\
"zEnwSM4KDCRc25wAdZykFXf8uXEuIIZG4QsH56ljGrAoulJAGGV1qwqaYoHQzowV\n"\
"PDFfDEKYKLzT4MF0/kDsYgrnZka2HreLba0Ujwx4MjMDkeoAjbg/uW2jOgRgAHsY\n"\
"h0lBer2hP8NFqBPBBTNDwQ==\n"\
"-----END PRIVATE KEY-----\n";
*/
std::string publicKey ="-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdKXiqYHzi++YmEb9X6q\n"\
"vqFWLCz1VEfxom2JhinPSJxxcuZWBejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvY\n"\
"JumKO4R5zg0QSA7qdxiEhcwf/ekfSvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ\n"\
"7EgEcWUTvCs/GZJLI9s6XmKY2SMmv9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/\n"\
"yJ4vZwXvXGFqNDJyqG+ww7f77HYubQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/Be\n"\
"ZlL1YJHHM7CIBnb3/bzED0n944woio+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/J\n"\
"RQIDAQAB\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);
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);
}
unsigned char * strToHex(std::string plainText){
unsigned char * hexArray;
hexArray = (unsigned char*)malloc(plainText.length());
for(int i = 0; i < plainText.size();i++){
hexArray[i] = std::strtol(&plainText[i],NULL,64);
}
return hexArray;
}
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.data(), 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 = "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=";
char* signature = signMessage(privateKey, plainText);
bool authentic = verifySignature(publicKey, "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=", signature);
if ( authentic ) {
std::cout << "Authentic" << std::endl;
std::cout << signature << std::endl;
} else {
std::cout << "Not Authentic" << std::endl;
}
}
What I'm actually trying to do is to 'translate' a C# code used by a third-party, I REQUIRE to do the same operations, I tried looking for the docs of the libreries used here but I couldn't find much, the code I'm trying to replicate is the following:
using System;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace KeyPairLoad
{
class Program
{
static void Main(string[] args)
{
string cadena = ComputeSha256Hash("ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=");
string pathPrivateKey = #"C:\Users\xxx\Downloads\Fieles de pruebas\FOO1\some.key";
string password = "12345678a";
byte[] privBytes = System.IO.File.ReadAllBytes(pathPrivateKey);
AsymmetricKeyParameter llavePrivada = PrivateKeyFactory.DecryptKey(password.ToCharArray(), privBytes);
var rsaPriv = DotNetUtilities.ToRSA(llavePrivada as RsaPrivateCrtKeyParameters);
var csp = new CspParameters();
csp.KeyContainerName = "KeyContainer";
var rsaPrivate = new RSACryptoServiceProvider(csp);
string fin = Convert.ToBase64String(rsaPrivate.SignHash(Convert.FromBase64String(cadena), "SHA256"));
}
static string ComputeSha256Hash(string rawData)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
return Convert.ToBase64String(bytes);
}
}
}
}
This third-party gave me the signature I'm supposed to be obtaining. I've tried many things but nothing works, I get different signatures but not the one I'm looking for.
Am I missing something in my translation? Am I doing something wrong?
Thanks for your patience and time. Let me know if u require more info.
Regards!
This code gets the desired signature:
Zg8ftxJqRyoreMQtMKAZNrjHHcD/rOSkU29Ty8zV9aItwHBDO0WpzaaPrqnX6/vdayUAndDVvSBoOc9g0WBkFHQHtB/auLlq+ABeBP4jxy
d7ypPxBbJFecfZiBDaGCq4jAxUnhQ2HjT5R23DHOOcf/i50TrWXr2G5k8enqa754TUn1JiDOJJT2JkfnKmgM7EPpCjHV/eCJsOQFXNaxht
h7zHz5hZ4aOfy6EGGveOggzIjKSLeo0pIE8jBc1wy9V8vZkhPTpkeLguCxnwvpMIV1X7zF3m5OoM0PbC5yXgPUYPrz0JNSlvCKR9q5CsFm
rnit5vBfi5el1ZmevP2MgyEA==
that I originally stated. It writes it in a file called result.dat which I have to encode in base 64 resulting int he above signature.
#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 <string>
#include <cstring>
#include <memory>
#include <vector>
#include <fstream>
#include "base64.h"
std::string privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEogIBAAKCAQEAjdKXiqYHzi++YmEb9X6qvqFWLCz1VEfxom2JhinPSJxxcuZW\n"
"Bejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvYJumKO4R5zg0QSA7qdxiEhcwf/ekf\n"
"SvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ7EgEcWUTvCs/GZJLI9s6XmKY2SMm\n"
"v9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/yJ4vZwXvXGFqNDJyqG+ww7f77HYu\n"
"bQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/BeZlL1YJHHM7CIBnb3/bzED0n944wo\n"
"io+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/JRQIDAQABAoIBAG2AzvWE4L346z02\n"
"0cmptdhe5hRR2lLrAc1yWh83JQ9hi881vfHuMtRql+3cZ218SV4nRNarIo6612NJ\n"
"JFfM3SaeZ9cwoIPSXmHk8nBmg9xzEbiRSVIzA09uPZB4t9EB+sNYQvDkPMuPn0b3\n"
"EWaq+LWRnayYaLZ/hccOx+m1mcnJnIs27+EPnufrUKVniCguburQoU3VEXSFCzBk\n"
"23rhSu20vUOikLuuU4gcvWfnfUoOwdhb2iBhjgMbsjTTmg3+GQuPtblCSTKjk11F\n"
"YX2MJHEDFfwVzSurmbqAZC9rjr7PbflC8GMmPfa1LCb7IG5s9AIM4v9Fea0SyZP+\n"
"/pM9mzkCgYEAyjLPU7ieqly9+mgeb2fmWh7pYgO49KuFIqqHnP+LaXXYK/TvCJ8X\n"
"zJ3PxBgwVMOT94nXSDNjzNLzp0hl8OWWBH0tN0fiq1OEyySM3Mlji6o8KpGcU1k4\n"
"jFkXMK1rVQcW8ckLmzMrQF3SphQi4UiEpLX1Zba4YQ4fNHK8NHHHaEMCgYEAs48m\n"
"Oe4iEZcVDnag+Mp0Zjgu4mYJeeeGtVUZFCJOeyLDsQVmnt5mJIgGwrxg4o3qljut\n"
"aAUXzf8aYZ0fURAsLcwnQg03THFKeIt94Rw/72n2UWT+AZTU3GQtuwf+osZHUfS3\n"
"XTLaQE+A1JBC4XLJ99j/95sxt6xZy5YyfhfY09cCgYAbqyhDxJexqE823NiNViJn\n"
"YqN9DhVZJb9qJvu3uCBTphSWr0WmYF7ZWR79LnIupzSwQuR6tM2LUbKVyYpplIEa\n"
"zCZL0kJqP1uEkNPVwpkkm37wNEy3+xWJ3wcVWiW91OKG44P7EN1ySWRx5X+AZHQC\n"
"NgQGjyJb5ZrPioPGiWtIEQKBgE/0B/N3o9ftTET6cccWbootDkNlaAbOH1+TGu2q\n"
"MQQHgNfMLdvD7/uITmpb81AuHSz0Ocy9p9HkK90XV6CC8QkbhMeWlu8E60It6slY\n"
"COgUaMfpjmkp2nagbPSBJNNaMtu9egCX6jMEs7ry2bUFpgUkrSWWB1df+UP8B1O6\n"
"TqRVAoGAVQoCUPVm6C6h6V5dgPvsJMxJ8EjOCgwkXNucAHWcpBV3/LlxLiCGRuEL\n"
"B+epYxqwKLpSQBhldasKmmKB0M6MFTwxXwxCmCi80+DBdP5A7GIK52ZGth63i22t\n"
"FI8MeDIzA5HqAI24P7ltozoEYAB7GIdJQXq9oT/DRagTwQUzQ8E=\n"
"-----END RSA PRIVATE KEY-----\n";
// std::string privateKey ="-----BEGIN PRIVATE KEY-----\n"\
// "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN0peKpgfOL75i\n"\
// "YRv1fqq+oVYsLPVUR/GibYmGKc9InHFy5lYF6OTYjnIIvmkOdRobbGlCUxORX/tL\n"\
// "sl8Ya9gm6Yo7hHnODRBIDup3GISFzB/96R9K/MzYQOcscMIoBDARaycnLvy7FlMv\n"\
// "O7/rlVnsSARxZRO8Kz8Zkksj2zpeYpjZIya/369+oGqQk1cTRkHo59JvJ4Tfbk/3\n"\
// "iIyf4H/Ini9nBe9cYWo0MnKob7DDt/vsdi5tA8mMtA953LapNyCZIDCRQQlUGNgD\n"\
// "qY9/8F5mUvVgkcczsIgGdvf9vMQPSf3jjCiKj7j6ucxl1+FwJWmbvgNmiaUR/0q4\n"\
// "m2rm78lFAgMBAAECggEAbYDO9YTgvfjrPTbRyam12F7mFFHaUusBzXJaHzclD2GL\n"\
// "zzW98e4y1GqX7dxnbXxJXidE1qsijrrXY0kkV8zdJp5n1zCgg9JeYeTycGaD3HMR\n"\
// "uJFJUjMDT249kHi30QH6w1hC8OQ8y4+fRvcRZqr4tZGdrJhotn+Fxw7H6bWZycmc\n"\
// "izbv4Q+e5+tQpWeIKC5u6tChTdURdIULMGTbeuFK7bS9Q6KQu65TiBy9Z+d9Sg7B\n"\
// "2FvaIGGOAxuyNNOaDf4ZC4+1uUJJMqOTXUVhfYwkcQMV/BXNK6uZuoBkL2uOvs9t\n"\
// "+ULwYyY99rUsJvsgbmz0Agzi/0V5rRLJk/7+kz2bOQKBgQDKMs9TuJ6qXL36aB5v\n"\
// "Z+ZaHuliA7j0q4Uiqoec/4tpddgr9O8InxfMnc/EGDBUw5P3iddIM2PM0vOnSGXw\n"\
// "5ZYEfS03R+KrU4TLJIzcyWOLqjwqkZxTWTiMWRcwrWtVBxbxyQubMytAXdKmFCLh\n"\
// "SISktfVltrhhDh80crw0ccdoQwKBgQCzjyY57iIRlxUOdqD4ynRmOC7iZgl554a1\n"\
// "VRkUIk57IsOxBWae3mYkiAbCvGDijeqWO61oBRfN/xphnR9RECwtzCdCDTdMcUp4\n"\
// "i33hHD/vafZRZP4BlNTcZC27B/6ixkdR9LddMtpAT4DUkELhcsn32P/3mzG3rFnL\n"\
// "ljJ+F9jT1wKBgBurKEPEl7GoTzbc2I1WImdio30OFVklv2om+7e4IFOmFJavRaZg\n"\
// "XtlZHv0uci6nNLBC5Hq0zYtRspXJimmUgRrMJkvSQmo/W4SQ09XCmSSbfvA0TLf7\n"\
// "FYnfBxVaJb3U4objg/sQ3XJJZHHlf4BkdAI2BAaPIlvlms+Kg8aJa0gRAoGAT/QH\n"\
// "83ej1+1MRPpxxxZvKi0OQ2VoBs4fX5Ma7aoxBAeA18wt28Pv+4hOalvzUC4dLPQ5\n"\
// "zL2n0eQr3RdXoILxCRuEx5aW7wTrQi3qyVgI6BRox+mOaSnadqBs9IEk01oy2716\n"\
// "AJfqMwSzuvLZtQWmBSStJZYHV1/5Q/wHU7pOpFUCgYBVCgJQ9WboLqHpXl2A++wk\n"\
// "zEnwSM4KDCRc25wAdZykFXf8uXEuIIZG4QsH56ljGrAoulJAGGV1qwqaYoHQzowV\n"\
// "PDFfDEKYKLzT4MF0/kDsYgrnZka2HreLba0Ujwx4MjMDkeoAjbg/uW2jOgRgAHsY\n"\
// "h0lBer2hP8NFqBPBBTNDwQ==\n"\
// "-----END PRIVATE KEY-----\n";
std::string publicKey ="-----BEGIN PUBLIC KEY-----\n"\
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjdKXiqYHzi++YmEb9X6q\n"\
"vqFWLCz1VEfxom2JhinPSJxxcuZWBejk2I5yCL5pDnUaG2xpQlMTkV/7S7JfGGvY\n"\
"JumKO4R5zg0QSA7qdxiEhcwf/ekfSvzM2EDnLHDCKAQwEWsnJy78uxZTLzu/65VZ\n"\
"7EgEcWUTvCs/GZJLI9s6XmKY2SMmv9+vfqBqkJNXE0ZB6OfSbyeE325P94iMn+B/\n"\
"yJ4vZwXvXGFqNDJyqG+ww7f77HYubQPJjLQPedy2qTcgmSAwkUEJVBjYA6mPf/Be\n"\
"ZlL1YJHHM7CIBnb3/bzED0n944woio+4+rnMZdfhcCVpm74DZomlEf9KuJtq5u/J\n"\
"RQIDAQAB\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;
}
void sellar(std::string hashclear, std::string privateKey_string){
EVP_PKEY_CTX *ctx;
/* md is a SHA-256 digest in this example. */
unsigned char *sig;
size_t siglen;
unsigned char clear_message[hashclear.length()];
strcpy((char*) clear_message,hashclear.c_str());
size_t mdlen;
// //1. Decodificar hashclear. || base64 -d data.dat > b64.dat -> Me debe dar una cadena de 32 bytes.
unsigned char * md = base64_decode(clear_message, strlen((char*) clear_message), &mdlen);
std::cout << "MD is " << mdlen << " bytes long.\n";
// //2. Cargar llave privada.
RSA* privateRSA = createPrivateRSA(privateKey);
EVP_PKEY* signing_key = EVP_PKEY_new();
EVP_PKEY_assign_RSA(signing_key, privateRSA);
ctx = EVP_PKEY_CTX_new(signing_key, NULL /* no engine */);
if(!ctx) {
std::cout << "Error CTX_new" << std::endl;
return;
}
if (EVP_PKEY_sign_init(ctx) <= 0){
std::cout << "Error sign_init\n";
return;
}
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0){
std::cout << "Error set_rsa_padding\n";
return;
}
if (EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0){
std::cout << "Error set_signature_md\n";
return;
}
/* Determine buffer length */
if (EVP_PKEY_sign(ctx, NULL, &siglen, md, mdlen) <= 0){
std::cout << "Error PKEY_sign\n";
return;
}
sig = (unsigned char*)OPENSSL_malloc(siglen);
if (!sig){
std::cout << "Error malloc";
return;
}
if (EVP_PKEY_sign(ctx, sig, &siglen, md, mdlen) <= 0){
std::cout << "Error sign";
return;
}
std::cout << siglen << " bytes written in buffer sig\n";
/* Signature is siglen bytes written to buffer sig */
size_t cadena_sellada_len;
unsigned char * cadena_sellada = base64_encode(sig, siglen, &cadena_sellada_len);
std::ofstream myfile ("result_final.dat");
if (myfile.is_open())
{
for(int count = 0; count < cadena_sellada_len; count ++){
myfile << cadena_sellada[count] ;
}
myfile.close();
}
else std::cout << "Unable to open file";
}
int main() {
std::string plainText = "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=\n";
// unsigned char src[plainText.length()];
// strcpy((char*) src,plainText.c_str());
// std::cout << "Src has " << strlen((char*)src) << " entries.\n";
// size_t out_len;
// unsigned char * bytes = base64_decode(src, strlen((char*)src), &out_len);
// std::cout << "bytes has " << out_len << " entries.\n";
// std::cout << bytes << std::endl;
// size_t re_out_len;
// unsigned char * re_encode = base64_encode(bytes, out_len,&re_out_len);
// std::cout << re_encode << "\n";
// std::ofstream myfile ("b64.dat");
// if (myfile.is_open())
// {
// for(int count = 0; count < out_len; count ++){
// myfile << bytes[count] ;
// }
// myfile.close();
// }
// else std::cout << "Unable to open file";
sellar(plainText, privateKey);
return 0;
//strcpy()
//std::cout << "Length : " << b64dat.length() << std::endl;
//char* signature = signMessage(privateKey, plainText);
//std::cout << signature << std::endl;
// bool authentic = verifySignature(publicKey, "ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=", signature);
// if ( authentic ) {
// std::cout << "Authentic" << std::endl;
// } else {
// std::cout << "Not Authentic" << std::endl;
// }
}
Thank you all for your time and patience.
I'm not going to read all the code to try and figure out what it is you're trying to do and thus where your mistake(s) are. Instead, I'll just examine what you've provided and you can go from there.
Clearly, both the signatures you've provided are valid signatures. This can be seen by manually going through the verification steps, stopping just after modular exponentiation using the encrypt exponent. The result is as expected for pkcs1 EMSA-PKCS1-v1_5 encoding. And just as clearly, we can see that different SHA-256 hashes are involved. In other words, the signatures are different because the data they are signing is different.
For the signature that starts with AR1X19... the data being signed is the UTF-8 encoding of the string ET8d1voUkzNcqud7M8W0WQcd3l2Ih1ZtiMxStPeubKg=. Note that this string a pretty obviously the base64-encoding of random looking 32 bytes. In this context one might guess that those 32-bytes are actually the sha256 hash of some other unknown quantity. And sure, enough the signature that starts with Zg8ftxJqR... is over data whose sha256 hash is the base64-decoding of ET8d....
So it looks like the first signature is correct, and the second one is the result of base64-encoding the sha256 hash during in the middle of the signing operation.

Generate an OAuth access token with openssl and c++

I need to get an access token (for a service account) for the google's OAuth authentication service. I tried several things an studied a lot of on the web but don't succeed.
Basically i followed https://developers.google.com/accounts/docs/OAuth2ServiceAccount
What i have done (VS2013):
int _tmain(int argc, _TCHAR* argv[])
{
Json::Value jwt_header;
Json::Value jwt_claim_set;
std::string jwt_b64;
std::time_t t = std::time(NULL);
Json::FastWriter jfw;
Json::StyledWriter jsw;
/* Create jwt header */
jwt_header["alg"] = "RS256";
jwt_header["typ"] = "JWT";
std::cout << jsw.write(jwt_header);
/* Create jwt claim set */
jwt_claim_set["iss"] = "myid#developer.gserviceaccount.com"; /* service account email address */
jwt_claim_set["scope"] = "https://www.googleapis.com/auth/plus.me" /* scope of requested access token */;
jwt_claim_set["aud"] = "https://accounts.google.com/o/oauth2/token"; /* intended target of the assertion for an access token */
jwt_claim_set["iad"] = std::to_string(t); /* issued time */
jwt_claim_set["exp"] = std::to_string(t+3600); /* expire time*/
std::cout << jsw.write(jwt_claim_set);
/* create http POST request body */
/* for header */
std::string json_buffer;
std::string json_buffer1;
json_buffer = jfw.write(jwt_header);
json_buffer = json_buffer.substr(0, json_buffer.size() - 1);
json_buffer = base64_encode(reinterpret_cast<const unsigned char*>(json_buffer.c_str()), json_buffer.length(), true); /* urlsafeBasic64 encode*/
json_buffer1.clear();
std::remove_copy(json_buffer.begin(), json_buffer.end(), std::back_inserter(json_buffer1), '=');
jwt_b64 = json_buffer1;
jwt_b64 += ".";
/* for claim set */
json_buffer = jfw.write(jwt_claim_set);
json_buffer = json_buffer.substr(0, json_buffer.size() - 1);
json_buffer = base64_encode(reinterpret_cast<const unsigned char*>(json_buffer.c_str()), json_buffer.length(), true); /* urlsafeBasic64 encode*/
json_buffer1.clear();
std::remove_copy(json_buffer.begin(), json_buffer.end(), std::back_inserter(json_buffer1), '=');
jwt_b64 += json_buffer1;
/* for signature */
std::string jwt_signature = jws_sign(jwt_b64, "key.p12");
if (!jwt_signature.empty())
{
jwt_b64 += ".";
json_buffer1.clear();
std::remove_copy(jwt_signature.begin(), jwt_signature.end(), std::back_inserter(json_buffer1), '=');
jwt_b64 += json_buffer1;
write2file("jwt.bat", jwt_b64); /* for test purpose calling with curl */
}
else
std::cout << "Error creating signature";
return 0;
}
int write2file(std::string filename, std::string data)
{
std::ofstream f(filename);
f << "%curl% -d \"grant_type=urn%%3Aietf%%3Aparams%%3Aoauth%%3Agrant-type%%3Ajwt-bearer&assertion=";
f << data;
f << "\" https://accounts.google.com/o/oauth2/token";
f.close();
return 0;
}
std::string jws_sign(std::string data, std::string pkcs12_path) {
SHA256_CTX mctx;
unsigned char hash[SHA256_DIGEST_LENGTH];
size_t hlen = SHA256_DIGEST_LENGTH;
const char *buf = data.c_str();
int n = strlen((const char*) buf);
SHA256_Init(&mctx);
SHA256_Update(&mctx, buf, n);
SHA256_Final(hash, &mctx);
std::string signature_b64;
unsigned char *sig = NULL;
size_t slen = 0;
EVP_PKEY_CTX *kctx;
EVP_PKEY *key = getPkey(pkcs12_path);
kctx = EVP_PKEY_CTX_new(key, NULL);
if (!kctx) goto err;
if (EVP_PKEY_sign_init(kctx) <= 0) goto err;
if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PADDING) <= 0) goto err;
if (EVP_PKEY_CTX_set_signature_md(kctx, EVP_sha256()) <= 0) goto err;
/* Determine buffer length */
if (EVP_PKEY_sign(kctx, NULL, &slen, hash, hlen) <= 0) goto err;
sig = (unsigned char *) OPENSSL_malloc(slen);
if (!sig) goto err;
if (EVP_PKEY_sign(kctx, sig, &slen, hash, hlen) <= 0) goto err;
signature_b64 = base64_encode(sig, (unsigned int)slen, true);
return signature_b64;
err:
/* Clean up */
EVP_cleanup();
signature_b64.clear();
return signature_b64;
}
All i receive back is
{
"error" : "invalid_grant"
}
So if someone can point me into the right direction would be great.
It would also help, if someone can point me to get the thing working by manually generating the jwt request out of openssl commands.
I'm working with VS2013
I found my mistake - was simply a typo :(
jwt_claim_set["iad"] = std::to_string(t); /* issued time */
needs to be
jwt_claim_set["iat"] = std::to_string(t); /* issued time */
The code works and generate valid token requests.
I've made a class for authentication on C++, will leave it here, may be someone may need it.
// YOU SHOULD GO TO Credentials SECTION FOR YOUR PROJECT AT https://console.developers.google.com/
// MAKE Service Account AND GET AUTHENTICATION JSON FROM IT,
// PLACE IT TO BUILD FOLDER AND CALL IT google_service_account.json
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iomanip>
// SSL INCLUDES
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
// https://github.com/nlohmann/json
#include <nlohmann/json.hpp>
using json = nlohmann::json;
class TGoogleAuthCpp {
json serviceAccountJSON;
bool serviceAccountExists;
void readServiceAccountJson();
RSA* createPrivateRSA(std::string key);
bool RSASign( RSA* rsa,
const unsigned char* Msg,
size_t MsgLen,
unsigned char** EncMsg,
size_t* MsgLenEnc);
std::string signMessage(std::string privateKey, std::string plainText);
std::string url_encode(const std::string &value);
std::string base64_encode(const std::string &in);
public:
TGoogleAuthCpp();
int createRequest();
};
TGoogleAuthCpp::TGoogleAuthCpp() {
serviceAccountExists = false;
readServiceAccountJson();
}
RSA* TGoogleAuthCpp::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;
}
bool TGoogleAuthCpp::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;
}
std::string TGoogleAuthCpp::signMessage(std::string privateKey, std::string plainText) {
RSA* privateRSA = createPrivateRSA(privateKey);
unsigned char* encMessage;
size_t encMessageLength;
RSASign(privateRSA, (unsigned char*) plainText.c_str(), plainText.length(), &encMessage, &encMessageLength);
std::string str1((char *)(encMessage), encMessageLength);
free(encMessage);
return base64_encode(str1);
}
void TGoogleAuthCpp::readServiceAccountJson() {
std::string fname = "google_service_account.json";
std::string line;
std::ifstream myfile (fname);
if (myfile.good()) {
std::stringstream ss;
if (myfile.is_open()) {
while (getline(myfile, line)) {
ss << line << '\n';
}
myfile.close();
serviceAccountJSON = json::parse(ss.str());
serviceAccountExists = true;
}
}
}
std::string TGoogleAuthCpp::base64_encode(const std::string &in) {
std::string out;
std::string base64_encode_b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//=
int val=0, valb=-6;
for (unsigned char c : in) {
val = (val<<8) + c;
valb += 8;
while (valb>=0) {
out.push_back(base64_encode_b[(val>>valb)&0x3F]);
valb-=6;
}
}
if (valb>-6) out.push_back(base64_encode_b[((val<<8)>>(valb+8))&0x3F]);
while (out.size()%4) out.push_back('=');
return out;
}
std::string TGoogleAuthCpp::url_encode(const std::string &value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) {
std::string::value_type c = (*i);
// Keep alphanumeric and other accepted characters intact
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
// Any other characters are percent-encoded
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char) c);
escaped << std::nouppercase;
}
return escaped.str();
}
int TGoogleAuthCpp::createRequest() {
if (!serviceAccountExists) return 0;
json jwt_header;
json jwt_claim_set;
std::time_t t = std::time(NULL);
// Create jwt header
jwt_header["alg"] = "RS256";
jwt_header["typ"] = "JWT";
// Create jwt claim set
jwt_claim_set["iss"] = serviceAccountJSON["client_email"]; /* service account email address */
jwt_claim_set["scope"] = "https://www.googleapis.com/auth/androidpublisher" /* scope of requested access token */;
jwt_claim_set["aud"] = serviceAccountJSON["token_uri"]; /* intended target of the assertion for an access token */
jwt_claim_set["iat"] = t; /* issued time */
jwt_claim_set["exp"] = t+3600; /* expire time*/
// web token
std::stringstream jwt_ss;
// header
jwt_ss << base64_encode(jwt_header.dump());
jwt_ss << ".";
// claim set
jwt_ss << base64_encode(jwt_claim_set.dump());
// signature
std::string signed_msg = signMessage(serviceAccountJSON["private_key"], jwt_ss.str());
jwt_ss << "." << signed_msg;
std::stringstream post_body_ss;
post_body_ss << "curl -d '";
post_body_ss << "grant_type=" << url_encode("urn:ietf:params:oauth:grant-type:jwt-bearer");
post_body_ss << "&assertion=" << url_encode(jwt_ss.str());
post_body_ss << "' https://oauth2.googleapis.com/token";
std::string post_body = post_body_ss.str();
std::cout << post_body << std::endl;
return 1;
}
int main() {
TGoogleAuthCpp auth;
int res = auth.createRequest();
}

How to create a RSA public key from a unsigned char * modulus and exponent 65537(RSA_F4)

I'm trying generate a rsa public key from a modulus type char[], and I now the exponent is RSA_F4(65537);
But when I'm trying generate my public key using this values for "n" and "e", the RSA_public_encrypt, return -1;
Thanks!
My code:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <crypt.h>
#include <iostream>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/opensslconf.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rc4.h>
using namespace std;
int main(void)
{
//modulus in format char hex;
char key[] = "C0E7FC730EB5CF85B040EC25DAEF288912641889AD651B3707CFED9FC5A1D3F6C40062AD46E3B3C3E21D4E71CC4800C80226D453242AEB2F86D748B41DDF35FD";
char palavra[] = "teste";
char crip[512];
int ret;
RSA * pubkey = RSA_new();
BIGNUM * modul = BN_new();
BIGNUM * expon = BN_new();
BN_hex2bn(&modul, (const char *) key);
BN_hex2bn(&expon, "010001");
cout << "N KEY: " << BN_bn2hex(modul) << endl;
cout << "E KEY: " << BN_bn2hex(expon) << endl;
pubkey->n = modul;
pubkey->e = expon;
cout << "N PUB KEY: " << BN_bn2hex(pubkey->n) << endl;
cout << "E PUB KEY: " << BN_bn2hex(pubkey->e) << endl;
if (RSA_public_encrypt(strlen((const char *) palavra), (const unsigned char *) palavra, (unsigned char *) crip, pubkey, RSA_PKCS1_PADDING ))
{
printf("ERRO encrypt\n");
}
else
{
printf("SUC encrypt\n");
}
return 0;
}
You probably want something that looks more like:
RSA *pubkey = RSA_new();
int len = BN_hex2bn(&pubkey->n, (const char *)p);
if (len == 0 || p[len])
fprintf(stderr, "'%s' does not appear to be a valid modulus\n", p);
BN_hex2bn(&pubkey->e, "010001");
edit
Your code works fine, except for the error check. RSA_public_encrypt returns the size of the ciphertext on success, not 0, so to make the code above work, add a <= 0 test to if line:
if (RSA_public_encrypt(....) <= 0)
Here is some C code, that does the trick:
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
// cheating, .. ignoring deprecation warnings
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
unsigned char *base64_decode(const char* base64data, int* len) {
BIO *b64, *bmem;
size_t length = strlen(base64data);
unsigned char *buffer = (unsigned char *)malloc(length);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf((void*)base64data, length);
bmem = BIO_push(b64, bmem);
*len = BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
BIGNUM* bignum_base64_decode(const char* base64bignum) {
BIGNUM* bn = NULL;
int len;
unsigned char* data = base64_decode(base64bignum, &len);
if (len) {
bn = BN_bin2bn(data, len, NULL);
}
free(data);
return bn;
}
EVP_PKEY* RSA_fromBase64(const char* modulus_b64, const char* exp_b64) {
BIGNUM *n = bignum_base64_decode(modulus_b64);
BIGNUM *e = bignum_base64_decode(exp_b64);
if (!n) printf("Invalid encoding for modulus\n");
if (!e) printf("Invalid encoding for public exponent\n");
if (e && n) {
EVP_PKEY* pRsaKey = EVP_PKEY_new();
RSA* rsa = RSA_new();
rsa->e = e;
rsa->n = n;
EVP_PKEY_assign_RSA(pRsaKey, rsa);
return pRsaKey;
} else {
if (n) BN_free(n);
if (e) BN_free(e);
return NULL;
}
}
void assert_syntax(int argc, char** argv) {
if (argc != 4) {
fprintf(stderr, "Description: %s takes a RSA public key modulus and exponent in base64 encoding and produces a public key file in PEM format.\n", argv[0]);
fprintf(stderr, "syntax: %s <modulus_base64> <exp_base64> <output_file>\n", argv[0]);
exit(1);
}
}
int main(int argc, char** argv) {
assert_syntax(argc, argv);
const char* modulus = argv[1];
const char* exp = argv[2];
const char* filename = argv[3];
EVP_PKEY* pkey = RSA_fromBase64(modulus, exp);
if (pkey == NULL) {
fprintf(stderr, "an error occurred :(\n");
return 2;
} else {
printf("success decoded into RSA public key\n");
FILE* file = fopen(filename, "w");
PEM_write_PUBKEY(file, pkey);
fflush(file);
fclose(file);
printf("written to file: %s\n", filename);
}
return 0;
}
See this link for further info: http://www.techper.net/2012/06/01/converting-rsa-public-key-modulus-and-exponent-into-pem-file/

Generate SHA hash in C++ using OpenSSL library

How can I generate SHA1 or SHA2 hashes using the OpenSSL libarary?
I searched google and could not find any function or example code.
From the command line, it's simply:
printf "compute sha1" | openssl sha1
You can invoke the library like this:
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
int main()
{
unsigned char ibuf[] = "compute sha1";
unsigned char obuf[20];
SHA1(ibuf, strlen(ibuf), obuf);
int i;
for (i = 0; i < 20; i++) {
printf("%02x ", obuf[i]);
}
printf("\n");
return 0;
}
OpenSSL has a horrible documentation with no code examples, but here you are:
#include <openssl/sha.h>
bool simpleSHA256(void* input, unsigned long length, unsigned char* md)
{
SHA256_CTX context;
if(!SHA256_Init(&context))
return false;
if(!SHA256_Update(&context, (unsigned char*)input, length))
return false;
if(!SHA256_Final(md, &context))
return false;
return true;
}
Usage:
unsigned char md[SHA256_DIGEST_LENGTH]; // 32 bytes
if(!simpleSHA256(<data buffer>, <data length>, md))
{
// handle error
}
Afterwards, md will contain the binary SHA-256 message digest. Similar code can be used for the other SHA family members, just replace "256" in the code.
If you have larger data, you of course should feed data chunks as they arrive (multiple SHA256_Update calls).
Adaptation of #AndiDog version for big file:
static const int K_READ_BUF_SIZE{ 1024 * 16 };
std::optional<std::string> CalcSha256(std::string filename)
{
// Initialize openssl
SHA256_CTX context;
if(!SHA256_Init(&context))
{
return std::nullopt;
}
// Read file and update calculated SHA
char buf[K_READ_BUF_SIZE];
std::ifstream file(filename, std::ifstream::binary);
while (file.good())
{
file.read(buf, sizeof(buf));
if(!SHA256_Update(&context, buf, file.gcount()))
{
return std::nullopt;
}
}
// Get Final SHA
unsigned char result[SHA256_DIGEST_LENGTH];
if(!SHA256_Final(result, &context))
{
return std::nullopt;
}
// Transform byte-array to string
std::stringstream shastr;
shastr << std::hex << std::setfill('0');
for (const auto &byte: result)
{
shastr << std::setw(2) << (int)byte;
}
return shastr.str();
}
correct syntax at command line should be
echo -n "compute sha1" | openssl sha1
otherwise you'll hash the trailing newline character as well.
Here is OpenSSL example of calculating sha-1 digest using BIO:
#include <openssl/bio.h>
#include <openssl/evp.h>
std::string sha1(const std::string &input)
{
BIO * p_bio_md = nullptr;
BIO * p_bio_mem = nullptr;
try
{
// make chain: p_bio_md <-> p_bio_mem
p_bio_md = BIO_new(BIO_f_md());
if (!p_bio_md) throw std::bad_alloc();
BIO_set_md(p_bio_md, EVP_sha1());
p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length());
if (!p_bio_mem) throw std::bad_alloc();
BIO_push(p_bio_md, p_bio_mem);
// read through p_bio_md
// read sequence: buf <<-- p_bio_md <<-- p_bio_mem
std::vector<char> buf(input.size());
for (;;)
{
auto nread = BIO_read(p_bio_md, buf.data(), buf.size());
if (nread < 0) { throw std::runtime_error("BIO_read failed"); }
if (nread == 0) { break; } // eof
}
// get result
char md_buf[EVP_MAX_MD_SIZE];
auto md_len = BIO_gets(p_bio_md, md_buf, sizeof(md_buf));
if (md_len <= 0) { throw std::runtime_error("BIO_gets failed"); }
std::string result(md_buf, md_len);
// clean
BIO_free_all(p_bio_md);
return result;
}
catch (...)
{
if (p_bio_md) { BIO_free_all(p_bio_md); }
throw;
}
}
Though it's longer than just calling SHA1 function from OpenSSL, but it's more universal and can be reworked for using with file streams (thus processing data of any length).
C version of #Nayfe code, generating SHA1 hash from file:
#include <stdio.h>
#include <openssl/sha.h>
static const int K_READ_BUF_SIZE = { 1024 * 16 };
unsigned char* calculateSHA1(char *filename)
{
if (!filename) {
return NULL;
}
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
return NULL;
}
unsigned char* sha1_digest = malloc(sizeof(char)*SHA_DIGEST_LENGTH);
SHA_CTX context;
if(!SHA1_Init(&context))
return NULL;
unsigned char buf[K_READ_BUF_SIZE];
while (!feof(fp))
{
size_t total_read = fread(buf, 1, sizeof(buf), fp);
if(!SHA1_Update(&context, buf, total_read))
{
return NULL;
}
}
fclose(fp);
if(!SHA1_Final(sha1_digest, &context))
return NULL;
return sha1_digest;
}
It can be used as follows:
unsigned char *sha1digest = calculateSHA1("/tmp/file1");
The res variable contains the sha1 hash.
You can print it on the screen using the following for-loop:
char *sha1hash = (char *)malloc(sizeof(char) * 41);
sha1hash[40] = '\0';
int i;
for (i = 0; i < SHA_DIGEST_LENGTH; i++)
{
sprintf(&sha1hash[i*2], "%02x", sha1digest[i]);
}
printf("SHA1 HASH: %s\n", sha1hash);