Added wolfcrypt API for the ChaCha20-Poly1305 AEAD.

This commit is contained in:
Andrew Burks
2015-02-24 09:15:11 -08:00
parent 14b6254e6e
commit 8c3410d6c2
4 changed files with 589 additions and 99 deletions

View File

@@ -0,0 +1,283 @@
/* chacha.c
*
* Copyright (C) 2006-2015 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if( defined( HAVE_CHACHA ) && defined( HAVE_POLY1305 ) )
#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/poly1305.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#include <wolfcrypt/src/misc.c>
#endif
#ifdef CHACHA_AEAD_TEST
#include <stdio.h>
#endif
#define CHACHA20_POLY1305_AEAD_INITIAL_COUNTER 0
#define CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT 16
static void _word32ToLittle64( const word32 inLittle32, byte outLittle64[8] );
static int _calculateAuthTag( const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte* inAAD, const word32 inAADLen,
const byte *inCiphertext, const word32 inCiphertextLen,
byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE] );
static int constantTimeCompare( const byte *a, const byte *b, word32 len );
WOLFSSL_API int wc_ChaCha20Poly1305_Encrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
const byte *inAAD, const word32 inAADLen,
const byte *inPlaintext, const word32 inPlaintextLen,
byte *outCiphertext,
byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE] )
{
int err;
byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
ChaCha chaChaCtx;
// Validate function arguments
if( !inKey || !inIV ||
!inPlaintext || !inPlaintextLen ||
!outCiphertext ||
!outAuthTag )
{
return BAD_FUNC_ARG;
}
ForceZero( poly1305Key, sizeof( poly1305Key ) );
err = 0;
// Create the Poly1305 key
err += wc_Chacha_SetKey( &chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE );
err += wc_Chacha_SetIV( &chaChaCtx, inIV, CHACHA20_POLY1305_AEAD_INITIAL_COUNTER );
err += wc_Chacha_Process( &chaChaCtx, poly1305Key, poly1305Key, CHACHA20_POLY1305_AEAD_KEYSIZE );
if( err )
{
return err;
}
// Encrypt the plaintext using ChaCha20
err = wc_Chacha_Process( &chaChaCtx, outCiphertext, inPlaintext, inPlaintextLen );
if( err )
{
return err;
}
// Calculate the Poly1305 auth tag
err = _calculateAuthTag( poly1305Key,
inAAD, inAADLen,
outCiphertext, inPlaintextLen,
outAuthTag );
return err;
}
WOLFSSL_API int wc_ChaCha20Poly1305_Decrypt( const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
const byte *inAAD, const word32 inAADLen,
const byte *inCiphertext, const word32 inCiphertextLen,
const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
byte* outPlaintext )
{
int err;
byte poly1305Key[CHACHA20_POLY1305_AEAD_KEYSIZE];
ChaCha chaChaCtx;
byte calculatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
// Validate function arguments
if( !inKey || !inIV ||
!inCiphertext || !inCiphertextLen ||
!inAuthTag ||
!outPlaintext )
{
return BAD_FUNC_ARG;
}
ForceZero( calculatedAuthTag, sizeof( calculatedAuthTag ) );
ForceZero( poly1305Key, sizeof( poly1305Key ) );
err = 0;
// Create the Poly1305 key
err += wc_Chacha_SetKey( &chaChaCtx, inKey, CHACHA20_POLY1305_AEAD_KEYSIZE );
err += wc_Chacha_SetIV( &chaChaCtx, inIV, CHACHA20_POLY1305_AEAD_INITIAL_COUNTER );
err += wc_Chacha_Process( &chaChaCtx, poly1305Key, poly1305Key, CHACHA20_POLY1305_AEAD_KEYSIZE );
if( err )
{
return err;
}
// Calculate the Poly1305 auth tag
err = _calculateAuthTag( poly1305Key,
inAAD, inAADLen,
inCiphertext, inCiphertextLen,
calculatedAuthTag );
// Compare the calculated auth tag with the received one
if( constantTimeCompare( inAuthTag, calculatedAuthTag, CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE ) )
{
return MAC_CMP_FAILED_E;
}
// Decrypt the received ciphertext
err = wc_Chacha_Process( &chaChaCtx, outPlaintext, inCiphertext, inCiphertextLen );
return err;
}
static int _calculateAuthTag( const byte inAuthKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte *inAAD, const word32 inAADLen,
const byte *inCiphertext, const word32 inCiphertextLen,
byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE] )
{
int err;
Poly1305 poly1305Ctx;
byte padding[CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1];
word32 paddingLen;
byte little64[8];
ForceZero( padding, sizeof( padding ) );
paddingLen = 0;
// Initialize Poly1305
err = wc_Poly1305SetKey( &poly1305Ctx, inAuthKey, CHACHA20_POLY1305_AEAD_KEYSIZE );
if( err )
{
return err;
}
// Create the authTag by MAC'ing the following items:
// -- AAD
if( inAAD && inAADLen )
{
err = wc_Poly1305Update( &poly1305Ctx, inAAD, inAADLen );
// -- padding1: pad the AAD to 16 bytes
paddingLen = -inAADLen & ( CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1 );
if( paddingLen )
{
err += wc_Poly1305Update( &poly1305Ctx, padding, paddingLen );
}
if( err )
{
return err;
}
}
// -- Ciphertext
err = wc_Poly1305Update( &poly1305Ctx, inCiphertext, inCiphertextLen );
if( err )
{
return err;
}
// -- padding2: pad the ciphertext to 16 bytes
paddingLen = -inCiphertextLen & ( CHACHA20_POLY1305_MAC_PADDING_ALIGNMENT - 1 );
if( paddingLen )
{
err = wc_Poly1305Update( &poly1305Ctx, padding, paddingLen );
}
if( err )
{
return err;
}
// -- AAD length as a 64-bit little endian integer
_word32ToLittle64( inAADLen, little64 );
err = wc_Poly1305Update( &poly1305Ctx, little64, sizeof( little64 ) );
if( err )
{
return err;
}
// -- Ciphertext length as a 64-bit little endian integer
_word32ToLittle64( inCiphertextLen, little64 );
err = wc_Poly1305Update( &poly1305Ctx, little64, sizeof( little64 ) );
if( err )
{
return err;
}
// Finalize the auth tag
err = wc_Poly1305Final( &poly1305Ctx, outAuthTag );
return err;
}
static void _word32ToLittle64( const word32 inLittle32, byte outLittle64[8] )
{
ForceZero( outLittle64, 8 );
outLittle64[0] = ( inLittle32 & 0x000000FF );
outLittle64[1] = ( inLittle32 & 0x0000FF00 ) >> 8;
outLittle64[2] = ( inLittle32 & 0x00FF0000 ) >> 16;
outLittle64[3] = ( inLittle32 & 0xFF000000 ) >> 24;
}
static int constantTimeCompare( const byte *a, const byte *b, word32 len )
{
word32 i;
byte result = 0;
for( i = 0; i < len; i++ )
{
result |= a[i] ^ b[i];
}
return (int)result;
}
#endif /* HAVE_CHACHA && HAVE_POLY1305 */

