Guk
Guk

Reputation: 71

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

I'm trying to encrypt hash with salt.

In command line, I found right hash written in the shadow file using below command.

openssl passwd -6 -salt abcd appple $6$abcd$vIWAp1OzuGuo376cRkZ5DXcgI8KIlnUibsk.iydtfCFqb9okOz.S70Ysu7.qRRg9Me5XwAyTjkZBQJXiIxwpL/

And I tried to get it in C using openssl(How to convert a raw 64-byte binary to Hex or ASCII in C).

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

int main() {
        char data[] = "abcdapple";
        unsigned char hash[SHA512_DIGEST_LENGTH*2+1];
        SHA512((unsigned char *)&data, strlen(data), (unsigned char *)&hash);

        char buffer[SHA512_DIGEST_LENGTH*2+1];
        for(int i =0; i < SHA512_DIGEST_LENGTH; ++i)
                sprintf(&buffer[i*2],"%02x", (unsigned int)hash[i]);
        printf("digest: %s\n", buffer);
        printf("\n");
}

but generated hash is ea1d5a8b11297d20f954a3ab15092d21b733484b2eb9b7226b2b138639f0df30627774945458a774eb279cd83d2e977a2bc5599606d6a9a3b2f075f9b1895ecd, which is different from right thing.

I think I didn't use salt well. Also there seems to be a fundamental problem. Can't I implement encrypt program with salt using C?

Upvotes: 1

Views: 2731

Answers (2)

zwol
zwol

Reputation: 140445

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

Upvotes: 3

AKX
AKX

Reputation: 168824

You can find the source for the openssl passwd command (and in particular the core do_passwd function) over at GitHub: https://github.com/openssl/openssl/blob/8ea761bf40e6578ecd95ec47772ef86a2e4d4607/apps/passwd.c#L795-L874

The (very non-trivial, 290-line) SHA-512 passwd hash computation function is found a little above that, at https://github.com/openssl/openssl/blob/8ea761bf40e6578ecd95ec47772ef86a2e4d4607/apps/passwd.c#L509-L793

You're probably better off just calling openssl passwd from your app as a subprocess.

Upvotes: 1

Related Questions