I need to authenticate to a websocket endpoint to subscribe to private data, the authentication steps are as follows:
Hash the challenge with the SHA-256 algorithm
Base64-decode your api_secret
Use the result of step 2 to hash the result of step 1 with the HMAC-SHA-512 algorithm
Base64-encode the result of step 3
I am using openssl in my C++ program for all the crypto and I am using some base64 encoding and decoding algorithms I found on stackoverflow, however I am unable to follow the authentication procedure and produce the correct result.
I am confident that the base64 decoder is correct as it produces the correct binary when I decode the secret furthermore the openssl sha256 algorithm is also correct as it produces the correct hash for the challenge, (I used cryptiis online base64 decoder and sha256 to verify this), something must be wrong with the way I am using the openssl HMAC or the base64 encoder for the final step.
#include <openssl/sha.h>
#include <cstdio>
#include <cstring>
void sha256(const char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <cstring>
#include <memory>
#include <string>
#include <vector>
namespace {
struct BIOFreeAll { void operator()(BIO* p) { BIO_free_all(p); } };
}
auto Base64Encode(const std::vector<unsigned char>& binary)
{
std::unique_ptr<BIO,BIOFreeAll> b64(BIO_new(BIO_f_base64()));
BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL);
BIO* sink = BIO_new(BIO_s_mem());
BIO_push(b64.get(), sink);
BIO_write(b64.get(), binary.data(), binary.size());
BIO_flush(b64.get());
const unsigned char* encoded;
const unsigned long len = BIO_get_mem_data(sink, &encoded);
return std::basic_string<unsigned char>{encoded, len};
}
// Assumes no newlines or extra characters in encoded string
std::vector<unsigned char> Base64Decode(const char* encoded)
{
std::unique_ptr<BIO,BIOFreeAll> b64(BIO_new(BIO_f_base64()));
BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL);
BIO* source = BIO_new_mem_buf(encoded, -1); // read-only source
BIO_push(b64.get(), source);
const int maxlen = strlen(encoded) / 4 * 3 + 1;
std::vector<unsigned char> decoded(maxlen);
const int len = BIO_read(b64.get(), decoded.data(), maxlen);
decoded.resize(len);
return decoded;
}
#include <openssl/hmac.h>
int main(int argc, const char * argv[])
{
const char* challenge = "c100b894-1729-464d-ace1-52dbce11db42";
static char buffer[65];
sha256(challenge, buffer);
printf("%s\n", buffer);
const char* encoded = "7zxMEF5p/Z8l2p2U7Ghv6x14Af+Fx+92tPgUdVQ748FOIrEoT9bgT+bTRfXc5pz8na+hL/QdrCVG7bh9KpT0eMTm";
std::cout << "encoded = " << encoded << std::endl;
const std::vector<unsigned char> decoded = Base64Decode(encoded);
std::cout << "decoded = " << decoded.data() << '\n';
// The data that we're going to hash using HMAC
std::basic_string<unsigned char> data = {decoded.data(), decoded.size()};
unsigned char* digest;
// Using sha512 hash engine here.
// You may use other hash engines. e.g EVP_md5(), EVP_sha224, EVP_sha512, etc
digest = HMAC(EVP_sha512(), data.c_str(), data.size(), reinterpret_cast<unsigned char*>(buffer), strlen(buffer), NULL, NULL);
// Be careful of the length of string with the choosen hash engine. SHA1 produces a 20-byte hash value which rendered as 40 characters.
// Change the length accordingly with your choosen hash engine
char mdString[128];
for(int i = 0; i < 64; ++i)
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("HMAC digest: %s\n", mdString);
const std::vector<unsigned char> binary{&digest[0], &digest[127] + 1};
const std::basic_string<unsigned char> encoded_result = Base64Encode(binary);
for (unsigned i = 0; i < 64; ++i)
{
std::cout << std::hex << std::setw(2) << (unsigned int)encoded_result[i];
}
std::cout << '\n';
return 0;
}
The code may not compile first time around as I have pulled the snippets from a larger repository, however if all put into one file it should compile (or require minor effort to successfully compile).
When the value of the initial challenge is
"c100b894-1729-464d-ace1-52dbce11db42"
and the api secret is
"7zxMEF5p/Z8l2p2U7Ghv6x14Af+Fx+92tPgUdVQ748FOIrEoT9bgT+bTRfXc5pz8na+hL/QdrCVG7bh9KpT0eMTm"
The line following HMAC digest should be the signed output, I am expecting it to be
"4JEpF3ix66GA2B+ooK128Ift4XQVtc137N9yeg4Kqsn9PI0Kpzbysl9M1IeCEdjg0zl00wkVqcsnG4bm
nlMb3A=="
whereas it is actually
"336e394b567a55634d46376478344b594354767267636d39456f584f51326c376f334f2f3348796f6939647a7a516a456e41786c3551537541453930422f424b".
What is more troublesome is that I am able to replicate the correct result using python and C# quite simply using the library functions, I am quite unsure as to where I am going wrong here.
You appear to be overly fond of hex encoding your data!
First of all, in your sha256 function you correctly hash the data to get the 32 byte digest, but then you hex encode this to get 64 hex characters (plus the null terminator) which you later use as the input to the HMAC. You need to use those original 32 bytes.
Then later, after you calculate the HMAC and base 64 encode the result, you hex encode that before printing it out. There’s no need to do that, base 64 already consists of printable characters.
Take out those two loops where you do the hex encoding (and change sha256 so you return the correct buffer) and it should work correctly.
Related
I want to calculate Sha1 of any given file in C++ using OpenSSL library.
I have read any article on the internet (including all from stackoverflow too) about doing this for almost 3 days.
Finally I get my program to work but the generated hash of any given file is not as it should be.
My code is someway similar to these found here and here but more easy to read and to use further in my program I write.
Also, I want to use C++ code not C code as they are written in the links above, second, they use:
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char*)input, length);
SHA256_Final(md, &context);
which aren't available anymore in the new/current OpenSSL version (3.0 or so, I think).
So, I think this question will help many other readers that I observe meet the same problem(s) I do with the new OpenSSL version and can not use old code samples anymore.
This is my C++ code that is created to read huge files by chuncks without loading them into memory (hope this will help future readers of this post because it have many useful lines but it is not fully working as you will see):
bool hashFullFile(const std::string& FilePath, std::string &hashed, std::string &hash_type) {
bool success = false;
EVP_MD_CTX *context = EVP_MD_CTX_new();
//read file by chuncks:
const int BUFFER_SIZE = 1024;
std::vector<char> buffer (BUFFER_SIZE + 1, 0);
// check if the file to read from exists and if so read the file in chunks
std::ifstream fin(FilePath, std::ifstream::binary | std::ifstream::in);
if (hash_type == "SHA1") {
if (context != NULL) {
if (EVP_DigestInit_ex(context, EVP_sha1(), NULL)) {
while (fin.good()){
fin.read(buffer.data(), BUFFER_SIZE);
std::streamsize s = ((fin) ? BUFFER_SIZE : fin.gcount());
buffer[s] = 0;
//convert vector of chars to string:
std::string str(buffer.data());
if (!EVP_DigestUpdate(context, str.c_str(), str.length())) {
fprintf(stderr, "Error while digesting file.\n");
return false;
}
}
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int lengthOfHash = 0;
if (EVP_DigestFinal_ex(context, hash, &lengthOfHash)) {
std::stringstream ss;
for (unsigned int i = 0; i < lengthOfHash; ++i) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int) hash[i];
}
hashed = ss.str();
success = true;
}else{
fprintf(stderr, "Error while finalizing digest.\n");
return false;
}
}else{
fprintf(stderr, "Error while initializing digest context.\n");
return false;
}
EVP_MD_CTX_free(context);
}else{
fprintf(stderr, "Error while creating digest context.\n");
return false;
}
}
fin.close();
return success;
}
And I am using it like this into main function:
std::string myhash;
std::string myhash_type = "SHA1";
hashFullFile(R"(C:\Users\UserName\data.bin)", myhash, myhash_type);
cout<<myhash<<endl;
The problem is that for a given file it calculates hash:
e.g. 169ed28c9796a8065f96c98d205f21ddac11b14e as the hash output but the same file has the hash:
openssl dgst -sha1 data.bin
SHA1(data.bin)= 1927f720a858d0c3b53893695879ae2a7897eedb
generated by Openssl command line and also by any site from the internet.
I can't figure out what am I doing wrong since my code seems to be correct.
Please help.
Thank you very much in advance!
You're missing the finishing calculation on your EVP API attempt. The use of an intermediate string is unnecessary as well. Finally, the function should return the digest as a vector of bytes. let the caller do with that what they want.
Examples using both the EVP API and a BIO chain are shown below.
#include <iostream>
#include <fstream>
#include <algorithm>
#include <array>
#include <vector>
#include <memory>
#include <openssl/evp.h>
#include <openssl/sha.h>
namespace
{
struct Delete
{
void operator()(BIO * p) const
{
BIO_free(p);
}
void operator()(EVP_MD_CTX *p) const
{
EVP_MD_CTX_free(p);
}
};
using BIO_ptr = std::unique_ptr<BIO, Delete>;
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, Delete>;
}
std::vector<uint8_t> hashFileEVP(const std::string &fname, std::string const &mdname = "sha1")
{
// will hold the resulting digest
std::vector<uint8_t> md;
// set this to however big you want the chunk size to be
static constexpr size_t BUFFER_SIZE = 1024;
std::array<char, BUFFER_SIZE> buff;
// get the digest algorithm by name
const EVP_MD *mthd = EVP_get_digestbyname(mdname.c_str());
if (mthd)
{
std::ifstream inp(fname, std::ios::in | std::ios::binary);
if (inp.is_open())
{
EVP_MD_CTX_ptr ctx{EVP_MD_CTX_new()};
EVP_DigestInit_ex(ctx.get(), mthd, nullptr);
while (inp.read(buff.data(), BUFFER_SIZE).gcount() > 0)
EVP_DigestUpdate(ctx.get(), buff.data(), inp.gcount());
// size output vector
unsigned int mdlen = EVP_MD_size(mthd);
md.resize(mdlen);
// general final digest
EVP_DigestFinal_ex(ctx.get(), md.data(), &mdlen);
}
}
return md;
}
std::vector<uint8_t> hashFileBIO(std::string const &fname, std::string const &mdname = "sha1")
{
// the fixed-size read buffer
static constexpr size_t BUFFER_SIZE = 1024;
// will hold the resulting digest
std::vector<uint8_t> md;
// select this however you want.
const EVP_MD *mthd = EVP_get_digestbyname(mdname.c_str());
if (mthd)
{
// open the file and a message digest BIO
BIO_ptr bio_f(BIO_new_file(fname.c_str(), "rb"));
BIO_ptr bio_md(BIO_new(BIO_f_md()));
BIO_set_md(bio_md.get(), mthd);
// chain the bios together. note this bio is NOT
// held together with a smart pointer; all the
// bios in the chain are.
BIO *bio = BIO_push(bio_md.get(), bio_f.get());
// read through file one buffer at a time.
std::array<char, BUFFER_SIZE> buff;
while (BIO_read(bio, buff.data(), buff.size()) > 0)
; // intentionally empty
// size output buffer
unsigned int mdlen = EVP_MD_size(mthd);
md.resize(mdlen);
// read final digest from md bio.
BIO_gets(bio_md.get(), (char *)md.data(), mdlen);
}
return md;
}
// convert a vector of byte to std::string
std::string bin2hex(std::vector<uint8_t> const& bin)
{
std::string res;
size_t len = 0;
if (OPENSSL_buf2hexstr_ex(nullptr, 0, &len, bin.data(), bin.size(), 0) != 0)
{
res.resize(len);
OPENSSL_buf2hexstr_ex(&res[0], len, &len, bin.data(), bin.size(), 0);
}
return res;
}
int main()
{
OpenSSL_add_all_digests();
// i have this on my rig. use whatever you want
// or get the name from argv or some such.
static const char fname[] = "dictionary.txt";
auto md1 = hashFileEVP(fname);
auto md1str = bin2hex(md1);
std::cout << "hashed with EVP API\n";
std::cout << md1str << '\n';
auto md2 = hashFileBIO(fname);
auto md2str = bin2hex(md1);
std::cout << "hashed with BIO chain\n";
std::cout << md2str << '\n';
}
Output
hashed with EVP API
0A97D663ADA2E039FD904846ABC5361291BD2D8E
hashed with BIO chain
0A97D663ADA2E039FD904846ABC5361291BD2D8E
Output from openssl command line
craig#rogue1 % openssl dgst -sha1 dictionary.txt
SHA1(dictionary.txt)= 0a97d663ada2e039fd904846abc5361291bd2d8e
Note the digests are the same in all three cases.
EDIT
This question has been half answered through comments. I was successful in getting the encryption with both AES and SHA to work successfully. The problem with SHA was simple - I was hashing in Java with uppercase hex and C++ with lowercase. AES was successful after changing the type from string to unsigned char and using memcpy instead of strcpy.. I'm still interested in understanding why, after encryption, the result contained the original message in plaintext alongside the binary data - regardless of the type that I was using.
I am currently working on a project in C++ that requires encryption. Normally, I would use Java for this task, however, due to software requirements I have chose C++. After creating an Encryption class with the openssl library, I ran a simple test with AES-CBC 256. The test was a Hello World message encrypted by a hex string key and IV followed by the encrypted result being decrypted. The output below shows the results.
After encryption the binary data contains the original string in plain text as well as the hex value present in the encrypted hex string. After decryption the original hex value for the message is shown in the output as if the process worked.
I am also having problems with creating a SHA-512 hash. Creating a hash in Java differs from the one created in C++. Creating a SHA-256 Hmac hash, however, produces the same output in both languages.
Below is the C++ code I am using in the encryption class.
std::string Encryption::AES::cbc256(const char* data, ssize_t len, const char* key, const char* iv, bool encrypt) {
std::string keyStr = key;
std::string ivStr = iv;
std::string dataStr = data;
std::string _keyStr = Encryption::Utils::fromHex(keyStr.c_str(), 64);
std::string _ivStr = Encryption::Utils::fromHex(ivStr.c_str(), 32);
std::string _dataStr = Encryption::Utils::fromHex(dataStr.c_str(), dataStr.size());
size_t inputLength = len;
char aes_input[_dataStr.size()];
char aes_key[32];
memset(aes_input, 0, _dataStr.size());
memset(aes_key, 0, sizeof(aes_key));
strcpy(aes_input, _dataStr.c_str());
strcpy(aes_key, _keyStr.c_str());
char aes_iv[16];
memset(aes_iv, 0x00, AES_BLOCK_SIZE);
strcpy(aes_iv, _ivStr.c_str());
const size_t encLength = ((inputLength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE);
if(encrypt) {
char res[inputLength];
AES_KEY enc_key;
AES_set_encrypt_key((unsigned char*) aes_key, 256, &enc_key);
AES_cbc_encrypt((unsigned char*) aes_input, (unsigned char *) res, inputLength, &enc_key, (unsigned char *) aes_iv, AES_ENCRYPT);
return Encryption::Utils::toHex((unsigned char *) res, strlen(res));
} else {
char res[inputLength];
AES_KEY enc_key;
AES_set_decrypt_key((unsigned char*) aes_key, 256, &enc_key);
AES_cbc_encrypt((unsigned char*) aes_input, (unsigned char *) res, inputLength, &enc_key, (unsigned char *) aes_iv, AES_DECRYPT);
return Encryption::Utils::toHex((unsigned char *) res, strlen(res));
}
}
std::string Encryption::SHA::hash512(const char *source) {
std::string input = source;
unsigned char hash[64];
SHA512_CTX sha512;
SHA512_Init(&sha512);
SHA512_Update(&sha512, input.c_str(), input.size());
SHA512_Final(hash, &sha512);
std::stringstream ss;
for(int i=0; i<sizeof(hash); i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int) hash[i];
}
return ss.str();
}
std::string Encryption::Utils::fromHex(const char* source, ssize_t size) {
int _size = size / 2;
char* dest = new char[_size];
std::string input = source;
int x=0;
int i;
for(i=0;i<_size; i++) {
std::string ret = "";
for(int y=0; y<2; y++) {
ret += input.at(x);
x++;
}
std::stringstream ss;
ss << std::hex << ret;
unsigned int j;
ss >> j;
dest[i] = (char) static_cast<int>(j);
}
return std::string(dest);
}
Can anyone explain to me, or offer their help, as to why I am getting the output I am getting?
I have the working code below using OPENSSL AES 256 CBC to encrypt/decrypt.
It is working but I am missing something really important that is to CONVERT the Encryption result to readable text and STORE it to a STRING variable if possible (for later use).
For example, I need to see something like this: UkV8ecEWh+b1Dz0ZdwMzFVFieCI5Ps3fxYrfqAoPmOY=
Trying hard to find how to do that and what format OPENSSL is throwing out from Encryption process. (binary format ??) See image attached.
ps. Don't worry about the hashes below. They are not in production.
Thanks in Advance!!
Here is my code so far:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
using namespace std;
// HEX PRINT
static void hex_print(const void* pv, size_t len)
{
const unsigned char* p = (const unsigned char*)pv;
if (NULL == pv)
printf("NULL");
else
{
size_t i = 0;
for (; i < len; ++i)
printf("%02X ", *p++);
}
printf("\n");
}
// Starting MAIN function
int main()
{
int keylength = 256;
unsigned char aes_key[] = "1Tb2lYkqstqbh9lPAbeWpQOs3seHk6cX";
// Message we want to encrypt
unsigned char aes_input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 abcdefghijklmnopqrstuvwxyz";
size_t inputslength = sizeof(aes_input)-1; // -1 because we don't want to encrypt the \0 character
// initialization vector IV - same for Encryption and Decryption
unsigned char iv_enc[] = "JxebB512Gl3brfx4" ;
unsigned char iv_dec[] = "JxebB512Gl3brfx4" ;
// buffers for encryption and decryption
const size_t encslength = inputslength ;
unsigned char enc_out[257];
unsigned char dec_out[257];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
//Encryption START
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, keylength, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT);
//Decryption START
AES_set_decrypt_key(aes_key, keylength, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);
// Printing Results
printf("original: \t");
hex_print(aes_input, sizeof(aes_input));
cout << aes_input << endl;
printf("encrypted: \t");
hex_print(enc_out, sizeof(enc_out));
cout << enc_out << endl;
printf("decrypt: \t");
hex_print(dec_out, sizeof(dec_out));
cout << dec_out << endl;
return 0;
}
Image of the Process
All Right. Thanks for the tips #RemyLebeau and #PaulSanders !!
I could resolve the issue using another tip from here -->
Base64 C++
Working REALLY fine now!!
Thanks Much!!
Here is the code for "encode" and "decode" Base64, just in case someone wants to do the same. Very usefull!!
typedef unsigned char uchar;
static const string b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static string base64_encode(const string &in) {
string out;
int val=0, valb=-6;
for (uchar c : in) {
val = (val<<8) + c;
valb += 8;
while (valb>=0) {
out.push_back(b[(val>>valb)&0x3F]);
valb-=6;
}
}
if (valb>-6) out.push_back(b[((val<<8)>>(valb+8))&0x3F]);
while (out.size()%4) out.push_back('=');
return out;
}
static string base64_decode(const string &in) {
string out;
vector<int> T(256,-1);
for (int i=0; i<64; i++) T[b[i]] = i;
int val=0, valb=-8;
for (uchar c : in) {
if (T[c] == -1) break;
val = (val<<6) + T[c];
valb += 6;
if (valb>=0) {
out.push_back(char((val>>valb)&0xFF));
valb-=8;
}
}
return out;
}
I'm using Openssl EVP to encrypt, decrypt a plaintext with aes-gcm-256. I provide an empty string as additional data and randomly generate the IVs every time using RAND_bytes. My IVs are 16 bytes long. The key is static, just like the plaintext. So the only thing which is different on each run is the IV. If I loop this program 10.000 times it works approximately 82% of the time. Is it possible that some values don't work when included in the IV?
Here are some of the IVs not working: (provided in hex format for readability)
868DCDA3B6A47F9461CEFC1CF096E419
942A3E63CB22BFFCF4309B038575D9DF
7DABF472A03FCFD4AA88A17BF17049B5
10E94264C5133011665978290D157FDF
B33323638D679A4CDD17844C5E50A656
D77CA61F54374F8AF76BF625F6065317
A81C1087C2218E29DB5DBBE3DF31CF03
15678C7484E20DD2C4BDB9E67D4FA7AD
3DC18C3AAFE48367905091D6C760A2CA
9940CA7685B92C46F716FE3E3EDD4675
CA2E9EBACD824F06523A7471ABB1A637
691D54DB476FF73C27D19B0BFD7191D2
020FF1C6702BCF5D8715082768B14CC8
F72623956640DDA62047821E3418F1EC
743F1B9A8AF46D8EC2472DD44059E87E
6CC0C96CFEA33DC96B9C8FB27587A6B6
2A73F05FC73AB2BE0D3B78FD65824100
0D44B61773986D5C4E11521121A9D7BF
DEB9896F1EACE3B8F10F980595108578
4AA5B4922564E664C67BC83B58C18A94
AFF764905CAD86EF7ABA582853EAD2F5
FD4C09E91EA36024E8BA8D4D5FA6751E
5F764A3F0217EAA54D242E28C7E45640
5ED5B3C23DF30E178517FAB51F28DE32
34E9B4CF4E2149EBF919F75D9374267A
31D65E7E61D888CF4C244B009B71117C
Of course, there are many more. If someone has a clue I would be very thankful.
int successful = 0;
for (int i = 1; i < 10001; ++i)
{
unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
/* Message to be encrypted */
unsigned char *plaintext = (unsigned char *)"The quick brown fox jumps over the lazy dog";
unsigned char ciphertext[128];
/* Buffer for the decrypted text */
unsigned char decryptedtext[128];
/* Buffer for the tag */
unsigned char tag[16];
int decryptedtext_len, ciphertext_len;
//initialize random number generator (for IVs)
int rv = RAND_load_file("/dev/urandom", 32);
a:
/* A 128 bit IV */
size_t iv_len = 16;
unsigned char iv[iv_len];
RAND_bytes(iv, sizeof(iv));
ciphertext_len = gcm_encrypt(plaintext, key, iv, iv_len, ciphertext, tag);
decryptedtext_len = gcm_decrypt(ciphertext, tag, key, iv, iv_len, decryptedtext);
if (decryptedtext_len >= 0)
{
/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';
++successful;
std::string dec(reinterpret_cast<char *>(iv), iv_len);
//std::cout << (float)successful / i << " " << string_to_hex(dec) << "\n";
}
else
{
//printf("Decryption failed\n");
std::string dec(reinterpret_cast<char *>(iv), iv_len);
std::cout << string_to_hex(dec) << "\n";
goto a;
}
}
std::cout << (float)successful / 10000 << "\n";
The gcm_encrypt and gcm_decrypt functions are similar to the ones used in the documentation. I only changed that the function calculates the lengths itself,
https://wiki.openssl.org/images/0/08/Evp-gcm-encrypt.c
You appear not to be passing the ciphertext length to your decrypt
function, how does it know how much ciphertext there is to decrypt? If
you're just using strlen() or the like, what happens when the
ciphertext contains a 0x00 byte? -- Iridium
This solved my question, thanks.
I am trying to perform a SHA256 hash on the message digest of a RIPEMD 160 hash. I am using the OpenSSL library on the Mac platform.
The issue I am having is the intermediary process of taking the message digest of the RIPEMD 160 and then performing another SHA256 hash on it. So far I have only been able to perform 1) a SHA256 Hash on a string, 2) a RIPEMD160 hash on a string in isolation. I need to perform a RIPEMD160 hash on a previous SHA256 message digest then perform a second SHA256 hash on the RIPEMD 160 digest......
SHA256 digest-> RIPEMD160 hash function-> RIPEMD160 digest -> 2nd SHA256 Hash function. I hope this makes sense....?
Code for SHA256 Hash function on just a String
string sha256(const string str)
{
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
ss << hex << setw(2) << setfill('0') << (int)hash[i];
}
return ss.str();
}
Code for RIPEMD160 Hash on just a String
int main()
{
unsigned char digest[RIPEMD160_DIGEST_LENGTH];
char string[] = "hello world";
RIPEMD160((unsigned char*)&string, strlen(string), (unsigned
char*)&digest);
char mdString[RIPEMD160_DIGEST_LENGTH*2+1];
for(int i = 0; i < RIPEMD160_DIGEST_LENGTH; i++)
sprintf(&mdString[i*2], "%02x", (unsigned int)digest[i]);
printf("RIPEMD160 digest: %s\n", mdString);
return 0;
}
Code for SHA256 Hash function on just a String
SHA256 doesn't operate on strings. SHA256 operates on bytes. Unfortunately, in C, they are frequently the same data type.
Once you leave Caesar and Vigenere behind cryptography doesn't work on strings. This is very important to remember.
Assuming that your input data IS a text string, and it IS currently represented in the expected encoding (US-ASCII / ISO-8859-1 / UTF-8) then, after correcting some bad pointers, your code is fine:
unsigned char digest[RIPEMD160_DIGEST_LENGTH];
...
RIPEMD160((unsigned char*)string, strlen(string), (unsigned char*)digest);
Now digest contains your RIPEMD160 digest. We recall that cryptography only operates on bytes, and that digest is bytes, and we get
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, digest, RIPEMD160_DIGEST_LENGTH);
SHA256_Final(hash, &sha256);
Or the accelerator version, like you did with RIPEMD160:
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(digest, RIPEMD160_DIGEST_LENGTH, hash);