mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
DirtySDK (EA's Dirty Sockets library) will be used for the LiveAPI implementation, and depends on: EABase, EAThread.
622 lines
20 KiB
C
622 lines
20 KiB
C
/*H********************************************************************************/
|
|
/*!
|
|
\File cryptchacha.c
|
|
|
|
\Description
|
|
Implements the ChaCha20-Poly1305 AEAD cipher
|
|
|
|
\Notes
|
|
This implementation is based on the IETF Protocol and implements the
|
|
ChaCha20-Poly1305 AEAD cipher as used in TLS et all.
|
|
|
|
References:
|
|
- ChaCha20 and Poly1305 for IETF Protocols: https://tools.ietf.org/html/rfc8439
|
|
- ChaCha20-Poly1305 Cipher Suites for TLS: https://tools.ietf.org/html/rfc7905
|
|
- Original implementation of ChaCha: https://cr.yp.to/chacha.html
|
|
- Original implementation of Poly1305: https://cr.yp.to/mac.html
|
|
|
|
As per https://tools.ietf.org/html/rfc7539#section-2.7, Poly1305 requires
|
|
a one-time key and is "...biased, unlike HMAC". As such it is not suitable
|
|
for general use, and is therefore included dicrectly in the ChaCha20
|
|
AEAD cipher implementation.
|
|
|
|
\Copyright
|
|
Copyright (c) 2018 Electronic Arts
|
|
|
|
\Version 02/12/2018 (jbrookes) First Version
|
|
*/
|
|
/********************************************************************************H*/
|
|
|
|
/*** Include files ****************************************************************/
|
|
|
|
#include <string.h>
|
|
|
|
#include "DirtySDK/platform.h"
|
|
#include "DirtySDK/dirtysock/dirtylib.h"
|
|
|
|
#include "DirtySDK/crypt/cryptbn.h"
|
|
#include "DirtySDK/crypt/cryptchacha.h"
|
|
|
|
/*** Defines **********************************************************************/
|
|
|
|
#define CRYPTCHACHA_VERBOSE (DIRTYCODE_DEBUG && FALSE)
|
|
|
|
/*** Macros ***********************************************************************/
|
|
|
|
#define CHACHA_RDWORD(_ptr) (((uint32_t)(_ptr)[0]) | ((uint32_t)((_ptr)[1])<<8) | (((uint32_t)(_ptr)[2])<<16) | (((uint32_t)(_ptr)[3])<<24))
|
|
#define CHACHA_WRWORD(_ptr, _x) ((_ptr)[0] = (uint8_t)(_x),\
|
|
(_ptr)[1] = (uint8_t)((_x)>>8),\
|
|
(_ptr)[2] = (uint8_t)((_x)>>16),\
|
|
(_ptr)[3] = (uint8_t)((_x)>>24))
|
|
#define CHACHA_ROTATE(_x, _n) (((_x)<<(_n))|((_x)>>(32-(_n))))
|
|
#define CHACHA_XOR(_v, _w) ((_v) ^ (_w))
|
|
#define CHACHA_PLUS(_v, _w) ((_v) + (_w))
|
|
#define CHACHA_PLUSONE(_v) (CHACHA_PLUS((_v), 1))
|
|
|
|
#define CHACHA_QUARTERROUND(_x, _a, _b, _c, _d) \
|
|
(_x)[_a] = CHACHA_PLUS((_x)[_a], (_x)[_b]); (_x)[_d] = CHACHA_ROTATE(CHACHA_XOR((_x)[_d], (_x)[_a]), 16); \
|
|
(_x)[_c] = CHACHA_PLUS((_x)[_c], (_x)[_d]); (_x)[_b] = CHACHA_ROTATE(CHACHA_XOR((_x)[_b], (_x)[_c]), 12); \
|
|
(_x)[_a] = CHACHA_PLUS((_x)[_a], (_x)[_b]); (_x)[_d] = CHACHA_ROTATE(CHACHA_XOR((_x)[_d], (_x)[_a]), 8); \
|
|
(_x)[_c] = CHACHA_PLUS((_x)[_c], (_x)[_d]); (_x)[_b] = CHACHA_ROTATE(CHACHA_XOR((_x)[_b], (_x)[_c]), 7);
|
|
|
|
/*** Type Definitions *************************************************************/
|
|
|
|
//! Poly1305 state
|
|
typedef struct CryptPolyT
|
|
{
|
|
CryptBnT r, s, a, p;
|
|
} CryptPolyT;
|
|
|
|
/*** Variables ********************************************************************/
|
|
|
|
/*** Private Functions ************************************************************/
|
|
|
|
|
|
/*
|
|
Poly1305 Routines
|
|
*/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyLE16
|
|
|
|
\Description
|
|
Covert input to little endian and pad to 16 bytes
|
|
|
|
\Input *pOutput - [out] output for padded and flipped data
|
|
\Input *pInput - input to pad/flip
|
|
\Input iLength - length of input data
|
|
|
|
\Output
|
|
int32_t - length (16)
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static int32_t _CryptPolyLE16(uint8_t *pOutput, const uint8_t *pInput, int32_t iLength)
|
|
{
|
|
int32_t iData;
|
|
if (iLength > 16)
|
|
{
|
|
iLength = 16;
|
|
}
|
|
for (iData = 0; iData < 16-iLength; iData += 1)
|
|
{
|
|
pOutput[iData] = 0;
|
|
}
|
|
for ( ; iData < 16; iData += 1)
|
|
{
|
|
pOutput[iData] = pInput[16-iData-1];
|
|
}
|
|
return(16);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyBnInit
|
|
|
|
\Description
|
|
Init a BigNumber from input data, optionally extending with 0x01
|
|
|
|
\Input *pState - BigNumber to init
|
|
\Input iWidth - width to pass through to CryptBnInit
|
|
\Input *pBuffer - input data
|
|
\Input iLength - length of input data
|
|
\Input iExtra - one to extend with 0x01, else zero
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyBnInit(CryptBnT *pState, int32_t iWidth, const uint8_t *pBuffer, int32_t iLength, int32_t iExtra)
|
|
{
|
|
uint8_t aLEData[17];
|
|
if (iExtra)
|
|
{
|
|
aLEData[0] = 0x01;
|
|
}
|
|
iLength = _CryptPolyLE16(aLEData+iExtra, pBuffer, iLength);
|
|
CryptBnInitFrom(pState, iWidth, aLEData, iLength+iExtra);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyClamp
|
|
|
|
\Description
|
|
Clamp vector as per https://tools.ietf.org/html/rfc7539#section-2.5
|
|
|
|
\Input *pInput - input vector to clamp
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyClamp(uint8_t *pInput)
|
|
{
|
|
pInput[3] &= 15;
|
|
pInput[7] &= 15;
|
|
pInput[11] &= 15;
|
|
pInput[15] &= 15;
|
|
pInput[4] &= 252;
|
|
pInput[8] &= 252;
|
|
pInput[12] &= 252;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyInit
|
|
|
|
\Description
|
|
Init Poly state with specified key
|
|
|
|
\Input *pState - module state
|
|
\Input *pKey - input encryption key
|
|
\Input iKeyLen - length of key
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyInit(CryptPolyT *pState, uint8_t *pKey, int32_t iKeyLen)
|
|
{
|
|
static const uint8_t p_src[] = { 0x3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb };
|
|
// clamp(r): r &= 0x0ffffffc0ffffffc0ffffffc0fffffff
|
|
_CryptPolyClamp(pKey);
|
|
// r = (le_bytes_to_num(key[0..15])
|
|
_CryptPolyBnInit(&pState->r, -1, pKey, 16, 0);
|
|
// s = le_num(key[16..31])
|
|
_CryptPolyBnInit(&pState->s, -1, pKey+16, 16, 0);
|
|
// accumulator = 0
|
|
CryptBnInitSet(&pState->a, 0);
|
|
// p = (1<<130)-5
|
|
CryptBnInitFrom(&pState->p, -1, p_src, sizeof(p_src));
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyUpdate
|
|
|
|
\Description
|
|
Update Poly state with specified input data. Data is padded to 16 byte
|
|
width and extended with 0x1 as per https://tools.ietf.org/html/rfc7539#section-2.5.1
|
|
|
|
\Input *pState - module state
|
|
\Input *pData - input data to process
|
|
\Input iLength - length of data
|
|
|
|
\Notes
|
|
BnMultiply and BnMod steps are utilized instead of BnModMultiply because
|
|
the product of a and r can exceed the size of the modulus p; this is not
|
|
supported by CryptBn.
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyUpdate(CryptPolyT *pState, const uint8_t *pData, int32_t iLength)
|
|
{
|
|
CryptBnT n;
|
|
|
|
// for i=1 upto ceil(msg length in bytes / 16)
|
|
for ( ; iLength > 0; pData += 16, iLength -= 16)
|
|
{
|
|
// n = le_bytes_to_num(msg[((i-1)*16)..(i*16)] | [0x01])
|
|
_CryptPolyBnInit(&n, -1, pData, iLength, 1);
|
|
// a += n
|
|
CryptBnAccumulate(&pState->a, &n);
|
|
// a *= r
|
|
CryptBnMultiply(&pState->a, &pState->r, &pState->a);
|
|
// a %= p
|
|
CryptBnMod(&pState->a, &pState->p, &pState->a, NULL);
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyFinal
|
|
|
|
\Description
|
|
Generate final tag
|
|
|
|
\Input *pState - module state
|
|
\Input *pData - [out] output buffer to write tag to
|
|
\Input iLength - length of buffer
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyFinal(CryptPolyT *pState, uint8_t *pData, int32_t iLength)
|
|
{
|
|
uint8_t aTag[16];
|
|
// a += s
|
|
CryptBnAccumulate(&pState->a, &pState->s);
|
|
// num_to_16_le_bytes(a)
|
|
CryptBnFinal(&pState->a, aTag, sizeof(aTag));
|
|
// write out the tag
|
|
_CryptPolyLE16(pData, aTag, iLength);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptPolyGenerateTag
|
|
|
|
\Description
|
|
Generate authentication tag based on input data, key, and additional
|
|
authentication data.
|
|
|
|
\Input *pBuffer - input data to generate tag for
|
|
\Input iLength - length of input data
|
|
\Input *pKey - encryption key used for poly operation
|
|
\Input iKeyLen - length of key
|
|
\Input *pAddData - additional unencrypted data
|
|
\Input iAddLen - length of additional data
|
|
\Input *pTag - [out] buffer to write tag to
|
|
\Input iTagLen - length of tag buffer
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptPolyGenerateTag(const uint8_t *pBuffer, int32_t iLength, uint8_t *pKey, int32_t iKeyLen, const uint8_t *pAddData, int32_t iAddLen, uint8_t *pTag, int32_t iTagLen)
|
|
{
|
|
CryptPolyT Poly;
|
|
uint8_t aLengths[16];
|
|
|
|
// generate add and txt lengths
|
|
aLengths[0] = (uint8_t)(iAddLen>>0);
|
|
aLengths[1] = (uint8_t)(iAddLen>>8);
|
|
aLengths[2] = (uint8_t)(iAddLen>>16);
|
|
aLengths[3] = (uint8_t)(iAddLen>>24);
|
|
aLengths[4] = aLengths[5] = aLengths[6] = aLengths[7] = 0;
|
|
aLengths[8] = (uint8_t)(iLength>>0);
|
|
aLengths[9] = (uint8_t)(iLength>>8);
|
|
aLengths[10] = (uint8_t)(iLength>>16);
|
|
aLengths[11] = (uint8_t)(iLength>>24);
|
|
aLengths[12] = aLengths[13] = aLengths[14] = aLengths[15] = 0;
|
|
|
|
// init poly state
|
|
_CryptPolyInit(&Poly, pKey, iKeyLen);
|
|
|
|
// update with add data (padded) | text (padded) | lengths
|
|
_CryptPolyUpdate(&Poly, pAddData, iAddLen);
|
|
_CryptPolyUpdate(&Poly, pBuffer, iLength);
|
|
_CryptPolyUpdate(&Poly, aLengths, sizeof(aLengths));
|
|
|
|
// generate tag
|
|
_CryptPolyFinal(&Poly, pTag, iTagLen);
|
|
}
|
|
|
|
/*
|
|
ChaCha20 Routines
|
|
*/
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _ChaCha20Block
|
|
|
|
\Description
|
|
ChaCha20 block round as per https://tools.ietf.org/html/rfc7539#section-2.3.1
|
|
|
|
\Input *pOutput - [out] buffer to write output
|
|
\Input *pInput - input for block round
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _ChaCha20Block(uint8_t *pOutput, const uint32_t *pInput)
|
|
{
|
|
uint32_t aBlock[16];
|
|
int32_t iBlock;
|
|
|
|
// read iBlockInput
|
|
ds_memcpy(aBlock, pInput, sizeof(aBlock));
|
|
|
|
// quarter rounds; note that the original reference had eight rounds, while the IETF version has ten
|
|
for (iBlock = 0; iBlock < 10; iBlock += 1)
|
|
{
|
|
CHACHA_QUARTERROUND(aBlock, 0, 4, 8, 12);
|
|
CHACHA_QUARTERROUND(aBlock, 1, 5, 9, 13);
|
|
CHACHA_QUARTERROUND(aBlock, 2, 6, 10, 14);
|
|
CHACHA_QUARTERROUND(aBlock, 3, 7, 11, 15);
|
|
CHACHA_QUARTERROUND(aBlock, 0, 5, 10, 15);
|
|
CHACHA_QUARTERROUND(aBlock, 1, 6, 11, 12);
|
|
CHACHA_QUARTERROUND(aBlock, 2, 7, 8, 13);
|
|
CHACHA_QUARTERROUND(aBlock, 3, 4, 9, 14);
|
|
}
|
|
|
|
// accumulate input and write output
|
|
for (iBlock = 0; iBlock < 16; iBlock += 1)
|
|
{
|
|
CHACHA_WRWORD(pOutput + (4*iBlock), CHACHA_PLUS(aBlock[iBlock], pInput[iBlock]));
|
|
}
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptChaChaInitKey
|
|
|
|
\Description
|
|
Initialize crypt state based on input key
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pKeyBuf - input key
|
|
\Input iKeyLen - length of key in bytes
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptChaChaInitKey(CryptChaChaT *pChaCha, const uint8_t *pKeyBuf, int32_t iKeyLen)
|
|
{
|
|
static const char _strSigma[16] = "expand 32-byte k";
|
|
static const char _strTau[16] = "expand 16-byte k";
|
|
const char *pConstant;
|
|
|
|
// read first half of key
|
|
pChaCha->aInput[4] = CHACHA_RDWORD(pKeyBuf+0);
|
|
pChaCha->aInput[5] = CHACHA_RDWORD(pKeyBuf+4);
|
|
pChaCha->aInput[6] = CHACHA_RDWORD(pKeyBuf+8);
|
|
pChaCha->aInput[7] = CHACHA_RDWORD(pKeyBuf+12);
|
|
|
|
// determine 2nd half based on key length
|
|
if (iKeyLen == 32)
|
|
{
|
|
pKeyBuf += 16;
|
|
pConstant = _strSigma;
|
|
}
|
|
else
|
|
{
|
|
pConstant = _strTau;
|
|
}
|
|
|
|
// read second half of key
|
|
pChaCha->aInput[8] = CHACHA_RDWORD(pKeyBuf+0);
|
|
pChaCha->aInput[9] = CHACHA_RDWORD(pKeyBuf+4);
|
|
pChaCha->aInput[10] = CHACHA_RDWORD(pKeyBuf+8);
|
|
pChaCha->aInput[11] = CHACHA_RDWORD(pKeyBuf+12);
|
|
|
|
// read in constant
|
|
pChaCha->aInput[0] = CHACHA_RDWORD(pConstant+0);
|
|
pChaCha->aInput[1] = CHACHA_RDWORD(pConstant+4);
|
|
pChaCha->aInput[2] = CHACHA_RDWORD(pConstant+8);
|
|
pChaCha->aInput[3] = CHACHA_RDWORD(pConstant+12);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptChaChaGeneratePolyKey
|
|
|
|
\Description
|
|
Generate the Poly key as per https://tools.ietf.org/html/rfc7539#section-2.6
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pKey - [out] buffer for generated key
|
|
\Input iKeyLen - length of buffer
|
|
|
|
\Version 02/14/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptChaChaGeneratePolyKey(CryptChaChaT *pChaCha, uint8_t *pKey, int32_t iKeyLen)
|
|
{
|
|
uint8_t aPoly[64];
|
|
uint32_t uCounter;
|
|
// save current counter, set it to zero
|
|
uCounter = pChaCha->aInput[12];
|
|
pChaCha->aInput[12] = 0;
|
|
// use chacha20 to generate key state
|
|
_ChaCha20Block(aPoly, pChaCha->aInput);
|
|
// clamp r
|
|
_CryptPolyClamp(aPoly);
|
|
// copy out key
|
|
ds_memcpy_s(pKey, iKeyLen, aPoly, 32);
|
|
// restore counter
|
|
pChaCha->aInput[12] = uCounter;
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptChaChaInitIv
|
|
|
|
\Description
|
|
Initialize IV/Nonce portion of ChaCha state as per
|
|
https://tools.ietf.org/html/rfc7539#section-2.3
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pInitVec - input iv
|
|
\Input iIvLen - iv length
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptChaChaInitIv(CryptChaChaT *pChaCha, const uint8_t *pInitVec, int32_t iIvLen)
|
|
{
|
|
pChaCha->aInput[12] = 1; // as per https://tools.ietf.org/html/rfc7539#section-2.8 initial counter value is one
|
|
pChaCha->aInput[13] = CHACHA_RDWORD(pInitVec+0);
|
|
pChaCha->aInput[14] = CHACHA_RDWORD(pInitVec+4);
|
|
pChaCha->aInput[15] = CHACHA_RDWORD(pInitVec+8);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function _CryptChaChaEncrypt
|
|
|
|
\Description
|
|
Encrypted plaintext as per https://tools.ietf.org/html/rfc7539#section-2.4
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pInput - input to encrypt
|
|
\Input *pOutput - [out] buffer to write decrypted data to (may overlap)
|
|
\Input iLength - data length
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
static void _CryptChaChaEncrypt(CryptChaChaT *pChaCha, const uint8_t *pInput, uint8_t *pOutput, int32_t iLength)
|
|
{
|
|
int32_t iCount, iCopyLen;
|
|
uint8_t aOutput[64];
|
|
|
|
while (iLength > 0)
|
|
{
|
|
_ChaCha20Block(aOutput, pChaCha->aInput);
|
|
pChaCha->aInput[12] = CHACHA_PLUSONE(pChaCha->aInput[12]);
|
|
if (!pChaCha->aInput[12])
|
|
{
|
|
pChaCha->aInput[13] = CHACHA_PLUSONE(pChaCha->aInput[13]);
|
|
}
|
|
for (iCount = 0, iCopyLen = (iLength >= 64) ? 64 : iLength; iCount < iCopyLen; iCount += 1)
|
|
{
|
|
pOutput[iCount] = pInput[iCount] ^ aOutput[iCount];
|
|
}
|
|
iLength -= iCopyLen;
|
|
pInput += iCopyLen;
|
|
pOutput += iCopyLen;
|
|
}
|
|
}
|
|
|
|
|
|
/*** Public functions *************************************************************/
|
|
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptChaChaInit
|
|
|
|
\Description
|
|
Init the ChaCha cipher with the specified key
|
|
|
|
\Input *pChaCha - cipher state to initialize
|
|
\Input *pKeyBuf - pointer to key
|
|
\Input iKeyLen - key length
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
void CryptChaChaInit(CryptChaChaT *pChaCha, const uint8_t *pKeyBuf, int32_t iKeyLen)
|
|
{
|
|
// clear state
|
|
ds_memclr(pChaCha, sizeof(*pChaCha));
|
|
// init state with key
|
|
_CryptChaChaInitKey(pChaCha, pKeyBuf, iKeyLen);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptChaChaEncrypt
|
|
|
|
\Description
|
|
Encrypt input data in place and optionally generate authentication tag
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pBuffer - [inp/out] data to encrypt
|
|
\Input iLength - length of data to encrypt
|
|
\Input *pInitVec - initialization vector (IV)
|
|
\Input iIvLen - IV len
|
|
\Input *pAddData - additional authenticated data
|
|
\Input iAddLen - length of additional data
|
|
\Input *pTag - [out] tag buffer
|
|
\Input iTagLen - tag length
|
|
|
|
\Notes
|
|
Pass NULL to pTag if you don't want authentication tag to be generated.
|
|
|
|
\Output
|
|
int32_t - encrypted data size
|
|
|
|
\Version 07/01/2014 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptChaChaEncrypt(CryptChaChaT *pChaCha, uint8_t *pBuffer, int32_t iLength, const uint8_t *pInitVec, int32_t iIvLen, const uint8_t *pAddData, int32_t iAddLen, uint8_t *pTag, int32_t iTagLen)
|
|
{
|
|
uint8_t aPolyKey[32];
|
|
|
|
// set IV in state
|
|
_CryptChaChaInitIv(pChaCha, pInitVec, iIvLen);
|
|
|
|
if (pTag != NULL)
|
|
{
|
|
// generate the Poly1305 key
|
|
_CryptChaChaGeneratePolyKey(pChaCha, aPolyKey, sizeof(aPolyKey));
|
|
}
|
|
|
|
// encrypt the input
|
|
_CryptChaChaEncrypt(pChaCha, pBuffer, pBuffer, iLength);
|
|
|
|
if (pTag != NULL)
|
|
{
|
|
// generate the authentication tag
|
|
_CryptPolyGenerateTag(pBuffer, iLength, aPolyKey, sizeof(aPolyKey), pAddData, iAddLen, pTag, iTagLen);
|
|
}
|
|
|
|
// return success
|
|
return(iLength);
|
|
}
|
|
|
|
/*F********************************************************************************/
|
|
/*!
|
|
\Function CryptChaChaDecrypt
|
|
|
|
\Description
|
|
Decrypt input data in place and optionally generate authentication tag;
|
|
verify it matches the specified tag.
|
|
|
|
\Input *pChaCha - cipher state
|
|
\Input *pBuffer - [inp/out] data to decrypt
|
|
\Input iLength - length of data to decrypt
|
|
\Input *pInitVec - initialization vector (IV)
|
|
\Input iIvLen - IV len
|
|
\Input *pAddData - additional authenticated data
|
|
\Input iAddLen - length of additional data
|
|
\Input *pTag - tag buffer
|
|
\Input iTagLen - tag length
|
|
|
|
\Notes
|
|
Pass NULL to pTag if you don't want to generate and verify the authentication
|
|
tag.
|
|
|
|
\Output
|
|
int32_t - decrypted data size
|
|
|
|
\Version 02/12/2018 (jbrookes)
|
|
*/
|
|
/********************************************************************************F*/
|
|
int32_t CryptChaChaDecrypt(CryptChaChaT *pChaCha, uint8_t *pBuffer, int32_t iLength, const uint8_t *pInitVec, int32_t iIvLen, const uint8_t *pAddData, int32_t iAddLen, const uint8_t *pTag, int32_t iTagLen)
|
|
{
|
|
uint8_t aPolyKey[32], aTag[16];
|
|
|
|
// set IV in state
|
|
_CryptChaChaInitIv(pChaCha, pInitVec, iIvLen);
|
|
|
|
if (pTag != NULL)
|
|
{
|
|
// generate the Poly1305 key
|
|
_CryptChaChaGeneratePolyKey(pChaCha, aPolyKey, sizeof(aPolyKey));
|
|
|
|
// generate the authentication tag on the encrypted data
|
|
_CryptPolyGenerateTag(pBuffer, iLength, aPolyKey, sizeof(aPolyKey), pAddData, iAddLen, aTag, sizeof(aTag));
|
|
}
|
|
|
|
// do the decrypt
|
|
_CryptChaChaEncrypt(pChaCha, pBuffer, pBuffer, iLength);
|
|
|
|
// return length of decrypted data, or -1 if tag mismatch
|
|
return((pTag == NULL) || !memcmp(pTag, aTag, iTagLen) ? iLength : -1);
|
|
}
|
|
|
|
|