📄 gentest.c
字号:
/*
---------------------------------------------------------------------------
Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 13/10/2006
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#define cstr_cmp _strnicmp
#if 0
# define TEST_CCM
#endif
#if 0
# define TEST_GCM
#endif
#if 0
# define TEST_EAX
#endif
#if 1
# define GEN_TEST
#endif
#include "aes.h"
#include "ccm.h"
#include "ltc_ccm.h"
#include "gcm.h"
#include "ltc_gcm.h"
#include "eax.h"
#include "ltc_eax.h"
#define LTC_ENCRYPT 0
#define LTC_DECRYPT 1
typedef ret_type (*brg_i)(
const unsigned char key[],
unsigned long key_len,
void *ctx );
typedef ret_type (*brg_f)(
const unsigned char iv[], unsigned long iv_len,
const unsigned char hdr[], unsigned long hdr_len,
unsigned char msg[], unsigned long msg_len,
unsigned char tag[], unsigned long tag_len,
void *ctx );
typedef int (*ltc_f)(
const unsigned char key[], unsigned long key_len,
const unsigned char nonce[], unsigned long nonce_len,
const unsigned char hdr[], unsigned long hdr_len,
unsigned char pt[], unsigned long pt_len,
unsigned char ct[],
unsigned char tag[], unsigned long tag_len,
int dir, int *stat );
struct
{ brg_i brg_ifun[3];
brg_f brg_efun[3];
brg_f brg_dfun[3];
ltc_f ltc_fun[3];
} ea_funs =
{ { ccm_init_and_key, gcm_init_and_key, eax_init_and_key },
{ ccm_encrypt_message, gcm_encrypt_message, eax_encrypt_message },
{ ccm_decrypt_message, gcm_decrypt_message, eax_decrypt_message },
{ ccm_memory, gcm_memory, eax_memory }
} ;
typedef enum mode { m_ccm = 0, m_gcm = 1, m_eax = 2 };
char *mode_name[] = { "CCM", "GCM", "EAX" };
typedef union
{
ccm_ctx ccm[1];
gcm_ctx gcm[1];
eax_ctx eax[1];
} ctx_union;
char *rem =
"\nREM All vectors are arrays of 8-bit bytes (octets) that are indexed"
"\nREM from zero on the left with indexes that increase by 1 from left"
"\nREM to right for each pair of hexadecimal digits. Consecutive lines"
"\nREM with the same initial line designators are concatenated so that"
"\nREM array elements on later lines have higher indexes. The symbols"
"\nREM '0' to '9 and 'a' to 'f', in this order, specify numeric values"
"\nREM of 0 to 15 respectively with the left digit of each pair having"
"\nREM higher numeric significance. Numeric significance is undefined"
"\nREM except between the hexadecimal digits within individual bytes."
"\n"
"\nREM KEY = The AES key"
"\nREM NCE = The nonce"
"\nREM HDR = The header data"
"\nREM PTX = The plaintext data"
"\nREM CTX = The ciphertext data"
"\nREM TAG = The tag value\n";
/* The following definitions describe the different lines that can occur
in test vector files. Each line starts with a four character line
designator in which the last character is a space (which must be
present). Some lines are commands (e.g GEN means generate a test
vector) while others specify the values of inputs (e.g. KEY gives the
value of the key to be used) while others (e.g. CTX and TAG) give the
expected value of outputs. In the list of sequence designators, inputs
follow outputs and inputs are listed with the values that vary slowly
between suquential test vectors before those that vary more rapidly.
*/
enum des_type { KEY = 0, NCE, HDR, PTX, CTX, TAG, /* sequence values */
VEC = 16, GEN, END, NUL, ERR }; /* non-sequence values */
/* Input sequence designators are listed first with the most slowly
varying values earlier in the list. Then output values are listed,
followed by other values such as commands and aliases (e.g. IV is
an alias for NCE).
*/
char *des_name[] = { "KEY ", "NCE ", "HDR ", "PTX ", "CTX ", "TAG ", "IV ", "VEC ", "GEN ", "END " };
enum des_type des_m[] = { KEY , NCE , HDR , PTX , CTX , TAG , NCE , VEC , GEN , END };
/* Find if a line starts with a recognised line designator and
return its descriptor if it does or ERR if not.
*/
enum des_type find_des(char *s, char **cptr)
{ size_t i = strlen(s);
while( i && (s[i - 1] < ' ' || s[i - 1] > '\x7e') )
--i;
s[i] = '\0';
if( i == 0 )
return NUL;
for(i = 0; i < sizeof(des_name) / sizeof(des_name[0]); ++i)
if(!strncmp(des_name[i], s, strlen(des_name[i])))
{
*cptr = s + strlen(des_name[i]);
return des_m[i];
}
return ERR;
}
/* input a decimal number from a C string */
char *decimal_in(char *s, long long int *n)
{
int g = -1;
*n = 0;
if(*s == '-')
++s;
else
g = 1;
while( isdigit( *s ) )
*n = 10 * *n + g * (*s++ - '0');
return s;
}
int to_hex(char ch)
{
return (isdigit(ch) ? 0 : 9) + (ch & 0x0f);
}
/* input a hexadecimal number from a C string */
char *hexadecimal_in(char *s, long long int *n)
{
*n = 0;
while( isxdigit( *s ) )
*n = (*n << 4) + to_hex(*s++);
return s;
}
/* input an 8-bit byte from two charcters in a C string */
char *hexbyte_in(char *s, unsigned char *n)
{
if( isxdigit( *s) && isxdigit( *(s + 1) ) )
{
*n = (to_hex(*s) << 4) | to_hex(*(s + 1));
return s + 2;
}
else
return 0;
}
/* output a byte array preceeded by a descriptor */
void hex_out( FILE *f, char *desc, unsigned char buf[], unsigned int len )
{ unsigned int i;
if( len == 0 )
fprintf(f, "\n%s", desc);
else
for(i = 0; i < len; ++i)
{
if(i % 32 == 0)
fprintf(f, "\n%s", desc);
fprintf(f, "%02x", buf[i]);
}
}
uint_64t bytes_to_number(unsigned char x[], int len)
{ uint_64t t = 0;
while(len--)
t = 256 * t + x[len];
return t;
}
/* AES based random number generator */
static unsigned char key[16] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 2, 3, 8, 4 };
static unsigned char rnd[16] = { 2, 7, 1, 8, 2, 8, 1, 8, 2, 8, 4, 5, 9, 0, 4, 5 };
static aes_encrypt_ctx ctx[1];
static int r_cnt = -1; /* initialised negative to trigger AES keying */
void rand_update(void)
{
if( r_cnt < 0 )
aes_encrypt_key( key, 16, ctx );
/* OFB stream cipher for randomness */
aes_encrypt( rnd, rnd, ctx );
/* number of valid random bytes in buffer */
r_cnt = 16;
return;
}
/* return one pseudo random byte */
unsigned char rand8(void)
{
if(r_cnt <= 0)
rand_update();
return rnd[--r_cnt];
}
/* fill a byte array with pseudo random values */
void block_rndfill(unsigned char l[], unsigned long len)
{ unsigned long i;
for(i = 0; i < len; ++i)
l[i] = rand8();
}
#define MAX_BLOCK_SIZE 16 * 256 /* 4096 byte limit on blocks */
void do_test( unsigned int ntests, enum mode mm )
{
unsigned char key[2 * AES_BLOCK_SIZE]; /* the AES key */
unsigned char iv[MAX_BLOCK_SIZE]; /* the nonce */
unsigned char hdr[MAX_BLOCK_SIZE]; /* the header */
unsigned char ptx[MAX_BLOCK_SIZE]; /* the plaintext */
unsigned char ctx[2][MAX_BLOCK_SIZE]; /* BRG and LTC ciphertexts */
unsigned char res[2][MAX_BLOCK_SIZE]; /* BRG and LTC decrypts */
unsigned char tag[2][AES_BLOCK_SIZE]; /* BRG and LTC tags */
unsigned int i, key_len = AES_BLOCK_SIZE, iv_len, hdr_len, msg_len,
err = 0, err1, stat;
ctx_union context[1];
err1 = RETURN_OK;
for( i = 0; i < ntests; ++i )
{
/* the mode key value */
block_rndfill( key, 16 );
/* the iv/nonce value */
block_rndfill( (unsigned char*)&iv_len, 4 );
iv_len &= 0x1fff;
/* adjust for nonce format variations */
switch(mm)
{
case m_ccm:
iv_len = 6 + (iv_len & 7);
iv_len = ( iv_len < 7 ? 7 : iv_len );
break;
case m_gcm:
iv_len &= 0x1fff;
iv_len = (iv_len & 0x1000 ? 12 : iv_len);
break;
case m_eax:
iv_len &= 0x1fff;
iv_len = (iv_len & 0x1000 ? iv_len & 0x001f : iv_len);
}
block_rndfill( iv, iv_len );
/* the authenticated header */
block_rndfill( (unsigned char*)&hdr_len, 4 );
hdr_len &= 0x1fff;
/* half messages have no headers */
hdr_len = ( hdr_len & 0x1000 ? 0 : hdr_len );
block_rndfill( hdr, hdr_len );
/* the plaintext message */
block_rndfill( (unsigned char*)&msg_len, 4 );
msg_len &= 0x0fff;
block_rndfill( ptx, msg_len );
/* initialise BRG version */
ea_funs.brg_ifun[mm](key, key_len, context);
memcpy( ctx[0], ptx, msg_len );
/* encrypt and authenticate for BRG version*/
ea_funs.brg_efun[mm](iv, iv_len, hdr, hdr_len, ctx[0],
msg_len, tag[0], AES_BLOCK_SIZE, context );
/* initialise BRG version */
ea_funs.brg_ifun[mm]( key, key_len, context );
memcpy( res[0], ctx[0], msg_len );
/* decrypt and verify for BRG version*/
err = ea_funs.brg_dfun[mm]( iv, iv_len, hdr, hdr_len, res[0],
msg_len, tag[0], AES_BLOCK_SIZE, context );
/* encrypt and authenticate for LTC version*/
ea_funs.ltc_fun[mm]( key, key_len, iv, iv_len, hdr, hdr_len,
ptx, msg_len, ctx[1], tag[1], AES_BLOCK_SIZE, LTC_ENCRYPT, 0);
/* decrypt and verify for BRG version*/
ea_funs.ltc_fun[mm]( key, key_len, iv, iv_len, hdr, hdr_len,
res[1], msg_len, ctx[1], tag[1], AES_BLOCK_SIZE, LTC_DECRYPT, &stat);
if(memcmp(ptx, res[0], msg_len))
{
printf("\n%s: (BRG) encryption or decryption error", mode_name[mm]);
err1 = RETURN_ERROR;
}
if(err != RETURN_OK)
{
printf("\n%s: (BRG) tag error", mode_name[mm]);
err1 = RETURN_ERROR;
}
if(memcmp(ptx, res[1], msg_len))
{
printf("\n%s: (LTC) encryption or decryption error", mode_name[mm]);
err1 = RETURN_ERROR;
}
if(stat != RETURN_OK)
{
printf("\n%s: (LTC) tag error", mode_name[mm]);
err1 = RETURN_ERROR;
}
if(memcmp(ctx[0], ctx[1], msg_len))
{
printf("\n%s: ciphertext mismatch error", mode_name[mm]);
err1 = RETURN_ERROR;
}
if(memcmp(tag[0], tag[1], AES_BLOCK_SIZE))
{
printf("\n%s: tag mismatch error", mode_name[mm]);
err1 = RETURN_ERROR;
}
}
if(err1 == RETURN_OK)
{
printf("\n%s: (BRG) and (LTC) outputs match", mode_name[mm]);
}
}
/* This structure accumulates the character strings for each specific
line designator in a test vector template. The values are accumulated
in the dynamically allocated C string pointed to by rp. It also
records the position in this string while p;arsing it (pos) and
numerical values obtained as a result (cnt[6]). The number of values
obtained, up to five, is set in cnt[0]
*/
typedef struct
{
char *rp;
unsigned int len;
unsigned int pos;
long long int cnt[6];
} v_rec;
void add_to_record( v_rec *v, char *c)
{ char *cp = c + strlen(c) - 1;
/* remove extraneous characters at end of input */
while( *cp <= 0x20 || *cp >= 0x7f )
--cp;
*(cp + 1) = '\0';
if(*c == '\0' )
return;
/* if a string has not been allocated or it has but is not long enough */
if( !v->rp || v->len < strlen( v->rp ) + strlen( c ) + 1 )
{ char *p;
/* set a new maximum length and allocate a new string */
v->len = ( v->rp ? (unsigned int)strlen( v->rp ) : 0 ) + (unsigned int)strlen( c ) + 80;
p = malloc( v->len );
*p = '\0';
/* if necessary copy old content into it */
if( v-> rp)
{
strcpy( p, v->rp );
free( v-> rp );
}
v->rp = p;
}
/* if there is content in the string and the new value is not a */
/* continuation of a hexadecimal sequence, insert a comma */
if( *(v->rp) && *c != ',' && v->rp[strlen( v->rp ) - 1 ] != ',' &&
(!isxdigit( v->rp[strlen( v->rp ) - 1] ) || !isxdigit( *c )) )
strcat( v->rp, "," );
/* add the new content */
strcat( v->rp, c );
}
/* input strings are comma separated values which are either hexadecimal
sequences or 'bracket terms' consisting of up to five comma separated
numericall values within brackets. This routine parses the latter
bracket terms and puts the number of values obtained in cnt[0] and
the values in cnt[1] .. cnt[5]. Numbers are hexadecimal unless they
are preceeded by a '#', in which case they are decimal.
*/
int get_loop_vars( char **cp, long long int cnt[], int hex_flag )
{ char *p = *cp;
int i, retv = 0;
/* remove any leading space */
while(*p && ( *p == ' ' || *p == '\t' ) )
++p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -