-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
438 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
/* | ||
* 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. | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* 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. | ||
*/ | ||
|
||
#ifndef CRYPTO_HKDF_h | ||
#define CRYPTO_HKDF_h | ||
|
||
#include "Hash.h" | ||
#include "Crypto.h" | ||
|
||
class HKDFCommon | ||
{ | ||
public: | ||
virtual ~HKDFCommon(); | ||
|
||
void setKey(const void *key, size_t keyLen, const void *salt = 0, size_t saltLen = 0); | ||
|
||
void extract(void *out, size_t outLen, const void *info = 0, size_t infoLen = 0); | ||
|
||
void clear(); | ||
|
||
protected: | ||
HKDFCommon(); | ||
void setHashAlgorithm(Hash *hashAlg, uint8_t *buffer) | ||
{ | ||
hash = hashAlg; | ||
buf = buffer; | ||
} | ||
|
||
private: | ||
Hash *hash; | ||
uint8_t *buf; | ||
uint8_t counter; | ||
uint8_t posn; | ||
}; | ||
|
||
template <typename T> | ||
class HKDF : public HKDFCommon | ||
{ | ||
public: | ||
HKDF() { setHashAlgorithm(&hashAlg, buffer); } | ||
~HKDF() { ::clean(buffer, sizeof(buffer)); } | ||
|
||
private: | ||
T hashAlg; | ||
uint8_t buffer[T::HASH_SIZE * 2]; | ||
}; | ||
|
||
template <typename T> void hkdf | ||
(void *out, size_t outLen, const void *key, size_t keyLen, | ||
const void *salt, size_t saltLen, const void *info, size_t infoLen) | ||
{ | ||
HKDF<T> context; | ||
context.setKey(key, keyLen, salt, saltLen); | ||
context.extract(out, outLen, info, infoLen); | ||
} | ||
|
||
#endif |
Oops, something went wrong.