I try to create an application for use the AWS API. For this, i programme in c++ with the library CURL. I test my application with "GET" request and it's work. After, i test with the "PUT" request but, i have an error :
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>NotImplemented</Code>
<Message>A header you provided implies functionality that is not implemented</Message>
<Header>Transfer-Encoding</Header>
<RequestId> *** </RequestId>
<HostId> ***</HostId>
</Error>
my code :
#include <stdio.h>
#include <curl/curl.h>
#include <iostream>
#include "sha256_calc.h"
#include <ctime>
#include <hmac_sha256/hmac_sha256.h>
#include <vector>
using std::string;
using std::cout;
using std::endl;
#define BUCKET_NAME "<my bucket>"
#define REGION "eu-west-3"
#define METHODE_PUT "PUT"
#define SERVICE_S3 "s3"
#define ALGORITHM "AWS4-HMAC-SHA256"
#define ACCESS_KEY "<My access Key>"
#define SECRET_KEY "<My secret access Key>"
#define SHA256_HASH_SIZE 32
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
string vector_to_string (std::vector<uint8_t> val)
{
string retour = "";
char res[2048];
char intermedaire[2];
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
//sprintf(intermedaire,"%x",val[i]);
retour += val[i];
}
return retour;
}
std::vector<uint8_t> sign(string key,string msg)
{
std::vector<uint8_t> out(SHA256_HASH_SIZE);
hmac_sha256(key.data(), key.size(), msg.data(), msg.size(),out.data(), out.size());
return out;
}
std::vector<uint8_t> getSignatureKey(string key,string dateStamp,string regionName,string
serviceName)
{
printf("key : %s \n" , key.c_str());
std::vector<uint8_t> kDate = sign("AWS4" + key, dateStamp);
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",kDate[i]);
}
printf("\n");
string buff = vector_to_string (kDate);
std::vector<uint8_t> kRegion = sign(buff, regionName);
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",kRegion[i]);
}
printf("\n");
buff = vector_to_string (kRegion);
std::vector<uint8_t> kService = sign(buff, serviceName);
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",kService[i]);
}
printf("\n");
buff = vector_to_string (kService);
std::vector<uint8_t> kSigning = sign(buff, "aws4_request");
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",kSigning[i]);
}
printf("\n");
return kSigning;
}
int main(void)
{
CURL *curl;
CURLcode res;
curl_slist *chunk=NULL;
char *file = (char*)"fichier/CR1-12_11.pdf";
char end_point[2048];
char host[1024];
sprintf(host,"%s.s3.%s.amazonaws.com",BUCKET_NAME,REGION);
sprintf(end_point,"https://%s/fichier/CR1-12_11.pdf",host);
time_t now = time(0);
tm *gmtm = gmtime(&now);
char amzdate[32];
char datestamp[32];
sprintf(amzdate,"%04d%02d%02dT%02d%02d%02dZ",gmtm->tm_year+1900,gmtm->tm_mon+1,gmtm-
>tm_mday,gmtm->tm_hour,gmtm->tm_min,gmtm->tm_sec);
//sprintf(amzdate,"%04d%02d%02dT%02d%02d%02dZ",1900+gmtm->tm_year,gmtm->tm_mon+1,gmtm-
>tm_mday,8,45,25);
sprintf(datestamp,"%04d%02d%02d",1900+gmtm->tm_year,gmtm->tm_mon+1,gmtm->tm_mday);
cout << gmtm->tm_hour << endl;
string canonical_uri;
canonical_uri = (string)"/" + file;
string test = "";
string payload_hash = sha256(test);
string canonical_headers;
canonical_headers = (string)"host:" + host + "\nx-amz-content-sha256:" + payload_hash +
"\nx-amz-date:" + amzdate + "\n";
string signed_header = "host;x-amz-content-sha256;x-amz-date";
string canonicale_request;
canonicale_request = (string) METHODE_PUT + "\n" + canonical_uri + "\n\n" +
canonical_headers + "\n" + signed_header + "\n" + payload_hash;
printf ("%s\n",canonicale_request.c_str());
string credential_scope;
credential_scope = (string) datestamp + "/" + REGION + "/" + SERVICE_S3 + "/aws4_request";
string string_to_sign;
string_to_sign = (string) ALGORITHM + "\n" + amzdate + "\n" + credential_scope + "\n" +
sha256(canonicale_request);
char *pCACertFile = (char*)"<file>";
std::vector<uint8_t> signing_key ;
signing_key = getSignatureKey(SECRET_KEY,datestamp,REGION,SERVICE_S3);
string buff = vector_to_string(signing_key);
std::vector<uint8_t> signature(SHA256_HASH_SIZE);
string string_to_sign_buff = string_to_sign;
hmac_sha256(buff.data(), buff.size(), string_to_sign_buff.data(),
string_to_sign_buff.size(),signature.data(), signature.size());
printf("\n");
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",signing_key[i]);
}
printf("\n");
printf("\n %s \n",string_to_sign_buff.c_str());
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
printf("%d\n",signature[i]);
}
FILE *fileOpen = fopen("<file>","rb");
FILE *fileOpenWrite = fopen("<file>","wb");
if (fileOpen)
{
printf("fichier ok \n");
}
else
{
printf("erreur\n");
}
FILE *f = fopen(pCACertFile,"r");
if (f)
{
fclose(f);
}
else
{
printf("certificat abscent");
}
string buffUser="";
curl=curl_easy_init();
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_URL, end_point);
curl_easy_setopt(curl, CURLOPT_PUT, 1);
buff = credential_scope;
buff = ACCESS_KEY + string("/") + buff;
printf("%s\n",buff.c_str());
string test_val = "";
char tampon[8];
for (int i = 0; i < SHA256_HASH_SIZE; i++)
{
sprintf(tampon,"%02x",signature[i]);
test_val += tampon;
}
buffUser = (string) "Authorization:"+ ALGORITHM +" Credential="+ ACCESS_KEY + "/" +
credential_scope + ",SignedHeaders=" + signed_header + ",Signature=" + test_val;
chunk = curl_slist_append(chunk,buffUser.c_str());
buffUser = "x-amz-content-sha256:" + payload_hash;
chunk = curl_slist_append(chunk,buffUser.c_str());
buff = amzdate;
buffUser = "x-amz-date:" + buff;
chunk = curl_slist_append(chunk,buffUser.c_str());
buffUser = "x-amz-decoded-content-length: 1024";
chunk = curl_slist_append(chunk,buffUser.c_str());
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,chunk);
curl_easy_setopt(curl,CURLOPT_READDATA,fileOpen);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
// }
fclose (fileOpen);
printf("Fin programme \n");
return 0;
}
The signature fonction, i can verify this with an other programme and, the GET methode use this.