How to Calculate a Sha-512 Hash in C++ on Linux

How to calculate a SHA-512 hash in C++ on Linux?

Have you checked OpenSSL. I myself have not used it but documentation says it supports it.

Here is list of few more implementations.

Example code

 md = EVP_get_digestbyname("sha512");
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
EVP_DigestUpdate(&mdctx, mess1, strlen(mess1));
EVP_DigestUpdate(&mdctx, mess2, strlen(mess2));
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);

sha512: c program using the openSSL library

Yes, this will work. The man page for the SHA family of functions lists the following:

 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);

...

int SHA512_Init(SHA512_CTX *c);
int SHA512_Update(SHA512_CTX *c, const void *data, size_t len);
int SHA512_Final(unsigned char *md, SHA512_CTX *c);
unsigned char *SHA512(const unsigned char *d, size_t n,
unsigned char *md);

...

SHA1_Init() initializes a SHA_CTX structure.

SHA1_Update() can be called repeatedly with chunks of the message
to be hashed (len bytes at data).

SHA1_Final() places the message digest in md, which must have space
for SHA_DIGEST_LENGTH == 20 bytes of output, and erases the
SHA_CTX.

The SHA224, SHA256, SHA384 and SHA512 families of functions operate
in the same way as for the SHA1 functions. Note that SHA224 and
SHA256 use a SHA256_CTX object instead of SHA_CTX. SHA384 and
SHA512 use SHA512_CTX. The buffer md must have space for the
output from the SHA variant being used (defined by
SHA224_DIGEST_LENGTH, SHA256_DIGEST_LENGTH, SHA384_DIGEST_LENGTH
and SHA512_DIGEST_LENGTH). Also note that, as for the SHA1()
function above, the SHA224(), SHA256(), SHA384() and SHA512()
functions are not thread safe if md is NULL.

To confirm, let's look at some code segments. First with SHA256:

SHA256_CTX ctx;
unsigned char buffer[512];

char *str = "this is a test";
int len = strlen(str);

strcpy(buffer,str);

SHA256_Init(&ctx);
SHA256_Update(&ctx, buffer, len);
SHA256_Final(buffer, &ctx);

fwrite(&buffer,32,1,stdout);

When run as:

./test1 | od -t x1

Outputs:

0000000 2e 99 75 85 48 97 2a 8e 88 22 ad 47 fa 10 17 ff
0000020 72 f0 6f 3f f6 a0 16 85 1f 45 c3 98 73 2b c5 0c
0000040

Which matches the output of:

echo -n "this is a test" | openssl sha256

Which is:

(stdin)= 2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c

Now the same code with the changes you suggested:

SHA512_CTX ctx;
unsigned char buffer[512];

char *str = "this is a test";
int len = strlen(str);

strcpy(buffer,str);

SHA512_Init(&ctx);
SHA512_Update(&ctx, buffer, len);
SHA512_Final(buffer, &ctx);

fwrite(&buffer,64,1,stdout);

The output when passed through "od" gives us:

0000000 7d 0a 84 68 ed 22 04 00 c0 b8 e6 f3 35 ba a7 e0
0000020 70 ce 88 0a 37 e2 ac 59 95 b9 a9 7b 80 90 26 de
0000040 62 6d a6 36 ac 73 65 24 9b b9 74 c7 19 ed f5 43
0000060 b5 2e d2 86 64 6f 43 7d c7 f8 10 cc 20 68 37 5c
0000100

Which matches the output of:

echo -n "this is a test" | openssl sha512 

Which is:

(stdin)= 7d0a8468ed220400c0b8e6f335baa7e070ce880a37e2ac5995b9a97b809026de626da636ac7365249bb974c719edf543b52ed286646f437dc7f810cc2068375c

SHA-512 source code in C

sha512sum is found in the GNU Coreutils package

How can I encrypt SHA512 hash with salt in C and ubuntu?

What you are trying to generate is not an ordinary SHA-512 hash. It's a hashed password using a special-purpose algorithm based on SHA-512. openssl passwd computes this algorithm, but the OpenSSL library's SHA512 function computes ordinary SHA-512. This special-purpose algorithm, and several others with the same function, are documented in the crypt(5) manpage.

You can probably use the crypt_r function, from the libcrypt library (this library is inaccurately named for historical reasons; it only provides password-hashing algorithms), to compute hashed passwords using the same special-purpose algorithm as openssl passwd does. On my computer, this program prints the same string starting with $6$abcd that you got:

#include <crypt.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
struct crypt_data cd;
memset(&cd, 0, sizeof cd);
puts(crypt_r("appple", "$6$abcd", &cd));
return 0;
}

