Overview
Table of contents
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;
}