mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Split the OMAC code out of EAX so it can be used separately
This commit is contained in:
parent
21ac06136a
commit
e66f8fe6e0
@ -31,7 +31,7 @@
|
||||
\li Stream ciphers: ChaCha
|
||||
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, EAX, GCM
|
||||
\li Hash algorithms: SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
||||
\li Message authenticators: Poly1305, GHASH
|
||||
\li Message authenticators: Poly1305, GHASH, OMAC
|
||||
\li Public key algorithms: Curve25519, Ed25519
|
||||
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
||||
|
||||
|
@ -96,7 +96,7 @@ realtime clock and the LCD library to implement an alarm clock.
|
||||
\li Stream ciphers: ChaCha
|
||||
\li Authenticated encryption with associated data (AEAD): ChaChaPoly, EAX, GCM
|
||||
\li Hash algorithms: SHA256, SHA512, SHA3_256, SHA3_512, BLAKE2s, BLAKE2b (regular and HMAC modes)
|
||||
\li Message authenticators: Poly1305, GHASH
|
||||
\li Message authenticators: Poly1305, GHASH, OMAC
|
||||
\li Public key algorithms: Curve25519, Ed25519
|
||||
\li Random number generation: \link RNGClass RNG\endlink, TransistorNoiseSource, RingOscillatorNoiseSource
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
#include "EAX.h"
|
||||
#include "GF128.h"
|
||||
#include "Crypto.h"
|
||||
#include <string.h>
|
||||
|
||||
@ -42,10 +41,8 @@
|
||||
* This constructor must be followed by a call to setBlockCipher().
|
||||
*/
|
||||
EAXCommon::EAXCommon()
|
||||
: blockCipher(0)
|
||||
{
|
||||
state.encPosn = 0;
|
||||
state.authPosn = 0;
|
||||
state.authMode = 0;
|
||||
}
|
||||
|
||||
@ -56,7 +53,7 @@ EAXCommon::~EAXCommon()
|
||||
|
||||
size_t EAXCommon::keySize() const
|
||||
{
|
||||
return blockCipher->keySize();
|
||||
return omac.blockCipher()->keySize();
|
||||
}
|
||||
|
||||
size_t EAXCommon::ivSize() const
|
||||
@ -73,7 +70,7 @@ size_t EAXCommon::tagSize() const
|
||||
|
||||
bool EAXCommon::setKey(const uint8_t *key, size_t len)
|
||||
{
|
||||
return blockCipher->setKey(key, len);
|
||||
return omac.blockCipher()->setKey(key, len);
|
||||
}
|
||||
|
||||
bool EAXCommon::setIV(const uint8_t *iv, size_t len)
|
||||
@ -83,16 +80,16 @@ bool EAXCommon::setIV(const uint8_t *iv, size_t len)
|
||||
return false;
|
||||
|
||||
// Hash the IV to create the initial nonce for CTR mode. Also creates B.
|
||||
omacInitFirst(state.counter);
|
||||
omacUpdate(state.counter, iv, len);
|
||||
omacFinal(state.counter);
|
||||
omac.initFirst(state.counter);
|
||||
omac.update(state.counter, iv, len);
|
||||
omac.finalize(state.counter);
|
||||
|
||||
// The tag is initially the nonce value. Will be XOR'ed with
|
||||
// the hash of the authenticated and encrypted data later.
|
||||
memcpy(state.tag, state.counter, 16);
|
||||
|
||||
// Start the hashing context for the authenticated data.
|
||||
omacInit(state.hash, 1);
|
||||
omac.initNext(state.hash, 1);
|
||||
state.encPosn = 16;
|
||||
state.authMode = 1;
|
||||
|
||||
@ -105,21 +102,21 @@ void EAXCommon::encrypt(uint8_t *output, const uint8_t *input, size_t len)
|
||||
if (state.authMode)
|
||||
closeAuthData();
|
||||
encryptCTR(output, input, len);
|
||||
omacUpdate(state.hash, output, len);
|
||||
omac.update(state.hash, output, len);
|
||||
}
|
||||
|
||||
void EAXCommon::decrypt(uint8_t *output, const uint8_t *input, size_t len)
|
||||
{
|
||||
if (state.authMode)
|
||||
closeAuthData();
|
||||
omacUpdate(state.hash, input, len);
|
||||
omac.update(state.hash, input, len);
|
||||
encryptCTR(output, input, len);
|
||||
}
|
||||
|
||||
void EAXCommon::addAuthData(const void *data, size_t len)
|
||||
{
|
||||
if (state.authMode)
|
||||
omacUpdate(state.hash, (const uint8_t *)data, len);
|
||||
omac.update(state.hash, (const uint8_t *)data, len);
|
||||
}
|
||||
|
||||
void EAXCommon::computeTag(void *tag, size_t len)
|
||||
@ -146,95 +143,6 @@ void EAXCommon::clear()
|
||||
clean(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises the first OMAC hashing context and creates the B value.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
*/
|
||||
void EAXCommon::omacInitFirst(uint8_t omac[16])
|
||||
{
|
||||
// Start the OMAC context for the nonce. We assume that the
|
||||
// data that follows will be at least 1 byte in length so that
|
||||
// we can encrypt the zeroes now to derive the B value.
|
||||
memset(omac, 0, 16);
|
||||
blockCipher->encryptBlock(omac, omac);
|
||||
state.authPosn = 0;
|
||||
|
||||
// Generate the B value from the encrypted block of zeroes.
|
||||
// We will need this later when finalising the OMAC hashes.
|
||||
memcpy(state.b, omac, 16);
|
||||
GF128::dblEAX(state.b);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises an OMAC hashing context.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
* \param t The tag value indicating which OMAC calculation we are doing.
|
||||
*/
|
||||
void EAXCommon::omacInit(uint8_t omac[16], uint8_t t)
|
||||
{
|
||||
memset(omac, 0, 15);
|
||||
omac[15] = t;
|
||||
state.authPosn = 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Updates an OMAC hashing context with more data.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
* \param data Points to the data to be hashed.
|
||||
* \parm len The number of bytes to be hashed.
|
||||
*/
|
||||
void EAXCommon::omacUpdate(uint8_t omac[16], const uint8_t *data, size_t len)
|
||||
{
|
||||
while (len > 0) {
|
||||
// Encrypt the current block if it is already full.
|
||||
if (state.authPosn == 16) {
|
||||
blockCipher->encryptBlock(omac, omac);
|
||||
state.authPosn = 0;
|
||||
}
|
||||
|
||||
// XOR the incoming data with the current block.
|
||||
uint8_t size = 16 - state.authPosn;
|
||||
if (size > len)
|
||||
size = (uint8_t)len;
|
||||
for (uint8_t index = 0; index < size; ++index)
|
||||
omac[(state.authPosn)++] ^= data[index];
|
||||
|
||||
// Move onto the next block.
|
||||
len -= size;
|
||||
data += size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Finalises an OMAC hashing context.
|
||||
*
|
||||
* \param omac The OMAC hashing context on entry, the final OMAC value on exit.
|
||||
*/
|
||||
void EAXCommon::omacFinal(uint8_t omac[16])
|
||||
{
|
||||
// Apply padding if necessary.
|
||||
if (state.authPosn != 16) {
|
||||
// Need padding: XOR with P = 2 * B.
|
||||
uint32_t p[4];
|
||||
memcpy(p, state.b, 16);
|
||||
GF128::dblEAX(p);
|
||||
omac[state.authPosn] ^= 0x80;
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
omac[index] ^= ((const uint8_t *)p)[index];
|
||||
clean(p);
|
||||
} else {
|
||||
// No padding necessary: XOR with B.
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
omac[index] ^= ((const uint8_t *)(state.b))[index];
|
||||
}
|
||||
|
||||
// Encrypt the hash to get the final OMAC value.
|
||||
blockCipher->encryptBlock(omac, omac);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Closes the authenticated data portion of the session and
|
||||
* starts encryption or decryption.
|
||||
@ -242,13 +150,13 @@ void EAXCommon::omacFinal(uint8_t omac[16])
|
||||
void EAXCommon::closeAuthData()
|
||||
{
|
||||
// Finalise the OMAC hash and XOR it with the final tag.
|
||||
omacFinal(state.hash);
|
||||
omac.finalize(state.hash);
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
state.tag[index] ^= state.hash[index];
|
||||
state.authMode = 0;
|
||||
|
||||
// Initialise the hashing context for the ciphertext data.
|
||||
omacInit(state.hash, 2);
|
||||
omac.initNext(state.hash, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +174,7 @@ void EAXCommon::encryptCTR(uint8_t *output, const uint8_t *input, size_t len)
|
||||
// Do we need to start a new block?
|
||||
if (state.encPosn == 16) {
|
||||
// Encrypt the counter to create the next keystream block.
|
||||
blockCipher->encryptBlock(state.stream, state.counter);
|
||||
omac.blockCipher()->encryptBlock(state.stream, state.counter);
|
||||
state.encPosn = 0;
|
||||
|
||||
// Increment the counter, taking care not to reveal
|
||||
@ -304,7 +212,7 @@ void EAXCommon::closeTag()
|
||||
closeAuthData();
|
||||
|
||||
// Finalise the hash over the ciphertext and XOR with the final tag.
|
||||
omacFinal(state.hash);
|
||||
omac.finalize(state.hash);
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
state.tag[index] ^= state.hash[index];
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "AuthenticatedCipher.h"
|
||||
#include "BlockCipher.h"
|
||||
#include "OMAC.h"
|
||||
|
||||
class EAXCommon : public AuthenticatedCipher
|
||||
{
|
||||
@ -50,25 +51,21 @@ public:
|
||||
|
||||
protected:
|
||||
EAXCommon();
|
||||
void setBlockCipher(BlockCipher *cipher) { blockCipher = cipher; }
|
||||
void setBlockCipher(BlockCipher *cipher)
|
||||
{
|
||||
omac.setBlockCipher(cipher);
|
||||
}
|
||||
|
||||
private:
|
||||
BlockCipher *blockCipher;
|
||||
struct {
|
||||
uint8_t counter[16];
|
||||
uint8_t stream[16];
|
||||
uint8_t tag[16];
|
||||
uint8_t hash[16];
|
||||
uint32_t b[4];
|
||||
uint8_t encPosn;
|
||||
uint8_t authPosn;
|
||||
uint8_t authMode;
|
||||
} state;
|
||||
|
||||
void omacInitFirst(uint8_t omac[16]);
|
||||
void omacInit(uint8_t omac[16], uint8_t t);
|
||||
void omacUpdate(uint8_t omac[16], const uint8_t *data, size_t len);
|
||||
void omacFinal(uint8_t omac[16]);
|
||||
OMAC omac;
|
||||
|
||||
void closeAuthData();
|
||||
void encryptCTR(uint8_t *output, const uint8_t *input, size_t len);
|
||||
|
200
libraries/Crypto/OMAC.cpp
Normal file
200
libraries/Crypto/OMAC.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 "OMAC.h"
|
||||
#include "GF128.h"
|
||||
#include "Crypto.h"
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* \class OMAC OMAC.h <OMAC.h>
|
||||
* \brief Implementation of the OMAC message authenticator.
|
||||
*
|
||||
* OMAC is the message authentication part of EAX mode. It is provided
|
||||
* as a separate class for the convenience of applications that need
|
||||
* message authentication separate from encryption.
|
||||
*
|
||||
* References: https://en.wikipedia.org/wiki/EAX_mode,
|
||||
* http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
|
||||
*
|
||||
* \sa EAX
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Constructs a new OMAC object.
|
||||
*
|
||||
* This constructor must be followed by a call to setBlockCipher()
|
||||
* to specify the block cipher to use.
|
||||
*/
|
||||
OMAC::OMAC()
|
||||
: _blockCipher(0)
|
||||
, posn(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys this OMAC object.
|
||||
*
|
||||
* \sa clear()
|
||||
*/
|
||||
OMAC::~OMAC()
|
||||
{
|
||||
clean(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn BlockCipher *OMAC::blockCipher() const
|
||||
* \brief Gets the block cipher that is in use for this OMAC object.
|
||||
*
|
||||
* \sa setBlockCipher()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn void OMAC::setBlockCipher(BlockCipher *cipher)
|
||||
* \brief Sets the block cipher to use for this OMAC object.
|
||||
*
|
||||
* \param cipher The block cipher to use to implement OMAC.
|
||||
* This object must have a block size of 128 bits (16 bytes).
|
||||
*
|
||||
* \sa blockCipher()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Initialises the first OMAC hashing context and creates the B value.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
*
|
||||
* This function must be called first before initNext(), update(), or
|
||||
* finalize() to create the B value from the OMAC algorithm which is
|
||||
* used to finalize later hashes. It is assumed that setBlockCipher()
|
||||
* has already been called.
|
||||
*
|
||||
* The tag value for the context is implicitly set to zero, which means
|
||||
* that the context can be used for ordinary hashing as long as the
|
||||
* data that follows is non-zero in length. Alternatively, initNext()
|
||||
* can be called to restart the context with a specific tag.
|
||||
*
|
||||
* This function must be called again whenever the block cipher or the
|
||||
* key changes.
|
||||
*
|
||||
* \sa initNext(), update(), finalize()
|
||||
*/
|
||||
void OMAC::initFirst(uint8_t omac[16])
|
||||
{
|
||||
// Start the OMAC context. We assume that the data that follows
|
||||
// will be at least 1 byte in length so that we can encrypt the
|
||||
// zeroes now to derive the B value.
|
||||
memset(omac, 0, 16);
|
||||
_blockCipher->encryptBlock(omac, omac);
|
||||
posn = 0;
|
||||
|
||||
// Generate the B value from the encrypted block of zeroes.
|
||||
// We will need this later when finalising the OMAC hashes.
|
||||
memcpy(b, omac, 16);
|
||||
GF128::dblEAX(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initialises or restarts an OMAC hashing context.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
* \param tag The tag value indicating which OMAC calculation we are doing.
|
||||
*
|
||||
* It is assumed that initFirst() was called previously to create the B
|
||||
* value for the context.
|
||||
*
|
||||
* \sa initFirst(), update(), finalize()
|
||||
*/
|
||||
void OMAC::initNext(uint8_t omac[16], uint8_t tag)
|
||||
{
|
||||
memset(omac, 0, 15);
|
||||
omac[15] = tag;
|
||||
posn = 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Updates an OMAC hashing context with more data.
|
||||
*
|
||||
* \param omac The OMAC hashing context.
|
||||
* \param data Points to the data to be hashed.
|
||||
* \param size The number of bytes to be hashed.
|
||||
*
|
||||
* \sa initFirst(), initNext(), finalize()
|
||||
*/
|
||||
void OMAC::update(uint8_t omac[16], const uint8_t *data, size_t size)
|
||||
{
|
||||
while (size > 0) {
|
||||
// Encrypt the current block if it is already full.
|
||||
if (posn == 16) {
|
||||
_blockCipher->encryptBlock(omac, omac);
|
||||
posn = 0;
|
||||
}
|
||||
|
||||
// XOR the incoming data with the current block.
|
||||
uint8_t len = 16 - posn;
|
||||
if (len > size)
|
||||
len = (uint8_t)size;
|
||||
for (uint8_t index = 0; index < len; ++index)
|
||||
omac[posn++] ^= data[index];
|
||||
|
||||
// Move onto the next block.
|
||||
size -= len;
|
||||
data += len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Finalises an OMAC hashing context.
|
||||
*
|
||||
* \param omac The OMAC hashing context on entry, the final OMAC value on exit.
|
||||
*
|
||||
* \sa initFirst(), initNext(), update()
|
||||
*/
|
||||
void OMAC::finalize(uint8_t omac[16])
|
||||
{
|
||||
// Apply padding if necessary.
|
||||
if (posn != 16) {
|
||||
// Need padding: XOR with P = 2 * B.
|
||||
uint32_t p[4];
|
||||
memcpy(p, b, 16);
|
||||
GF128::dblEAX(p);
|
||||
omac[posn] ^= 0x80;
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
omac[index] ^= ((const uint8_t *)p)[index];
|
||||
clean(p);
|
||||
} else {
|
||||
// No padding necessary: XOR with B.
|
||||
for (uint8_t index = 0; index < 16; ++index)
|
||||
omac[index] ^= ((const uint8_t *)b)[index];
|
||||
}
|
||||
|
||||
// Encrypt the hash to get the final OMAC value.
|
||||
_blockCipher->encryptBlock(omac, omac);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Clears all security-sensitive state from this object.
|
||||
*/
|
||||
void OMAC::clear()
|
||||
{
|
||||
clean(b);
|
||||
}
|
50
libraries/Crypto/OMAC.h
Normal file
50
libraries/Crypto/OMAC.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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_OMAC_H
|
||||
#define CRYPTO_OMAC_H
|
||||
|
||||
#include "BlockCipher.h"
|
||||
|
||||
class OMAC
|
||||
{
|
||||
public:
|
||||
OMAC();
|
||||
~OMAC();
|
||||
|
||||
BlockCipher *blockCipher() const { return _blockCipher; }
|
||||
void setBlockCipher(BlockCipher *cipher) { _blockCipher = cipher; }
|
||||
|
||||
void initFirst(uint8_t omac[16]);
|
||||
void initNext(uint8_t omac[16], uint8_t tag);
|
||||
void update(uint8_t omac[16], const uint8_t *data, size_t size);
|
||||
void finalize(uint8_t omac[16]);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
BlockCipher *_blockCipher;
|
||||
uint32_t b[4];
|
||||
uint8_t posn;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user