Overview

Table of contents
  1. NIST
  2. PBKDF2 Implementation
  3. API
    1. PQC_pbkdf_2
  4. Example

PBKDF2, which stands for Password-Based Key Derivation Function 2, is a cryptographic algorithm designed to transform a password into a cryptographic key. It is widely used in applications that require secure password hashing and key generation, such as password storage, encryption key derivation, and digital signing.

NIST

https://csrc.nist.gov/News/2023/proposal-to-revise-nist-sp-800-132-pbkdf

PBKDF2 (Password-Based Key Derivation Function 2) is recognized and standardized by the National Institute of Standards and Technology (NIST). NIST provides guidelines and recommendations on the use of PBKDF2 for secure password storage and key derivation. The relevant standards and publications include: Recommendation for Password-Based Key Derivation, Authentication and Lifecycle Management, Salt and Key Length, Iteration Count, Hash Function.

PBKDF2 Implementation

Initial Hashing: The password and salt are concatenated and hashed using a pseudorandom function (usually HMAC-SHA-1, HMAC-SHA-256, or another HMAC-based hash function).

Iteration Process: The resulting hash is repeatedly fed back into the hash function along with the original password and salt for the specified number of iterations.

Final Output: The final output after all iterations is the derived key, which can be used for cryptographic purposes such as encryption or as a secure password hash for storage.

PBKDF2 is standardized in RFC 8018 and widely implemented in many cryptographic libraries and frameworks. It is a recommended practice for password hashing due to its resistance to various attack vectors and its configurability in terms of security parameters.

API

PQC_pbkdf_2

Include pqc/pbkdf2.h

The PQC_pbkdf_2 function is used for securely deriving cryptographic keys from passwords.

Function signature:

size_t PQC_API PQC_pbkdf_2(
    int mode, size_t hash_length, size_t password_length, const uint8_t * password, size_t key_length,
    uint8_t * master_key, size_t master_key_length, uint8_t * salt, size_t salt_length, size_t iterations
)

Parameters:

  • mode: Additional mode specifier which should always be set to PQC_PBKDF2_HMAC_SHA3 as per the requirement.
  • hash_length: The length of the hash.
  • password_length: The length of the password.
  • password: Password used to encrypt the file for security.
  • key_length: The length of the key buffer.
  • master_key: Buffer for storing the derived key.
  • master_key_length: Define the length of the master key to be derived.
  • salt: Salt value used in file encryption. It’s recommended to use a constant specific to the application for enhanced security.
  • salt_length: The length of the salt.
  • iterations: Number of iterations, positive integer value.

Return values:

  • PQC_OK: This return value indicates that the operation was executed successfully. The output will be a generated key of the length you have specified.

  • PQC_IO_ERROR: This return value suggests that an unexpected error occurred during the deletion process.

Example

Code

#include "pqc/kdf.h"
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>


/*
In this example, we will derive a key using the PBKDF2 (Password-Based Key Derivation Function 2) with HMAC-SHA3.
We will convert the password and salt into a derived key and print it in hexadecimal format.
*/


/*
Converts a hexadecimal string to a vector of bytes.
This function is used to convert the hexadecimal representation of the salt
into a byte array that can be used with the PBKDF2 function.
 */
std::vector<uint8_t> hex_to_bytes(const std::string & hex)
{
    std::vector<uint8_t> bytes;
    bytes.reserve(hex.size() / 2);
    for (size_t i = 0; i < hex.size(); i += 2)
    {
        std::istringstream iss(hex.substr(i, 2));
        int val;
        iss >> std::hex >> val;
        bytes.push_back(static_cast<uint8_t>(val));
    }
    return bytes;
}

int main()
{
    // Define the password in plain text
    const uint8_t password[] = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
    // Calculate the length of the password
    const size_t password_length = sizeof(password) / sizeof(password[0]);
    // Define the length of the master key to be derived
    const size_t master_key_length = 32 * 8; // 32 bytes * 8 bits per byte
    // Prepare a buffer to store the derived key
    uint8_t master_key[master_key_length / 8] = {0}; // Actual byte array

    std::string salt_hex = "a5dcea8d0bba2f1fcfa5824085bf06e65fa1255484dafd499984323672b71fee";
    std::vector<uint8_t> salt = hex_to_bytes(salt_hex);
    const size_t salt_length = salt.size();
    // Set the hash length and number of iterations for PBKDF2
    size_t hash_length = 256;
    size_t iterations = 10000;
    // Call the PBKDF2 function to derive the key
    size_t result = PQC_pbkdf_2(
        PQC_PBKDF2_HMAC_SHA3, hash_length, password_length, password, master_key_length, master_key, sizeof(master_key),
        salt.data(), salt_length, iterations
    );
    // Check if the key derivation was successful
    if (result == PQC_OK)
    {
        std::cout << "Derived key in hex: ";
        for (size_t i = 0; i < sizeof(master_key); i++)
        {
            std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(master_key[i]);
        }
        std::cout << std::endl;
    }
    else
    {
        std::cout << "Error occurred during key derivation: " << result << std::endl;
    }

    return 0;
}

© Copyright 2024, Terra Quantum AG.