View File

@@ -56,6 +56,7 @@
#include <wolfssl/wolfcrypt/hc128.h> #include <wolfssl/wolfcrypt/hc128.h>
#include <wolfssl/wolfcrypt/rabbit.h> #include <wolfssl/wolfcrypt/rabbit.h>
#include <wolfssl/wolfcrypt/chacha.h> #include <wolfssl/wolfcrypt/chacha.h>
#include <wolfssl/wolfcrypt/chacha20_poly1305.h>
#include <wolfssl/wolfcrypt/pwdbased.h> #include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/ripemd.h> #include <wolfssl/wolfcrypt/ripemd.h>
#include <wolfssl/wolfcrypt/error-crypt.h> #include <wolfssl/wolfcrypt/error-crypt.h>
@@ -2076,114 +2077,258 @@ int poly1305_test(void)
#if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305)
int chacha_poly_test(void) int chacha_poly_test(void)
{ {
// Test #1 from Section 2.8.2 of
// https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305
const byte key[] = { const byte key1[] = {
0x42,0x90,0xbc,0xb1,0x54,0x17,0x35,0x31, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0xf3,0x14,0xaf,0x57,0xf3,0xbe,0x3b,0x50, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x06,0xda,0x37,0x1e,0xce,0x27,0x2a,0xfa, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x1b,0x5d,0xbd,0xd1,0x10,0x0a,0x10,0x07 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
}; };
const byte input[] = { const byte plaintext1[] = {
0x86,0xd0,0x99,0x74,0x84,0x0b,0xde,0xd2, 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
0xa5,0xca 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
0x74, 0x2e
}; };
const byte nonce[] = { const byte iv1[] = {
0x00,0x00,0x00,0x00,0xcd,0x7c,0xf6,0x7b, 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43,
0xe3,0x9c,0x79,0x4a 0x44, 0x45, 0x46, 0x47
}; };
const byte ad[] = { /* aditional data */ const byte aad1[] = { /* additional data */
0x87,0xe2,0x29,0xd4,0x50,0x08,0x45,0xa0, 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
0x79,0xc0,0x0a,0x00,0x00,0x00,0x00,0x00, 0xc4, 0xc5, 0xc6, 0xc7
0x00,0x00
}; };
const byte test[] = { /* expected output from operation */ const byte cipher1[] = { /* expected output from operation */
0xe3,0xe4,0x46,0xf7,0xed,0xe9,0xa1,0x9b, 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
0x62,0xa4,0x98,0xa5,0x9a,0x87,0xf9,0x82, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
0xa1,0xfe,0xcb,0xac,0xd3,0xff,0xe8,0x29, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
0x31,0x04 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
0x61, 0x16
}; };
const byte authTag1[] = { /* expected output from operation */
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
};
byte polyKey[64]; // Test #2 from Appendix A.2 in
byte cipher[32]; // https://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305
byte tag[16]; /* tag made from Poly1305 MAC algorithm */
byte out[48]; /* cipher (32) + tag size of (16) */
byte msg[10]; /* message after decryption */
word32 keySz = 32;
int ret = 0;
ChaCha chaEnc, chaDec; const byte key2[] = {
Poly1305 polyEnc, polyDec; 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
};
XMEMSET(polyKey, 0, sizeof(polyKey)); const byte plaintext2[] = {
XMEMSET(cipher, 0, sizeof(cipher)); 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
XMEMSET(tag, 0, sizeof(tag)); 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20,
XMEMSET(out, 0, sizeof(out)); 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
XMEMSET(msg, 0, sizeof(msg)); 0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69,
0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20,
0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d,
0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65,
0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64,
0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65,
0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61,
0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69,
0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72,
0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20,
0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b,
0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67,
0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
0x9d
};
/***** ENCRYPTION ******/ const byte iv2[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08
};
/* Initialise chacha / poly and get poly key */ const byte aad2[] = { /* additional data */
ret += wc_Chacha_SetKey(&chaEnc, key, keySz); 0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00,
ret += wc_Chacha_SetIV(&chaEnc, nonce, 0); /* start with counter at 0 */ 0x00, 0x00, 0x4e, 0x91
/* AEAD poly key is created by first run of ChaCha */ };
ret += wc_Chacha_Process(&chaEnc, polyKey, polyKey, 64);
ret += wc_Poly1305SetKey(&polyEnc, polyKey, 32);
/* encrypt the plain text then append tag */ const byte cipher2[] = { /* expected output from operation */
ret += wc_Chacha_SetIV(&chaEnc, nonce, 1); 0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4,
ret += wc_Chacha_Process(&chaEnc, cipher, input, sizeof(input)); 0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd,
/* tag is created with using ad and cipher (SSL/TLS uses padding as well) */ 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
ret += wc_Poly1305Update(&polyEnc, ad, sizeof(ad)); 0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2,
ret += wc_Poly1305Update(&polyEnc, cipher, sizeof(input)); 0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee,
ret += wc_Poly1305Final(&polyEnc, tag); 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
XMEMCPY(out, cipher, sizeof(input)); /* copy cipher to first of out */ 0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00,
XMEMCPY(out + sizeof(input), tag, sizeof(tag)); /* append tag to out */ 0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf,
0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81,
0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd,
0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38,
0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4,
0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46,
0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e,
0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e,
0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a,
0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea,
0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99,
0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10,
0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94,
0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf,
0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29,
0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
0x9b
};
const byte authTag2[] = { /* expected output from operation */
0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22,
0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, 0x38
};
/****** TEST *****/ byte generatedCiphertext[272];
byte generatedPlaintext[272];
byte generatedAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE];
int err;
/* encrypted AEAD msg is now in out[] it's length is sizeof input + tag size XMEMSET( generatedCiphertext, 0, sizeof( generatedCiphertext ) );
to test correctness we will compare the out[] to the expected output */ XMEMSET( generatedAuthTag, 0, sizeof( generatedAuthTag ) );
if (memcmp(out, test, sizeof(test))) XMEMSET( generatedPlaintext, 0, sizeof( generatedPlaintext ) );
return -1062;
// Test #1
/****** DECRYPTION ******/ err = wc_ChaCha20Poly1305_Encrypt( key1, iv1,
aad1, sizeof( aad1 ),
plaintext1, sizeof( plaintext1 ),
generatedCiphertext, generatedAuthTag );
if( err )
{
return err;
}
XMEMSET(polyKey, 0, sizeof(polyKey)); // -- Check the ciphertext and authtag
XMEMSET(tag, 0, sizeof(tag));
/* Initialise chacha / poly and get poly key */ if( XMEMCMP( generatedCiphertext, cipher1, sizeof( cipher1 ) ) )
ret += wc_Chacha_SetKey(&chaDec, key, keySz); {
ret += wc_Chacha_SetIV(&chaDec, nonce, 0); /* start with counter at 0 */
/* AEAD poly key is created by first run of ChaCha */
ret += wc_Chacha_Process(&chaDec, polyKey, polyKey, 64);
ret += wc_Poly1305SetKey(&polyDec, polyKey, 32);
/* compare generated tag to what was sent */
ret += wc_Poly1305Update(&polyDec, ad, sizeof(ad));
ret += wc_Poly1305Update(&polyDec, out, sizeof(input)); /* cipher sent */
ret += wc_Poly1305Final(&polyDec, tag);
/* comparison of tags should be in constant time when implemented */
if (memcmp(tag, out + sizeof(input), sizeof(tag))) /* compare tags */
return -1063;
/* decrypt the cipher text */
ret += wc_Chacha_Process(&chaDec, msg, out, sizeof(input));
/****** TEST *****/
/* plain text msg has been recieved compare it to expected for test */
if (memcmp(msg, input, sizeof(input)))
return -1064; return -1064;
}
return ret; if( XMEMCMP( generatedAuthTag, authTag1, sizeof( authTag1 ) ) )
{
return -1065;
}
// -- Verify decryption works
err = wc_ChaCha20Poly1305_Decrypt( key1, iv1,
aad1, sizeof( aad1 ),
cipher1, sizeof( cipher1 ),
authTag1, generatedPlaintext );
if( err )
{
return err;
}
if( XMEMCMP( generatedPlaintext, plaintext1, sizeof( plaintext1 ) ) )
{
return -1066;
}
XMEMSET( generatedCiphertext, 0, sizeof( generatedCiphertext ) );
XMEMSET( generatedAuthTag, 0, sizeof( generatedAuthTag ) );
XMEMSET( generatedPlaintext, 0, sizeof( generatedPlaintext ) );
// Test #2
err = wc_ChaCha20Poly1305_Encrypt( key2, iv2,
aad2, sizeof( aad2 ),
plaintext2, sizeof( plaintext2 ),
generatedCiphertext, generatedAuthTag );
if( err )
{
return err;
}
// -- Check the ciphertext and authtag
if( XMEMCMP( generatedCiphertext, cipher2, sizeof( cipher2 ) ) )
{
return -1067;
}
if( XMEMCMP( generatedAuthTag, authTag2, sizeof( authTag2 ) ) )
{
return -1068;
}
// -- Verify decryption works
err = wc_ChaCha20Poly1305_Decrypt( key2, iv2,
aad2, sizeof( aad2 ),
cipher2, sizeof( cipher2 ),
authTag2, generatedPlaintext );
if( err )
{
return err;
}
if( XMEMCMP( generatedPlaintext, plaintext2, sizeof( plaintext2 ) ) )
{
return -1069;
}
return err;
} }
#endif /* HAVE_CHACHA && HAVE_POLY1305 */ #endif /* HAVE_CHACHA && HAVE_POLY1305 */

