Search code examples
copensslsha1apple-silicon

Using OpenSSL's SHA1 with Apple Silicon in C


I am building a git clone and working on the hash-file command. I am currently trying to compute the SHA1 hash of a known string and have this code and the following issue:

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

int hashFile(char *file_name, int ww) {
    int i, ret;
    size_t size_len;
    unsigned long file_size;
    char path[56];
    unsigned char hash[SHA_DIGEST_LENGTH];
    char *token, *type, *blob_content, *content;

    FILE *src = fopen(file_name, "r");
    if (ferror(src)) {
        perror("Unable to read file");
        return 1;
    }
    fseek(src, 0L, SEEK_END);
    file_size = ftell(src);
    rewind(src);
    size_len = snprintf(NULL, 0, "%lu", file_size);

    char *buffer = (char *)malloc((size_t)file_size + 1);
    fread(buffer, sizeof(char), file_size, src);
    buffer[file_size] = '\0';

    blob_content = (char *)malloc((7 + sizeof(unsigned long) + file_size + 1) *
                                  sizeof(char));
    snprintf(blob_content, 7 + size_len + 1, "blob %lu\\0", file_size);
    strcat(blob_content, buffer);

    SHA1((unsigned char *)blob_content, strlen(blob_content), hash);
    printf("%s\n", hash);

    free(blob_content);
    free(buffer);

    return 0;
}

void printHashHelp() {
    printf("usage: twat hash-file [options] <file_name>\n");
    printf("\n");
    printf("options:\n");
    printf("\t-w: write contents to objects store\n");
}
$ clang --std=c17 -fmodules -fprebuilt-module-path=. -I/opt/homebrew/opt/openssl/include cmd.c comp.c init.c cat.c hash.c -o twat -v
...
Undefined symbols for architecture arm64:
  "_SHA1", referenced from:
      _hashFile in hash-fc3ff3.o
ld: symbol(s) not found for architecture arm64

How should I go about linking and enabling SHA1 to work on the M2 Max? What clang command should I be using if this is incorrect?

I have been trying different methods of linking openssl/sha.h and believed to have got it but have not got the function to work currently.

Following: How to use SHA1 hashing in C programming I attempted to use the linked library but got a compiler linking failure.


Solution

  • Append

    -L/opt/homebrew/lib -lcrypto
    

    to your command line.

    Also, your malloc and snprintf looks weird. The whole +1 and +7 looks error prone

    This would be better:

    char header[100] = {0};  // 100 is big enough for the entire "blob 12345" thing regardless of how big the file is
    
    SHA1_CTX ctx = {0};
    SHA1_Init(&ctx);
    sprintf(header, "blob %lu", file_size);
    SHA1_Update(&ctx, header, strlen(header));
    SHA1_Update(&ctx, buffer, file_size);
    SHA1_Final(hash, &ctx);
    

    And then if you really want to be pedantic, make sure you open the file as binary on non-Unix:

    #ifdef _WIN32
        char* flags = "rb";
    #else
        char* flags = "r";
    #endif
    
    FILE *src = fopen(file_name, flags);