Notice how the second argument (referred to as a "setting string" in the documentation I've been linking to) contains both the salt value abcd and the prefix $6$ (which tells crypt_r to use the SHA-512-based hash). It works this way so that login(1) can call crypt_r with the password it just read from the tty as the first argument, and the password entry from the shadow file as the second argument, and if it gets back the same string it put as the second argument then the user has successfully authenticated.

Compile and run like so:

$ gcc -std=gnu11 -O test.c -lcrypt
$ test $(./a.out) = '$6$abcd$vIWAp1OzuGuo376cRkZ5DXcgI8KIlnUibsk.iydtfCFqb9okOz.S70Ysu7.qRRg9Me5XwAyTjkZBQJXiIxwpL/'; echo $?
0

I say probably because the set of special-purpose hashing algorithms supported by this library varies from Unix to Unix. If (and only if) you can put the string $6$abcd$... in some account's password entry in /etc/shadow and then successfully log in as that account using the password appple, then it should work.

libcrypt may also have a function called crypt_gensalt_rn which you can use to generate setting strings and select an appropriate hashing algorithm. Here's a demo of that function:

#include <crypt.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
char setting[CRYPT_GENSALT_OUTPUT_SIZE];
crypt_gensalt_rn(0, 0, 0, 0, setting, CRYPT_GENSALT_OUTPUT_SIZE);

struct crypt_data cd;
memset(&cd, 0, sizeof cd);
puts(crypt_r("appple", setting, &cd));
return 0;
}

If you compile and run this program it will not print the string starting with $6$abcd; it will print something else, such as

$y$j9T$0aVoGQ/PFN0PHbcYlKZdZ1$05NbMJLbRliM7fmtSAeZoy3OoRsBqETpAZXQpnPey82

and what it prints will change every time you run it, but each of the strings it outputs will be usable as an /etc/shadow entry allowing someone to log in with password appple. You can control its behavior with the first four arguments that I left at 0.

(Disclosure: I am one of the authors of lib(x)crypt.)

opessl sha-512 string charset

What is the possible range of characters SHA-512 can produce?

All 256 possible byte values, like with every other relevant hashing function. However, because the output is effectively random, binary data, hash values are almost always encoded to represent them as plain (ASCII) text. base16 (hex) and base64 are popular. Each encoding has its own alphabet.

$6$qJV2Hr9qSOw4/Zxx$pVe4wDNy1mDRIAcPrIWEr0dCzpZQDS2Zb83Ix2pktuCd5jEwvQjO8EiDMFtlAQ/TfYXucKO8qWf9NtLQPbdgi1

The above is an example of SHA-512 hashed string using 'openssl'

No, not really. It's a password hash in crypt format. The selected mode is based on SHA-512, but the output encodes much more information than just a SHA-512 hash value. To the best of my knowledge there is no formal specification of the crypt format.

