c - Problems with creating HMAC signature -
i need work azure blob storage in programs written on c. didn't found c library work it, decide write own code using azure blob storage rest api, curl , openssl libraries.
i found bash script making simple request azure storage work , start rewriting c.
for have problems creating hmac signature request. i'm newbie in cryptography , after searching found this.
well, here code make simple request list of blobs in storage:
#include <errno.h> #include <string.h> #include <unistd.h> #include <time.h> #include <stdlib.h> #include <stdio.h> #include <limits.h> #include <openssl/evp.h> #include <curl/curl.h> #include <stdint.h> #include <assert.h> #include "crypto.h" #define verb_get "get" #define verb_post "post" #define verb_put "put" #define azure_api_version "2011-08-18" #define azure_key_type "sharedkey" #define request_header_x_ms_version "x-ms-version: "azure_api_version #define request_header_x_ms_date_f "x-ms-date: %s" #define request_header_authorization_f "authorization: "azure_key_type \ " %s:%s" static const char *account_name = "<account_name>"; static const char *container_name = "<container_name>"; static const char *account_key = "<account_key>"; // @ least 30 symbols result must allocated static void get_time_now_gmt(char *result) { #define gmt_time_format_string "%s, %02d %s %d %02d:%02d:%02d gmt" static const char *nameofday[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; static const char *nameofmonth[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; time_t t = time(null); struct tm tm = *gmtime(&t); // return thu, 07 jul 2016 11:07:53 gmt sprintf(result, gmt_time_format_string, nameofday[tm.tm_wday], // day of week name tm.tm_mday, // day nameofmonth[tm.tm_mon], // month name tm.tm_year + 1900, // year tm.tm_hour, // hour tm.tm_min, // minute tm.tm_sec); // second } struct memorystruct { char *memory; size_t size; }; static size_t curl_callback(void *contents, size_t size, size_t nmemb, void* userp) { size_t realsize = size * nmemb; struct memorystruct *mem = (struct memorystruct *) userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); if (!mem->memory) { /* out of memory! */ printf("not enough memory (realloc returned null)\n"); return 0; } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } void make_curl_req(const char *h1, const char *h2, const char *h3) { curl *curl_handle; curlcode res; char url[256]; struct memorystruct chunk; struct curl_slist *headers = null; chunk.memory = malloc(1); /* grown needed realloc above */ chunk.size = 0; /* no data @ point */ curl_global_init(curl_global_all); /* init curl session */ curl_handle = curl_easy_init(); sprintf(url, "https://%s.blob.core.windows.net/%s?restype=container&comp=list", account_name, container_name); headers = curl_slist_append(headers, "accept:"); headers = curl_slist_append(headers, h1); headers = curl_slist_append(headers, h2); headers = curl_slist_append(headers, h3); curl_easy_setopt(curl_handle, curlopt_httpheader, headers); /* specify url */ curl_easy_setopt(curl_handle, curlopt_url, url); /* send data function */ curl_easy_setopt(curl_handle, curlopt_writefunction, curl_callback); /* pass our 'chunk' struct callback function */ curl_easy_setopt(curl_handle, curlopt_writedata, (void *) &chunk); /* it! */ res = curl_easy_perform(curl_handle); /* check errors */ if (res != curle_ok) { fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); } else { /* * now, our chunk.memory points memory block chunk.size * bytes big , contains remote file. * * nice it! */ printf("%s\n", chunk.memory); } /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); free(chunk.memory); /* we're done libcurl, clean */ curl_global_cleanup(); } void print_it(const char* label, const unsigned char* buff, size_t len) { if(!buff || !len) return; if(label) printf("%s: ", label); for(size_t i=0; < len; ++i) printf("%02x", buff[i]); printf("\n"); } int main(int argc, char **argv) { char request_date[31]; char x_ms_date[45]; char canonicalized_headers[45 + sizeof(request_header_x_ms_version)]; char canonicalized_resources[strlen(account_name) + strlen(container_name) + 5]; char string_to_sign[1024]; unsigned char *decoded_hex_key; size_t decoded_hex_key_len; unsigned char *signature = null; size_t signature_len; unsigned char *signature_based; unsigned char auth_header[256]; openssl_add_all_algorithms(); get_time_now_gmt(request_date); sprintf(x_ms_date, request_header_x_ms_date_f, request_date); sprintf(canonicalized_headers, "%s\\n%s", x_ms_date, request_header_x_ms_version); sprintf(canonicalized_resources, "/%s/%s", account_name, container_name); sprintf(string_to_sign, "%s\n\n\n\n\n\n\n\n\n\n\n\n%s\n%s\ncomp:list\nrestype:container", verb_get, canonicalized_headers, canonicalized_resources); printf("string sign: %s\n", string_to_sign); base64_decode(account_key, &decoded_hex_key, &decoded_hex_key_len); print_it("decoded hex key: ", decoded_hex_key, decoded_hex_key_len); hmac_sha256(decoded_hex_key, decoded_hex_key_len, &signature, &signature_len, decoded_hex_key, decoded_hex_key_len); free(decoded_hex_key); base64_encode(signature, signature_len, &signature_based); free(signature); sprintf(auth_header, request_header_authorization_f, account_name, signature_based); printf("signature: %s\n", signature_based); free(signature_based); // make_curl_req(x_ms_date, request_header_x_ms_version, auth_header); return (exit_success); }
well, result of request incorrect digest. try print digest generates bash script , code found , different.
could please me how solve problem, because have no ideas.
p.s. created hmac digests different if put constant date request_date
in code , request_date
in bash script.
thanks in advance.
updated:
ok, well, recive next azure:
<?xml version="1.0" encoding="utf-8"?><error><code>authenticationfailed</code><message>server failed authenticate request. make sure value of authorization header formed correctly including signature. requestid:71251945-0001-0020-1167-f16d5e000000 time:2016-08-08t11:25:38.6226737z</message><authenticationerrordetail>the mac signature found in http request 'i4/lu2rk8sbj02kfokzzkz95qruroedv8vwxneo0uua=' not same computed signature. server used following string sign: 'get x-ms-date:mon, 08 aug 2016 11:25:39 gmt x-ms-version:2011-08-18 /<account_name>/<container_name> comp:list restype:container'.</authenticationerrordetail></error>
the signature generates code i4/lu2rk8sbj02kfokzzkz95qruroedv8vwxneo0uua=
, bash script fz/kd4oqh7/agqbgybs0hsgijm7jdcwqagxkflbkyri=
same values of request_date
.
the value of string_to_sign next:
00000000 47 45 54 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 78 |get............x| 00000010 2d 6d 73 2d 64 61 74 65 3a 4d 6f 6e 2c 20 30 38 |-ms-date:mon, 08| 00000020 20 41 75 67 20 32 30 31 36 20 31 30 3a 34 31 3a | aug 2016 10:41:| 00000030 32 32 20 47 4d 54 0a 78 2d 6d 73 2d 76 65 72 73 |22 gmt.x-ms-vers| 00000040 69 6f 6e 3a 32 30 31 31 2d 30 38 2d 31 38 0a 2f |ion:2011-08-18./| 00000050 3c 73 74 6f 72 61 67 65 5f 61 63 63 6f 75 6e 74 |<storage_account| 00000060 3e 2f 3c 63 6f 6e 74 61 69 6e 65 72 5f 6e 61 6d |>/<container_nam| 00000070 65 3e 0a 63 6f 6d 70 3a 6c 69 73 74 0a 72 65 73 |e>.comp:list.res| 00000080 74 79 70 65 3a 63 6f 6e 74 61 69 6e 65 72 |type:container| 0000008e
i think, problem in passing decoded_hex_key
passing hmac_sha256
. maybe have transorm before passing?
i've resolve problem. looks use incorrect signature creation method, or used incorrect (that more probable).
so, found next method, belive helpfull someone.
static int hmac_sha25_digest(const u_char *msg, size_t mlen, const u_char *key, size_t key_len, u_char **res, unsigned int *rlen) { *res = malloc((sha256_digest_length + 1) * sizeof(u_char)); memset(*res, 0, (sha256_digest_length + 1) * sizeof(u_char)); hmac_ctx ctx; hmac_ctx_init(&ctx); hmac_init_ex(&ctx, key, key_len, evp_sha256(), null); hmac_update(&ctx, msg, mlen); hmac_final(&ctx, *res, rlen); hmac_ctx_cleanup(&ctx); return 0; }
easy peasy , serve needs.
Comments
Post a Comment