简体   繁体   中英

compare unsigned char array in C

This is the output of my program:

Username: paolo
Password: paolo
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
254835d73cc88095a30fc74133beabe9d8463b2954493227b205ea326c8a9c86
No user or password inside the database;

And this is my program:

int main(void){

    int isok = -1;
    char *user = NULL, *pass = NULL;

    printf("Username: ");
    if(scanf("%m[^\n]%*c", &user) == EOF){
        perror("scanf user");
        return EXIT_FAILURE;
    }

    printf("Password: ");
    if(scanf("%m[^\n]%*c", &pass) == EOF){
        perror("scanf");
        free(user);
        return EXIT_FAILURE;
    }

    isok = check_login(user, pass);
    if(isok == 0){
        /* some code here */
    }
    else{
        /* some code here */
    }
    return EXIT_SUCCESS;
}

int check_login(char *u, char *p){

    int retval = -1;
    FILE *fp = NULL;
    char *tmp, *tmp2, *line = NULL;

    /* some code here */

    while(fgets(line, 255, fp) != NULL){
        tmp = strtok(line, " ");
        if(tmp == NULL){
            perror("strtok 1");
            free(u);
            free(p);
            free(line);
            free(fp);
            return -1;
        }

        tmp2 = strtok(NULL, "\n"); 
        if(tmp2 == NULL){
            perror("strtok 2");
            free(u);
            free(p);
            free(line);
            free(fp);
            return -1;
        }
        retval = hash_pwd(p, (unsigned char *)tmp2);
        if((strcmp(tmp,u) == 0) && (retval == 0)){
            free(line);
            free(fp);
            return 0;
        }
        else{
            continue;
        }
    }
    return -1;
}


int hash_pwd(char *to_hash, unsigned char *tocheck){
    SHA256_CTX context;
    unsigned char md[SHA256_DIGEST_LENGTH];
    size_t length = strlen((const char*)to_hash);
    int i;
    SHA256_Init(&context);
    SHA256_Update(&context, (unsigned char*)to_hash, length);
    SHA256_Final(md, &context);
    for(i=0; i<SHA256_DIGEST_LENGTH; i++){
        printf("%02x", md[i]);
    }
    printf("\n%s\n", tocheck);
    for(i=0; i<SHA256_DIGEST_LENGTH; i++){
        if(md[i] == tocheck[i]) continue;
        else return 1;
    }
    return 0;
}

Why my comparision inside the function hash-pwd doesn't work?
What am i doing wrong?

The reason it is not working is that one is a pointer to an ascii string that contains a hex value; and the other is an array of binary value (which you are printing as hex).

....
// print out the digest - a binary array of SHA256_DIGEST_LENGTH
// bytes printed in hex
for(i=0; i<SHA256_DIGEST_LENGTH; i++){
    printf("%02x", md[i]);
}

// A string of SHA256_DIGEST_LENGTH *2 + 1 length - containing
// the value in hex spelled out in ascii.
printf("\n%s\n", tocheck);

So you need to convert either to the other. And then compare.

How do you know that the hash comparison is failing? It could just as well be the strcmp() call:

if((strcmp(tmp,u) == 0) && (retval == 0)){

For instance, are you sure tmp doesn't contain a newline that is missing in u ?

Also, not sure if you're handling the hash loading properly, if you have a long string of hex characters in the file, that will need to be converted to binary before being compared. The hash computed by SHA256 is binary, not hex string.

There are two (in my opinion) reasonable ways of fixing this:

  1. Convert the hash read from the file to binary, before comparing
  2. Convert the hash computed at runtime to text, before comparing

You can see that the two solutions are each other's complement, which seems natural to me. I would not encourage the solution you mentioned in a comment, involving temporary files.

Of the above, the second one is probably the easiest to implement, since it's easier to convert a bunch of bytes into hex than doing the reverse. It's the solution I would go with, something like:

static int hash_to_string(char *output, size_t output_max,
                           const unsigned char *hash, size_t hash_size)
{
  size_t i;

  if(output_max < 2 * hash_size + 1)
    return 0;
  for(i = 0; i < hash_size; ++i)
    sprintf(output + 2 * i, "%02x", hash[i] & 0xff);
  output[2 * i] = '\0';
  return 1;
}

call the above with a pointer to a buffer large enough to hold the string version, then compare that against the one loaded from the file.

UPDATE : Or, you can use the existing API and just call SHA256_End() to get the hash in hex.

As a general observation, don't do this:

for(i=0; i<SHA256_DIGEST_LENGTH; i++){
    if(md[i] == tocheck[i]) continue;
    else return 1;
}
return 0;

instead, do this:

return memcmp(md, tocheck, sizeof md) != 0;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM