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

Popular posts from this blog

Spring Boot + JPA + Hibernate: Unable to locate persister -

go - Golang: panic: runtime error: invalid memory address or nil pointer dereference using bufio.Scanner -

c - double free or corruption (fasttop) -