1
0
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:
Rhys Weatherley 2016-02-09 19:06:26 +10:00
parent 21ac06136a
commit e66f8fe6e0
6 changed files with 271 additions and 116 deletions

View File

@ -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

View File

@ -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

View File

@ -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];
}

View File

@ -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
View 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
View 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