Cryptographic Hashes in Qt (HMAC-SHA1, PBKDF2, Md5)

At times we need to generate cryptographic hashes for encryption purposes. This can be done in Qt using QCryptographicHash or QCA (Qt Cryptographic Architecture). QCA is a cross-platform crypto API, using Qt datatypes and conventions, hence we need to download and build it separately and include it in Qt. On the other hand QCryptographicHash class comes with Qt itself and can be used to generate cryptographic hashes.

Using QCA increases the size of our application as we need to include qca plugins and library in our application bundle to make it deployable (I’ll explain how to build and deploy QCA in my next post). Therefore I prefer to use qt’s inbuilt class QCryptographicHash if requirements can be completed using this.

Even after some research I couldn’t find a way to generate PBKDF2 using QCryptographicHash, therefore I am using QCA to generate PBKDF2 from a string/byte-array.

In this post I’ll explain how to generate HMAC-SHA1 and Md5 hash using QCryptographicHash, and generate PBKDF2 using QCA library.

Here is the code to generate HMAC-SHA1 of public key and a secret base string:

// Returns HMAC-SHA1 encrypted signature composed of public key and secret base string
QString hmacSha1(QByteArray key, QByteArray baseString)
{
    int blockSize = 64; // HMAC-SHA-1 block size, defined in SHA-1 standard
    if (key.length() > blockSize) { // if key is longer than block size (64), reduce key length with SHA-1 compression
        key = QCryptographicHash::hash(key, QCryptographicHash::Sha1);
    }
    QByteArray innerPadding(blockSize, char(0x36)); // initialize inner padding with char "6"
    QByteArray outerPadding(blockSize, char(0x5c)); // initialize outer padding with char "\"
    // ascii characters 0x36 ("6") and 0x5c ("\") are selected because they have large
    // Hamming distance (http://en.wikipedia.org/wiki/Hamming_distance)

    for (int i = 0; i < key.length(); i++) {
        innerPadding[i] = innerPadding[i] ^ key.at(i); // XOR operation between every byte in key and innerpadding, of key length
        outerPadding[i] = outerPadding[i] ^ key.at(i); // XOR operation between every byte in key and outerpadding, of key length
    }

    // result = hash ( outerPadding CONCAT hash ( innerPadding CONCAT baseString ) ).toBase64
    QByteArray total = outerPadding;
    QByteArray part = innerPadding;
    part.append(baseString);
    total.append(QCryptographicHash::hash(part, QCryptographicHash::Sha1));
    QByteArray hashed = QCryptographicHash::hash(total, QCryptographicHash::Sha1);

    QString result = QCA::arrayToHex(hashed);
    return result;
}

Above method will return the HMAC-SHA1 hex as a string. Now, lets see how to generate md5 hash from the content of a file.

QString md5Hash(QString path)
{
    QFile file(path);
    if(!file.exists())
    {
        qDebug()<<"File does not exist to read md5hash";
        return "";
    }
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug()<<"error in reading file: "<<path;
        return "";
    }

    QByteArray fileContent(file.readAll());

    QByteArray fileHash = QCryptographicHash::hash(fileContent, QCryptographicHash::Md5);

    file.close();

    QString result = QString(fileHash.toHex());
   
    qDebug()<<"md5 : "<<result;

    return result;
}

Now, the last we are going to discuss here is PBKDF2. We will need to use QCA for this.
PBKDF2 of a string can be generated by passing the salt value, iterations and length of the key.
Here is the code to generate PBKDF2 from a password string passed in the function :

QString pbkdf2(QString password, QString salt, int length, int iterations)
{
    if(!QCA::isSupported("pbkdf2(sha1)", "qca-ossl"))
    {
       qDebug()<<"PBKDF version 2 with SHA1 not supported  ";
    }
    else
    {
        QCA::InitializationVector esalt(QCA::SecureArray(salt.toUtf8()));
        QCA::SecureArray epassword(password.toUtf8());
        QCA::SymmetricKey passwordOut = QCA::PBKDF2("sha1", "qca-ossl").makeKey (epassword, esalt, length, iterations);
        QString result = QCA::arrayToHex(passwordOut.toByteArray());
        return result;
     }
    return "";
}

Note: When using QCA classes remember to include the header <QtCrypto/QtCrypto>

Written By: Neha Gupta

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s