3

I have a simplest possible example of sha256 written in C, using the openSSL library.

// compile with: gcc -o sha256 sha256.c -lcrypto

#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    unsigned char buffer[BUFSIZ];
    FILE *f;
    SHA256_CTX ctx;
    size_t len;
    if (argc < 2) {
        fprintf(stderr, "usage: %s <file>\n", argv[0]);
        return 1;
    }

    f = fopen(argv[1], "r");
    if (!f) {
        fprintf(stderr, "couldn't open %s\n", argv[1]);
        return 1;
    }

    SHA256_Init(&ctx);

    do {
        len = fread(buffer, 1, BUFSIZ, f);
        SHA256_Update(&ctx, buffer, len);
    } while (len == BUFSIZ);

    SHA256_Final(buffer, &ctx);

    fclose(f);

    for (len = 0; len < SHA256_DIGEST_LENGTH; ++len)
        printf("%02x", buffer[len]);
    putchar('\n');
    return 0;
}

I need the same for sha1, but I could not find similar simple example that actually works. The naive approach of replacing occurrences of SHA256 in the above code with SHA1 does not work (obviously).

How can I modify my program for SHA1 ?

UPDATE

as suggested by @dbush, I have used his EVP code, and integrated it into my program. My program now looks like this:

#include <stdio.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/err.h>

int main(int argc, char **argv)
{

FILE *f;
size_t len;
unsigned char buffer[BUFSIZ];

if (argc < 2) {
    fprintf(stderr, "usage: %s <file>\n", argv[0]);
    return 1;
}

f = fopen(argv[1], "r");

if (!f) {
    fprintf(stderr, "couldn't open %s\n", argv[1]);
    return 1;
}


EVP_MD_CTX hashctx;
//EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
EVP_MD *hashptr = EVP_get_digestbyname("SHA1");

EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL));

do {
    len = fread(buffer, 1, BUFSIZ, f);
    EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);

EVP_DigestFinal_ex(&hashctx, buffer, &len);
EVP_MD_CTX_cleanup(&hashctx);

fclose(f);

int i;
for (i = 0; i < len; ++i)
    printf("%02x", buffer[i]);

    return 0;
}

When I compile it using gcc -o evp evp.c -lcrypto, I get couple of errors, such as:

evp.c: In function ‘main’:
evp.c:29:19: warning: initialization discards ‘const’ qualifier from pointer target type [enabled by default]
evp.c:32:43: error: expected ‘;’ before ‘)’ token
evp.c:32:43: error: expected statement before ‘)’ token
evp.c:39:1: warning: passing argument 3 of ‘EVP_DigestFinal_ex’ from incompatible pointer type [enabled by default]
In file included from evp.c:4:0:
/usr/include/openssl/evp.h:574:5: note: expected ‘unsigned int *’ but argument is of type ‘size_t *’
2
  • If you are encountering the "warning: initialization discards ‘const’ qualifier..." warnings, then I believe you are using a really old version of OpenSSL. Perhaps OpnSSL 0.9.8 on OS X? You may want to consider updating the library. Commented Dec 12, 2016 at 22:28
  • @jww - I am using libssl-dev version 1.0.1t-1+deb7u1 on Debian. Commented Dec 12, 2016 at 22:35

2 Answers 2

5

Rather than using the SHA1 or SHA256 specific functions, use the EVP_Digest* family of functions which work with any hash.

...

// makes all algorithms available to the EVP* routines
OpenSSL_add_all_algorithms();
// load the error strings for ERR_error_string
ERR_load_crypto_strings();

EVP_MD_CTX hashctx;
//const EVP_MD *hashptr = EVP_get_digestbyname("SHA256");
const EVP_MD *hashptr = EVP_get_digestbyname("SHA1");

EVP_MD_CTX_init(&hashctx);
EVP_DigestInit_ex(&hashctx, hashptr, NULL);

do {
    len = fread(buffer, 1, BUFSIZ, f);
    EVP_DigestUpdate(&hashctx, buffer, len);
} while (len == BUFSIZ);

unsigned int outlen;
EVP_DigestFinal_ex(&hashctx, buffer, &outlen);
EVP_MD_CTX_cleanup(&hashctx);

fclose(f);

int i;
for (i = 0; i < outlen; ++i)
    printf("%02x", buffer[i]);

I've omitted the error checking for brevity. To check for errors, do the following:

if (function_to_check() == 0) {
    char errstr[1000];
    ERR_error_string(ERR_get_error(), errstr);
    printf("error: %s\n", errstr;
}

EDIT:

There were some error in the above code that have been corrected:

  • hashptr was declared EVP_MD *, is now const EVP_MD *.
  • The call to EVP_DigestInit_ex had an extra parenthesis at the end
  • The third parameter to EVP_DigestFinal_ex is specifically given an unsigned int * instead a size_t *, which may not necessarily be the same.
  • Added calls to two OpenSSL initialization functions at the top
Sign up to request clarification or add additional context in comments.

6 Comments

thank you. Could you please add the rest of the missing code, so that I can copy it exactly? At the moment, when paste your code into my program (substituting relevant parts), I get couple of errors. Also, I believe you have a typo here: for (i = 0; len < len; ++i) , it should be i<len.
@MartinVegter You'll need to #include <openssl/evp.h> and #include <openssl/err.h>. Other than that, it should work. If not, update your question (or post a new one) with the relevant code.
@MartinVegter There were a few errors in what I originally posted. I've edited my sample code and confirmed that it runs correctly.
what errors does the error-checking code check for, and in what part of the code should it be integrated ?
@MartinVegter Apply the error checking to the EVP_Digest* functions. Also, check if EVP_get_digestbyname returns NULL.
|
2

You can simply do like this:-

#include <openssl/sha.h>
#include <stdio.h>
int main(int argc, char **argv)
 {
    unsigned char buffer[BUFSIZ];
    FILE *f;
    SHA_CTX ctx;
    size_t len;
    if (argc < 2) {
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            return 1;
    }

    f = fopen(argv[1], "r");
    if (!f) {
            fprintf(stderr, "couldn't open %s\n", argv[1]);
            return 1;
    }

    SHA1_Init(&ctx);

    do {
            len = fread(buffer, 1, BUFSIZ, f);
            SHA1_Update(&ctx, buffer, len);
    } while (len == BUFSIZ);

    SHA1_Final(buffer, &ctx);

    fclose(f);

    for (len = 0; len < SHA_DIGEST_LENGTH; ++len)
            printf("%02x", buffer[len]);
    putchar('\n');
    return 0;
 }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.