0

Can anyone help me to access azure storage using Qt/c++ ?

Here's my code.

    QString date = "Tue, 18 Mar 2014 21:49:13 GMT";
    QString datastring = "GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:"+date+"\nx-ms-version:2009-09-19\n/mystorage/\ncomp:list";
    QByteArray ba = datastring.toUtf8();

    unsigned char* signature = reinterpret_cast<unsigned char*>(ba.data());
    QByteArray kba = QByteArray::fromBase64("<accountkey>");
    unsigned char* key = (unsigned char*) kba.data();
    unsigned char result[EVP_MAX_MD_SIZE];
    unsigned int result_len;
    ENGINE_load_builtin_engines();
    ENGINE_register_all_complete();

    HMAC_CTX ctx;
    HMAC_CTX_init(&ctx);
    HMAC_Init_ex(&ctx, key, strlen((const char*)key), EVP_sha256(), NULL);
    HMAC_Update(&ctx, signature, strlen((const char*)signature));
    HMAC_Final(&ctx, result, &result_len);
    HMAC_CTX_cleanup(&ctx);


    QByteArray array = QByteArray::fromRawData((char*)result, result_len);
    array = array.toBase64();
    qDebug() << "signature hash" << array;

    QString version = "2009-09-19";

    //requesting the list of container to Windows Azure
    QNetworkAccessManager* manager = new QNetworkAccessManager();
    QNetworkRequest request;
    request.setUrl(QUrl("http://myaccount.blob.core.windows.net/?comp=list"));
    request.setRawHeader("Authorization","SharedKey myaccount:"+array);
    request.setRawHeader("x-ms-date", date.toStdString().c_str());
    request.setRawHeader("x-ms-version", version.toStdString().c_str());
    manager->get(request);

The request returns the following error

    <?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
    RequestId:6f7a9bf3-81f2-4191-84b8-c1cd1747411f
    Time:2014-03-18T05:03:12.2134625Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'T4vqb/a9SkDnWLvHXyhIEBREHWpBMfhuuMFQwxtRXMs=' is not the same as any computed signature. Server used following string to sign: 'GET

x-ms-date:Tue, 18 Mar 2014 21:49:13 GMT
x-ms-version:2009-09-19
/mystorage/
comp:list'.</AuthenticationErrorDetail></Error>" 

I don't know the exact error in the code. How can i fix this.

I got the source from here

Community
  • 1
  • 1
James Seva
  • 139
  • 1
  • 2
  • 7

1 Answers1

1

You can use this minimalistic Qt class to access Azure Storage (download/upload/list blobs): https://github.com/QuentinCG/QAzureStorageRestApi

This class doesn't have any dependencies except Qt.

Here is a copy paste of the function used to generate the shared key you are struggling with:

QString QAzureStorageRestApi::generateAutorizationHeader(const QString& httpVerb, const QString& container,
                                                     const QString& blobName, const QString& currentDateTime,
                                                     const long& contentLength, const QStringList additionnalCanonicalHeaders,
                                                     const QStringList additionnalCanonicalRessources)
{
  // Create canonicalized header
  QString canonicalizedHeaders;
  for (const QString& additionnalCanonicalHeader : additionnalCanonicalHeaders)
  {
    canonicalizedHeaders.append(additionnalCanonicalHeader+"\n");
  }
  canonicalizedHeaders.append(QString("x-ms-date:%1\nx-ms-version:%2").arg(currentDateTime, m_version));

  // Create canonicalized ressource
  QString canonicalizedResource;
  if (blobName.isEmpty())
  {
    canonicalizedResource = QString("/%1/%2").arg(m_accountName, container);
  }
  else
  {
    canonicalizedResource = QString("/%1/%2/%3").arg(m_accountName, container, blobName);
  }

  for (const QString& additionnalCanonicalRessource : additionnalCanonicalRessources)
  {
    canonicalizedResource.append("\n"+additionnalCanonicalRessource);
  }

  // Create signature
  QString signature = generateHeader(httpVerb, "", "", QString::number(contentLength), "", "", "", "",
                                 "", "", "", "", canonicalizedHeaders, canonicalizedResource);

  // Create authorization header
  QByteArray authorizationHeader = QMessageAuthenticationCode::hash(
    QByteArray(signature.toUtf8()),
    QByteArray(QByteArray::fromBase64(m_accountKey.toStdString().c_str())),
    QCryptographicHash::Sha256);
  authorizationHeader = authorizationHeader.toBase64();

  return QString("SharedKey %1:%2").arg(m_accountName, QString(authorizationHeader));
}

(Note: This class is based on http://ericzwliu.blogspot.de/2015/02/qt-azure-blob-storage.html)

Quentin CG
  • 748
  • 5
  • 6
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/19022659) – amod Mar 06 '18 at 16:40
  • 1
    Sorry, I'm new to Stackoverflow (as writer). I added the source code that answers the base question of the author + gave a link to the full source code to have a fully operational azure communication with Qt app. – Quentin CG Mar 14 '18 at 10:37