How can I use openssl/md5 in C++ to hash a string? - c

I need to hash with md5 algorithm a string in my program.
There is the lib openssl but I'm a newbie about it.
How is possible hash a string using that and where I can find a good doc that teach me how to use this lib, also with other function like aes?
I've tried this code:
int main()
{
unsigned char result[MD5_DIGEST_LENGTH];
const unsigned char* str;
str = (unsigned char*)"hello";
unsigned int long_size = 100;
MD5(str,long_size,result);
}
But the compiler told me:
undefined reference to MD5.
Why is there and undefined reference to MD5?

You should take a look at the documentation. An option is to use this function:
#include <openssl/md5.h>
unsigned char *MD5(const unsigned char *d,
unsigned long n,
unsigned char *md);
To which they state:
MD2(), MD4(), and MD5() compute the MD2, MD4, and MD5 message digest of the n bytes at d and place it in md (which must have space for MD2_DIGEST_LENGTH == MD4_DIGEST_LENGTH == MD5_DIGEST_LENGTH == 16 bytes of output). If md is NULL, the digest is placed in a static array.
As for AES, if you also want to use OpenSSL, then take a look at EVP doc and this example of how to use it. Just note that you have to add
#define AES_BLOCK_SIZE 16
In the top of the file for it to work, though.
Btw. I can really recommend the Crypto++ library since it's great and has all kinds of cryptographic primitives; AES, Elliptic Curves, MAC, public-key crypto and so on.

The MD5 function is now deprecated, so if you want to avoid all those nasty warnings in your code...
Here's a simple example of how to use md5 with OpenSSL 3.0 and above with C++:
#include <openssl/evp.h>
#include <cstdio>
using namespace std;
string md5(const string& content)
{
EVP_MD_CTX* context = EVP_MD_CTX_new();
const EVP_MD* md = EVP_md5();
unsigned char md_value[EVP_MAX_MD_SIZE];
unsigned int md_len;
string output;
EVP_DigestInit_ex2(context, md, NULL);
EVP_DigestUpdate(context, content.c_str(), content.length());
EVP_DigestFinal_ex(context, md_value, &md_len);
EVP_MD_CTX_free(context);
output.resize(md_len * 2);
for (unsigned int i = 0 ; i < md_len ; ++i)
std::sprintf(&output[i * 2], "%02x", md_value[i]);
return output;
}
According to: https://www.openssl.org/docs/man3.0/man3/EVP_DigestInit_ex.html

Related

Getting warnings with SHA512 OpenSSL with unsigned char

I am playing with openssl in C and getting some warnings I like to get rid of and am unsure how to tackle it as the examples I had found seem to do what I am emulating.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/sha.h>
int main(int argc, char** argv)
{
int i;
unsigned char resSHA512[SHA512_DIGEST_LENGTH];
unsigned char unhashed[1024];
printf("Input string to hash: ");
fgets(unhashed, sizeof(unhashed), stdin);
unhashed[strcspn(unhashed, "\n")] = 0;
SHA512(unhashed, strlen(unhashed), resSHA512);
printf("\nSHA512: ");
for ( i = 0; i < SHA512_DIGEST_LENGTH; i++ )
{
printf("%02x", resSHA512[i]);
}
printf("\n");
return 0;
}
I also got an alert that SHA512 has been deprecated by open when I compile on my Mac using openssl I got through it's git repository. I get no warnings in Linux unless I used the -Wall flag with gcc.
Any help is greatly appreciated, as I am trying to learn new things!
Thank you
What you're reading in to unhashed is a string, so you should declare it as an array of char. That will address the warning with the string-related functions.
That leaves you with a warning when calling SHA512 which expects an unsigned char for its first argument. In this case you can safely cast the argument to unsigned char *.
The warning you see on Mac is because the entire OpenSSL library was marked deprecated on that OS in favor of its own crypto library.

Convert size_t to integer

I'm working with moderately sized integers which are of a size so that their logarithm would be an int. I'm using the GNU Multiprecision library (GMP) with the C programming language.
I wonder whether there exists a function that would convert the data type size_t into an int.
Source: src
size_t is implementation dependent yeah, and it's size may vary. You can try to typecast it to int but that may not be able to store as you already mentioned indirectly.
But still you can work with strings
#include <iostream>
#include <string>
using namespace std;
int main()
{
size_t x = 123456789012345678LL;
std::cout<<(x)<<" "<<int(x)<<" "<<to_string(x);
And then use:
mpz_init(n);
mpz_set_ui(n,0);
flag = mpz_set_str(n,x, 10);
assert (flag == 0);
printf ("n = ");
mpz_out_str(stdout,10,n);
printf ("\n");
}
(Never read about GMP before this question, but the approach should be correct. Hope it helps :-)

Is there a standard way to generate a salt for crypt syscall?

I need to implement account management for my application, and I would rather not use chpasswd subprocess, or otherwise let the plaintext password out my my application's memory space.
I want to use putspent with a password hash I generate with crypt, but I can't find any standard function to randomize a salt for crypt. An online search only found weird hashing function implementations I'd rather not copy into my code. Is there a standard function that would generate a salt for me?
Otherwise, would it be wise to just re-use the current salt stored in my shadow file? I couldn't think of why it WOULD be a security hazard (it will not weaken my shadow file against a rainbow table attack), it just feels wrong because in systems security a rule of thumb is to always randomize everything... (Users are added with system utilities)
It depends on your libc version. In newer Versions there is crypt_gensalt which should be what you need. Use the *_rn versions to be thread-safe.
Example:
#include <crypt.h>
#include <stddef.h>
#include <stdio.h>
int main() {
char result[CRYPT_GENSALT_OUTPUT_SIZE];
const char* salt = crypt_gensalt_rn("$6$", 0, NULL, 0, result, sizeof(result));
if(salt == NULL)
return -1;
printf("salt: %s\n", salt);
struct crypt_data state_data = {0};
const char* hash = crypt_rn("password", salt, &state_data, sizeof(state_data));
printf("hash: %s\n", hash);
}
OpenSSL provides functions for sha512:
https://www.openssl.org/docs/man1.0.2/crypto/SHA512.html
int SHA256_Init(SHA256_CTX *c);
int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA256_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA256(const unsigned char *d, size_t n,
unsigned char *md);
For generating a salt for crypt(), you need 2 random bytes.
For this, you can use openssl:
#include <openssl/rand.h>
int RAND_bytes(unsigned char *buf, int num);
int RAND_pseudo_bytes(unsigned char *buf, int num);
Ref: https://www.openssl.org/docs/man1.0.2/crypto/RAND_bytes.html
Example:
unsigned char salt[2];
RAND_pseudo_bytes(salt, 2);
char *ptr = crypt(password, salt);

Returning wrong MD5 hash in C

I am trying to generate MD5 hash for an string "Hello World" using the original/untouched md5.h and md5c.c from http://www.arp.harvard.edu. But my result differs from all md5 online tools i have tested. Whats wrong this this code? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "md5.h"
void MD5hash(unsigned char *data, unsigned int dataLen, unsigned char *digest) {
MD5_CTX c;
MD5Init(&c);
MD5Update(&c, data, dataLen);
MD5Final(digest, &c);
}
int main(int argc, const char * argv[]) {
unsigned char digest[16];
const char *s = "Hello World";
unsigned int l = (unsigned int)strlen(s);
MD5hash((unsigned char *)s, l, digest);
for(int i = 0; i < 16; ++i)
printf("%02x", digest[i]);
return 0;
}
// My result: f2877a72c40494318c4b050bb436c582
// But online tools output: b10a8db164e0754105b7a99be72e3fe5
As #vipw mentioned there is an issue with padding. This MD5 implementation does not correctly manage padding for message sizes that are not a multiple of a MD5 block size (512-bit / 64 bytes).
To fix it on your side, replace:
const char *s = "Hello World";
by
const char s[64] = "Hello World";
EDIT:
There was a second issue related to portability in this MD5 implementation. In md5.h there is this type alias:
typedef unsigned long int UINT4;
On a Linux x86_64 system (which you are using), this must be changed to this:
typedef unsigned int UINT4;
You have an issue with padding. The MD5 Hash algorithm works on 512-bit blocks. When your final block is less than 512 bits, it needs to be padded. In your example, the first block is also the last block because it's less than 512 bits.
The padding is format is called Merkle–Damgård construction.
You can find some pseudo code that includes padding here.

Microchip C18 - Weird code behavior (maybe extended-mode / non-extended-mode related)

I have this weird problem with the Microchip C18 compiler for PIC18F67J60.
I have created a very simple function that should return the index of a Sub-String in a larger String.
I don't know whats wrong, but the behavior seems to be related to wether extended mode is enabled or not.
With Extended-Mode enabled in MPLAB.X I get:
The memcmppgm2ram function returns zero all the time.
With Extended-Mode disabled in MPLAB.X I get:
The value of iterator variable i counts as: 0, 1, 3, 7, 15, 21
I'm thinking some stack issue or something, because this is really weird.
The complete code is shown below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char bigString[] = "this is a big string";
unsigned char findSubStr(char *str, const rom char *subStr, unsigned char n, unsigned char m)
{
unsigned char i;
for (i=0; i < n-m; i++)
{
if(0 == memcmppgm2ram(&str[i], (const far rom void*)subStr, m))
return i;
}
return n; // not found
}
void main(void)
{
char n;
n = findSubStr(bigString, (const rom void*)"big", sizeof(bigString), 3);
}
memcmppgm2ram() expects a pointer to data memory (ram) as its first argument. You are passing a pointer to a string literal, which is located in program memory (rom).
You can use memcmppgm() instead, or copy the other string to ram using memcpypgm2ram() or strcpypgm2ram().
Unfortunately I can't test this, as I don't have access to this compiler at the moment.

Resources