Assuming that no parameter pairs are included (which openssl doesn't output as far as I know), the alphabet is that of base64 plus '$' and '.' which serve as separators.

To fully support all possible values in Modular Crypt Format, including those with key-value parameters (as in $md5,rounds=5000$GUBv0xjJ$$mSwgIswdjlTY0YxV7HBVm0) you should probably expect all printable ASCII characters, but at least '=' in addition to those mentioned above.

How to calculate sha 512 hash properly in .NET 6

    public string CreateSHA512(string strData)
{
var message = Encoding.UTF8.GetBytes(strData);
using (var alg = SHA512.Create())
{
string hex = "";

var hashValue = alg.ComputeHash(message);
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
}

Extract SHA-512 hash from /etc/shadow

You are comparing two different formats of two different algorithms.

  • The /etc/shadow hash is SHA512crypt in a customized base64 encoding.

  • The hash you calculated is a SHA-512 hash in hex notation.

They look visually different because they are formatted differently, and since the hashing algorithms are different, they can not be compared even if you use the same format for both.

sha512 hashed result in C is different with other languages (php, python)

You're not comparing apples to apples, and in the process also not computing your digest correctly for your C code. The byte stream emitted from a sha512 digest is not a C-string, and putting a zero-char on the end doesn't magically make it one. For example, the first digest looks like this (in hex):

ba 32 53 87 6a ed 6b c2 2d 4a 6f f5 3d 84 06 c6 
ad 86 41 95 ed 14 4a b5 c8 76 21 b6 c2 33 b5 48
ba ea e6 95 6d f3 46 ec 8c 17 f5 ea 10 f3 5e e3
cb c5 14 79 7e d7 dd d3 14 54 64 e2 a0 ba b4 13

The second digest is:

73 14 8c 26 3f fc 49 86 34 cc 1e be bd 67 51 69 
97 01 11 69 a3 7e 28 11 ed 51 d5 2c 82 d4 d5 72
af 32 c2 31 13 9f 1d 0f d7 af e2 9e 44 1d 44 ae
fa 29 c1 85 5e c6 52 07 63 92 72 11 0d 19 56 74

and the third, this:

a5 b2 65 20 84 63 58 8b 56 c1 08 4c 37 03 c4 a1 
a9 0c 71 05 89 cb 09 fc 22 07 85 8f 64 3b b1 72
8b 3e f3 f3 06 2c 84 72 f8 3a c6 1f f9 47 87 b8
b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7

Do you see it? Look at the last set of octets. Last row, second byte.

b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7 
^^

Since your digest source length is erroneously based on a C string length, that is where it is cut off. The remaining bytes are ignored and your digest chain is forever-more wrong.

Apart from that, your code leaks memory like a sieve leaks rainwater. Probably not a big deal for 640 bytes and 10 iterations, but move this to a million iterations and it starts adding up. Put it in a mission-critical piece of software and it is entirely unacceptable. Consider this:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>

void hash_sha512(unsigned char const *src, size_t len, unsigned char *dst)
{
SHA512_CTX ctx;
SHA512_Init(&ctx);
SHA512_Update(&ctx, src, len);
SHA512_Final(dst, &ctx);
}

int main(void)
{
char pwd[] = "123456"
unsigned char digest[2][SHA512_DIGEST_LENGTH] = {{0}};
hash_sha512((unsigned char*)pwd, strlen(pwd), digest[0]);

unsigned int count=1;
for (; count<10; ++count)
{
hash_sha512(digest[(count-1)%2], SHA512_DIGEST_LENGTH, digest[count%2]);
}

return 0;
}

This fixes the problem described earlier, and the final digest will be in digest[(count-1)%2].I leave it to you to integrate your file IO. Below is the first 10 iterations using an initial password of "123456" for your reference. I suggest you use hexdump to make sure things are going according to plan.

Ten Iterations

ba 32 53 87 6a ed 6b c2 2d 4a 6f f5 3d 84 06 c6 
ad 86 41 95 ed 14 4a b5 c8 76 21 b6 c2 33 b5 48
ba ea e6 95 6d f3 46 ec 8c 17 f5 ea 10 f3 5e e3
cb c5 14 79 7e d7 dd d3 14 54 64 e2 a0 ba b4 13

73 14 8c 26 3f fc 49 86 34 cc 1e be bd 67 51 69
97 01 11 69 a3 7e 28 11 ed 51 d5 2c 82 d4 d5 72
af 32 c2 31 13 9f 1d 0f d7 af e2 9e 44 1d 44 ae
fa 29 c1 85 5e c6 52 07 63 92 72 11 0d 19 56 74

a5 b2 65 20 84 63 58 8b 56 c1 08 4c 37 03 c4 a1
a9 0c 71 05 89 cb 09 fc 22 07 85 8f 64 3b b1 72
8b 3e f3 f3 06 2c 84 72 f8 3a c6 1f f9 47 87 b8
b8 00 3d 73 0b 29 a3 7b 88 a9 e3 14 ee 19 06 f7

75 15 b6 cb ef 3e 0b 4a 35 e3 58 b9 8b bb a3 2d
a0 bd 1e c8 9d 32 23 7c 09 ae c0 a7 f7 4e 70 35
c8 34 dd 2a ac 8d e4 e9 d1 e8 b5 7a 80 d8 80 db
07 7c 28 18 e8 30 40 aa 06 85 a5 2a 63 41 c6 b7

4d 25 d3 24 5e 22 b1 e4 e4 3f 1e a4 4e a3 eb e4
89 ab e3 c2 63 56 01 17 ea 1f 85 58 d4 da d2 63
6d 9c 2f 74 39 b6 87 85 2c 1c 27 f8 a8 9d 2a cf
ee 64 1c d9 28 5d 88 e5 c7 8b 9f 6e 1e c8 dd 99

17 e2 7f 2f fd a7 c3 b7 41 73 b9 2d e7 61 6e 77
72 79 41 16 14 90 01 db 6f 66 3b e6 12 94 22 06
a9 91 14 55 ab 7f 3a 34 eb 12 b3 a9 78 69 6a 23
8e 82 13 46 1e ed b4 33 e8 74 f8 15 15 a3 19 57

c1 60 9e c9 c4 82 4f 1c 71 a7 e2 7c 6e fc d9 5b
63 4f 27 25 ec fe d2 58 d6 77 61 8f 93 a1 a4 1e
f0 b7 8a 24 36 91 40 9b 5f dd c3 b5 b9 e1 c6 97
24 66 89 b0 79 c2 84 05 8e 4f 43 4b 5a bb 53 e6

7b f9 4c 45 be 2f 29 68 80 36 79 b7 1a 79 36 a3
7e 8b 9f 6e a0 80 3a 9e 5c bc 27 39 bd 2e 6e 9f
5a b2 8c b9 7f 43 9f b2 c4 72 41 99 f7 65 71 26
b7 b8 06 24 a8 34 ea 69 e4 05 ab 55 a7 a8 32 c2

1a 28 09 ee c5 a4 e5 86 98 0f 52 a1 fd ff a6 14
0f 3f 8b 14 85 34 bd a6 bd 45 54 2e 4c 2b da 62
d0 7c 98 38 5c 98 cd 76 df 18 ca 36 16 f2 be 8e
6c ed 76 e8 28 39 e6 38 d7 41 a4 9e 31 6d f0 ab

ce 0c 0f 2e 89 e5 1d c3 58 88 a3 1f a6 7c 18 74
1a 20 d3 84 43 9c 3a e8 4b d9 f1 fe 2e a1 67 0b
62 62 2d dc 02 eb 82 cd 90 b2 0f 8f e2 fe f5 43
7a ad 0c b1 62 d7 e9 45 3f be 14 53 2e b6 d0 68


Related Topics



Leave a reply



Submit