mirror of
https://github.com/ratspeak/ratdeck.git
synced 2026-05-14 11:25:05 +00:00
210 lines
6.5 KiB
C++
210 lines
6.5 KiB
C++
/*
|
|
* Copyright (C) 2022 Southern Storm Software, Pty Ltd.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "HKDF.h"
|
|
#include <string.h>
|
|
|
|
/**
|
|
* \class HKDFCommon HKDF.h <HKDF.h>
|
|
* \brief Concrete base class to assist with implementing HKDF mode for
|
|
* hash algorithms.
|
|
*
|
|
* Reference: https://datatracker.ietf.org/doc/html/rfc5869
|
|
*
|
|
* \sa HKDF
|
|
*/
|
|
|
|
/**
|
|
* \brief Constructs a new HKDF instance.
|
|
*
|
|
* This constructor must be followed by a call to setHashAlgorithm().
|
|
*/
|
|
HKDFCommon::HKDFCommon()
|
|
: hash(0)
|
|
, buf(0)
|
|
, counter(1)
|
|
, posn(255)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* \brief Destroys this HKDF instance.
|
|
*/
|
|
HKDFCommon::~HKDFCommon()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* \brief Sets the key and salt for a HKDF session.
|
|
*
|
|
* \param key Points to the key.
|
|
* \param keyLen Length of the \a key in bytes.
|
|
* \param salt Points to the salt.
|
|
* \param saltLen Length of the \a salt in bytes.
|
|
*/
|
|
void HKDFCommon::setKey(const void *key, size_t keyLen, const void *salt, size_t saltLen)
|
|
{
|
|
// Initialise the HKDF context with the key and salt to generate the PRK.
|
|
size_t hashSize = hash->hashSize();
|
|
if (salt && saltLen) {
|
|
hash->resetHMAC(salt, saltLen);
|
|
hash->update(key, keyLen);
|
|
hash->finalizeHMAC(salt, saltLen, buf + hashSize, hashSize);
|
|
} else {
|
|
// If no salt is provided, RFC 5869 says that a string of
|
|
// hashSize zeroes should be used instead.
|
|
memset(buf, 0, hashSize);
|
|
hash->resetHMAC(buf, hashSize);
|
|
hash->update(key, keyLen);
|
|
hash->finalizeHMAC(buf, hashSize, buf + hashSize, hashSize);
|
|
}
|
|
counter = 1;
|
|
posn = hashSize;
|
|
}
|
|
|
|
/**
|
|
* \brief Extracts data from a HKDF session.
|
|
*
|
|
* \param out Points to the buffer to fill with extracted data.
|
|
* \param outLen Number of bytes to extract into the \a out buffer.
|
|
* \param info Points to the application-specific information string.
|
|
* \param infoLen Length of the \a info string in bytes.
|
|
*
|
|
* \note RFC 5869 specifies that a maximum of 255 * HashLen bytes
|
|
* should be extracted from a HKDF session. This maximum is not
|
|
* enforced by this function.
|
|
*/
|
|
void HKDFCommon::extract(void *out, size_t outLen, const void *info, size_t infoLen)
|
|
{
|
|
size_t hashSize = hash->hashSize();
|
|
uint8_t *outPtr = (uint8_t *)out;
|
|
while (outLen > 0) {
|
|
// Generate a new output block if necessary.
|
|
if (posn >= hashSize) {
|
|
hash->resetHMAC(buf + hashSize, hashSize);
|
|
if (counter != 1)
|
|
hash->update(buf, hashSize);
|
|
if (info && infoLen)
|
|
hash->update(info, infoLen);
|
|
hash->update(&counter, 1);
|
|
hash->finalizeHMAC(buf + hashSize, hashSize, buf, hashSize);
|
|
++counter;
|
|
posn = 0;
|
|
}
|
|
|
|
// Copy as much output data as we can for this block.
|
|
size_t len = hashSize - posn;
|
|
if (len > outLen)
|
|
len = outLen;
|
|
memcpy(outPtr, buf + posn, len);
|
|
posn += len;
|
|
outPtr += len;
|
|
outLen -= len;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Clears sensitive information from this HKDF instance.
|
|
*/
|
|
void HKDFCommon::clear()
|
|
{
|
|
size_t hashSize = hash->hashSize();
|
|
hash->clear();
|
|
clean(buf, hashSize * 2);
|
|
counter = 1;
|
|
posn = hashSize;
|
|
}
|
|
|
|
/**
|
|
* \fn void HKDFCommon::setHashAlgorithm(Hash *hashAlg, uint8_t *buffer)
|
|
* \brief Sets the hash algorithm to use for HKDF operations.
|
|
*
|
|
* \param hashAlg Points to the hash algorithm instance to use.
|
|
* \param buffer Points to a buffer that must be at least twice the
|
|
* size of the hash output from \a hashAlg.
|
|
*/
|
|
|
|
/**
|
|
* \class HKDF HKDF.h <HKDF.h>
|
|
* \brief Implementation of the HKDF mode for hash algorithms.
|
|
*
|
|
* HKDF expands a key to a larger amount of material that can be used
|
|
* for cryptographic operations. It is based around a hash algorithm.
|
|
*
|
|
* The template parameter T must be a concrete subclass of Hash
|
|
* indicating the specific hash algorithm to use.
|
|
*
|
|
* The following example expands a 32-byte / 256-bit key into
|
|
* 128 bytes / 1024 bits of key material for use in a cryptographic session:
|
|
*
|
|
* \code
|
|
* uint8_t key[32] = {...};
|
|
* uint8_t output[128];
|
|
* HKDF<SHA256> hkdf;
|
|
* hkdf.setKey(key, sizeof(key));
|
|
* hkdf.extract(output, sizeof(output));
|
|
* \endcode
|
|
*
|
|
* Usually the key will be salted, which can be passed to the setKey()
|
|
* function:
|
|
*
|
|
* \code
|
|
* hkdf.setKey(key, sizeof(key), salt, sizeof(salt));
|
|
* \endcode
|
|
*
|
|
* It is also possible to acheive the same effect with a single function call
|
|
* using the hkdf() templated function:
|
|
*
|
|
* \code
|
|
* hkdf<SHA256>(output, sizeof(output), key, sizeof(key),
|
|
* salt, sizeof(salt), info, sizeof(info));
|
|
* \endcode
|
|
*
|
|
* Reference: https://datatracker.ietf.org/doc/html/rfc5869
|
|
*/
|
|
|
|
/**
|
|
* \fn HKDF::HKDF()
|
|
* \brief Constructs a new HKDF object for the hash algorithm T.
|
|
*/
|
|
|
|
/**
|
|
* \fn HKDF::~HKDF()
|
|
* \brief Destroys a HKDF instance and all sensitive data within it.
|
|
*/
|
|
|
|
/**
|
|
* \fn void hkdf<T>(void *out, size_t outLen, const void *key, size_t keyLen, const void *salt, size_t saltLen, const void *info, size_t infoLen)
|
|
* \brief All-in-one implementation of HKDF using a hash algorithm.
|
|
*
|
|
* \param out Points to the buffer to fill with extracted data.
|
|
* \param outLen Number of bytes to extract into the \a out buffer.
|
|
* \param key Points to the key.
|
|
* \param keyLen Length of the \a key in bytes.
|
|
* \param salt Points to the salt.
|
|
* \param saltLen Length of the \a salt in bytes.
|
|
* \param info Points to the application-specific information string.
|
|
* \param infoLen Length of the \a info string in bytes.
|
|
*
|
|
* The template parameter T must be a subclass of Hash.
|
|
*/
|