X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fdigest.c;fp=src%2Flib%2Fdigest.c;h=132f27e33b2f7c9aa0db3f7541f893b5d6b921fc;hb=e4169f77f892fefc66a97439d295d3e09ef3e2f0;hp=0000000000000000000000000000000000000000;hpb=4fb2a47294e74ba2fea809ad06d2378982270329;p=deb_shairplay.git diff --git a/src/lib/digest.c b/src/lib/digest.c new file mode 100644 index 0000000..132f27e --- /dev/null +++ b/src/lib/digest.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include + +#include "compat.h" +#include "utils.h" +#include "crypto/crypto.h" + +void +digest_md5_to_hex(const unsigned char *md5buf, char *md5hex) +{ + int i; + for (i=0; i>4; + md5hex[i] = (val<10) ? '0'+val : 'a'+(val-10); + } +} + +void +digest_get_response(const char *username, const char *realm, + const char *password, const char *nonce, + const char *method, const char *uri, + char *response) +{ + MD5_CTX md5ctx; + unsigned char md5buf[MD5_SIZE]; + char md5hex[MD5_SIZE*2]; + + /* Calculate first inner MD5 hash */ + MD5_Init(&md5ctx); + MD5_Update(&md5ctx, (const unsigned char *)username, strlen(username)); + MD5_Update(&md5ctx, (const unsigned char *)":", 1); + MD5_Update(&md5ctx, (const unsigned char *)realm, strlen(realm)); + MD5_Update(&md5ctx, (const unsigned char *)":", 1); + MD5_Update(&md5ctx, (const unsigned char *)password, strlen(password)); + MD5_Final(md5buf, &md5ctx); + digest_md5_to_hex(md5buf, md5hex); + + /* Calculate second inner MD5 hash */ + MD5_Init(&md5ctx); + MD5_Update(&md5ctx, (const unsigned char *)method, strlen(method)); + MD5_Update(&md5ctx, (const unsigned char *)":", 1); + MD5_Update(&md5ctx, (const unsigned char *)uri, strlen(uri)); + MD5_Final(md5buf, &md5ctx); + + /* Calculate outer MD5 hash */ + MD5_Init(&md5ctx); + MD5_Update(&md5ctx, (const unsigned char *)md5hex, sizeof(md5hex)); + MD5_Update(&md5ctx, (const unsigned char *)":", 1); + MD5_Update(&md5ctx, (const unsigned char *)nonce, strlen(nonce)); + MD5_Update(&md5ctx, (const unsigned char *)":", 1); + digest_md5_to_hex(md5buf, md5hex); + MD5_Update(&md5ctx, (const unsigned char *)md5hex, sizeof(md5hex)); + MD5_Final(md5buf, &md5ctx); + + /* Store the final result to response */ + digest_md5_to_hex(md5buf, response); +} + +void +digest_generate_nonce(char *result, int resultlen) +{ + MD5_CTX md5ctx; + unsigned char md5buf[MD5_SIZE]; + char md5hex[MD5_SIZE*2]; + unsigned int time; + + SYSTEM_GET_TIME(time); + + MD5_Init(&md5ctx); + MD5_Update(&md5ctx, (unsigned char *)&time, sizeof(time)); + MD5_Final(md5buf, &md5ctx); + digest_md5_to_hex(md5buf, md5hex); + + strncpy(result, md5hex, resultlen-1); + result[resultlen-1] = '\0'; +} + +int +digest_is_valid(const char *our_realm, const char *password, + const char *our_nonce, const char *method, + const char *authorization) +{ + char *auth; + char *current; + char *value; + int success; + + /* Get values from authorization */ + char *username = NULL; + char *realm = NULL; + char *nonce = NULL; + char *uri = NULL; + char *response = NULL; + + /* Buffer for our response */ + char our_response[MD5_SIZE*2+1]; + + if (!authorization) { + return 0; + } + current = auth = strdup(authorization); + if (!auth) { + return 0; + } + + /* Check that the type is digest */ + if (strncmp("Digest", current, 6)) { + free(auth); + return 0; + } + current += 6; + + while ((value = utils_strsep(¤t, ",")) != NULL) { + char *first, *last; + + /* Find first and last characters */ + first = value; + last = value+strlen(value)-1; + + /* Trim spaces from the value */ + while (*first == ' ' && first < last) first++; + while (*last == ' ' && last > first) last--; + + /* Validate the last character */ + if (*last != '"') continue; + else *last = '\0'; + + /* Store value if it is relevant */ + if (!strncmp("username=\"", first, 10)) + username = first+10; + if (!strncmp("realm=\"", first, 7)) + realm = first+7; + if (!strncmp("nonce=\"", first, 7)) + nonce = first+7; + if (!strncmp("uri=\"", first, 5)) + uri = first+5; + if (!strncmp("response=\"", first, 10)) + response = first+10; + } + + /* Calculate our response */ + memset(our_response, 0, sizeof(our_response)); + digest_get_response(username, realm, password, nonce, + method, uri, our_response); + success = !strcmp(response, our_response); + free(auth); + + return success; +} + +