View File

@@ -0,0 +1,60 @@
/* chacha20_poly1305.h
*
* Copyright (C) 2006-2015 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if( defined( HAVE_CHACHA ) && defined( HAVE_POLY1305 ) )
#ifndef WOLF_CRYPT_CHACHA20_POLY1305_H
#define WOLF_CRYPT_CHACHA20_POLY1305_H
#include <wolfssl/wolfcrypt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define CHACHA20_POLY1305_AEAD_KEYSIZE 32
#define CHACHA20_POLY1305_AEAD_IV_SIZE 12
#define CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE 16
enum {
CHACHA20_POLY_1305_ENC_TYPE = 8 /* cipher unique type */
};
WOLFSSL_API int wc_ChaCha20Poly1305_Encrypt(const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
const byte* inAAD, const word32 inAADLen,
const byte* inPlaintext, const word32 inPlaintextLen,
byte* outCiphertext,
byte outAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE]);
WOLFSSL_API int wc_ChaCha20Poly1305_Decrypt(const byte inKey[CHACHA20_POLY1305_AEAD_KEYSIZE],
const byte inIV[CHACHA20_POLY1305_AEAD_IV_SIZE],
const byte* inAAD, const word32 inAADLen,
const byte* inCiphertext, const word32 inCiphertextLen,
const byte inAuthTag[CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE],
byte* outPlaintext);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* WOLF_CRYPT_CHACHA20_POLY1305_H */
#endif /* HAVE_CHACHA && HAVE_POLY1305 */

View File

@@ -146,6 +146,8 @@ enum {
THREAD_STORE_KEY_E = -211, /* Thread local storage key create failure */ THREAD_STORE_KEY_E = -211, /* Thread local storage key create failure */
THREAD_STORE_SET_E = -212, /* Thread local storage key set failure */ THREAD_STORE_SET_E = -212, /* Thread local storage key set failure */
MAC_CMP_FAILED_E = -213, /* MAC comparison failed */
MIN_CODE_E = -300 /* errors -101 - -299 */ MIN_CODE_E = -300 /* errors -101 - -299 */
}; };