david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

[test] Generalise cipher tests and use okx()

Generalise the existing support for performing CBC-mode block cipher
tests, and update the code to use okx() for neater reporting of test
results.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown 2015-07-27 14:00:57 +01:00
parent 69891db8e2
commit c0be4c6861
5 changed files with 192 additions and 213 deletions

View File

@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* AES-in-CBC-mode tests
* AES tests
*
* These test vectors are provided by NIST as part of the
* Cryptographic Toolkit Examples, downloadable from:
@ -41,88 +41,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/aes.h>
#include <ipxe/test.h>
#include "cbc_test.h"
#include "cipher_test.h"
/** Define inline key */
#define KEY(...) { __VA_ARGS__ }
/** Define inline initialisation vector */
#define IV(...) { __VA_ARGS__ }
/** Define inline plaintext data */
#define PLAINTEXT(...) { __VA_ARGS__ }
/** Define inline ciphertext data */
#define CIPHERTEXT(...) { __VA_ARGS__ }
/** An AES-in-CBC-mode test */
struct aes_cbc_test {
/** Key */
const void *key;
/** Length of key */
size_t key_len;
/** Initialisation vector */
const void *iv;
/** Length of initialisation vector */
size_t iv_len;
/** Plaintext */
const void *plaintext;
/** Length of plaintext */
size_t plaintext_len;
/** Ciphertext */
const void *ciphertext;
/** Length of ciphertext */
size_t ciphertext_len;
};
/**
* Define an AES-in-CBC-mode test
*
* @v name Test name
* @v key_array Key
* @v iv_array Initialisation vector
* @v plaintext_array Plaintext
* @v ciphertext_array Ciphertext
* @ret test AES-in-CBC-mode test
*/
#define AES_CBC_TEST( name, key_array, iv_array, plaintext_array, \
ciphertext_array ) \
static const uint8_t name ## _key [] = key_array; \
static const uint8_t name ## _iv [] = iv_array; \
static const uint8_t name ## _plaintext [] = plaintext_array; \
static const uint8_t name ## _ciphertext [] = ciphertext_array; \
static struct aes_cbc_test name = { \
.key = name ## _key, \
.key_len = sizeof ( name ## _key ), \
.iv = name ## _iv, \
.iv_len = sizeof ( name ## _iv ), \
.plaintext = name ## _plaintext, \
.plaintext_len = sizeof ( name ## _plaintext ), \
.ciphertext = name ## _ciphertext, \
.ciphertext_len = sizeof ( name ## _ciphertext ), \
}
/**
* Report AES-in-CBC-mode
*
* @v state HMAC_DRBG internal state
* @v test Instantiation test
*/
#define aes_cbc_ok( test ) do { \
struct cipher_algorithm *cipher = &aes_cbc_algorithm; \
\
assert ( (test)->iv_len == cipher->blocksize ); \
assert ( (test)->plaintext_len == (test)->ciphertext_len ); \
cbc_encrypt_ok ( cipher, (test)->key, (test)->key_len, \
(test)->iv, (test)->plaintext, \
(test)->ciphertext, (test)->plaintext_len ); \
cbc_decrypt_ok ( cipher, (test)->key, (test)->key_len, \
(test)->iv, (test)->ciphertext, \
(test)->plaintext, (test)->ciphertext_len ); \
} while ( 0 )
/** CBC_AES128 */
AES_CBC_TEST ( test_128,
/** AES-128-CBC */
CIPHER_TEST ( aes_128_cbc, &aes_cbc_algorithm,
KEY ( 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15,
0x88, 0x09, 0xcf, 0x4f, 0x3c ),
IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
@ -144,8 +66,8 @@ AES_CBC_TEST ( test_128,
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09,
0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) );
/** CBC_AES256 */
AES_CBC_TEST ( test_256,
/** AES-256-CBC */
CIPHER_TEST ( aes_256_cbc, &aes_cbc_algorithm,
KEY ( 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61,
0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ),
@ -169,29 +91,28 @@ AES_CBC_TEST ( test_256,
0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) );
/**
* Perform AES-in-CBC-mode self-test
* Perform AES self-test
*
*/
static void aes_cbc_test_exec ( void ) {
struct cipher_algorithm *cipher = &aes_cbc_algorithm;
static void aes_test_exec ( void ) {
struct cipher_algorithm *cbc = &aes_cbc_algorithm;
unsigned int keylen;
/* Correctness tests */
aes_cbc_ok ( &test_128 );
aes_cbc_ok ( &test_256 );
cipher_ok ( &aes_128_cbc );
cipher_ok ( &aes_256_cbc );
/* Speed tests */
DBG ( "AES128 encryption required %ld cycles per byte\n",
cbc_cost_encrypt ( cipher, test_128.key_len ) );
DBG ( "AES128 decryption required %ld cycles per byte\n",
cbc_cost_decrypt ( cipher, test_128.key_len ) );
DBG ( "AES256 encryption required %ld cycles per byte\n",
cbc_cost_encrypt ( cipher, test_256.key_len ) );
DBG ( "AES256 decryption required %ld cycles per byte\n",
cbc_cost_decrypt ( cipher, test_256.key_len ) );
for ( keylen = 128 ; keylen <= 256 ; keylen += 128 ) {
DBG ( "AES-%d-CBC encryption required %ld cycles per byte\n",
keylen, cipher_cost_encrypt ( cbc, ( keylen / 8 ) ) );
DBG ( "AES-%d-CBC decryption required %ld cycles per byte\n",
keylen, cipher_cost_decrypt ( cbc, ( keylen / 8 ) ) );
}
}
/** AES-in-CBC-mode self-test */
struct self_test aes_cbc_test __self_test = {
.name = "aes_cbc",
.exec = aes_cbc_test_exec,
/** AES self-test */
struct self_test aes_test __self_test = {
.name = "aes",
.exec = aes_test_exec,
};

View File

@ -1,57 +0,0 @@
#ifndef _CBC_TEST_H
#define _CBC_TEST_H
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/test.h>
extern int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
size_t key_len, const void *iv,
const void *plaintext,
const void *expected_ciphertext, size_t len );
extern int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
size_t key_len, const void *iv,
const void *ciphertext,
const void *expected_plaintext, size_t len );
extern unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
size_t key_len );
extern unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
size_t key_len );
/**
* Report CBC encryption test result
*
* @v cipher Cipher algorithm
* @v key Key
* @v key_len Length of key
* @v iv Initialisation vector
* @v plaintext Plaintext data
* @v expected_ciphertext Expected ciphertext data
* @v len Length of data
*/
#define cbc_encrypt_ok( cipher, key, key_len, iv, plaintext, \
expected_ciphertext, len ) do { \
ok ( cbc_test_encrypt ( cipher, key, key_len, iv, plaintext, \
expected_ciphertext, len ) ); \
} while ( 0 )
/**
* Report CBC decryption test result
*
* @v cipher Cipher algorithm
* @v key Key
* @v key_len Length of key
* @v iv Initialisation vector
* @v ciphertext Ciphertext data
* @v expected_plaintext Expected plaintext data
* @v len Length of data
*/
#define cbc_decrypt_ok( cipher, key, key_len, iv, ciphertext, \
expected_plaintext, len ) do { \
ok ( cbc_test_decrypt ( cipher, key, key_len, iv, ciphertext, \
expected_plaintext, len ) ); \
} while ( 0 )
#endif /* _CBC_TEST_H */

View File

@ -25,7 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* CBC self-tests
* Cipher self-tests
*
*/
@ -38,86 +38,90 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <ipxe/crypto.h>
#include <ipxe/profile.h>
#include "cbc_test.h"
#include <ipxe/test.h>
#include "cipher_test.h"
/** Number of sample iterations for profiling */
#define PROFILE_COUNT 16
/**
* Test CBC encryption
* Report a cipher encryption test result
*
* @v cipher Cipher algorithm
* @v key Key
* @v key_len Length of key
* @v iv Initialisation vector
* @v plaintext Plaintext data
* @v expected_ciphertext Expected ciphertext data
* @v len Length of data
* @ret ok Ciphertext is as expected
* @v test Cipher test
* @v file Test code file
* @v line Test code line
*/
int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key,
size_t key_len, const void *iv, const void *plaintext,
const void *expected_ciphertext, size_t len ) {
void cipher_encrypt_okx ( struct cipher_test *test, const char *file,
unsigned int line ) {
struct cipher_algorithm *cipher = test->cipher;
size_t len = test->len;
uint8_t ctx[cipher->ctxsize];
uint8_t ciphertext[len];
int rc;
/* Initialise cipher */
rc = cipher_setkey ( cipher, ctx, key, key_len );
assert ( rc == 0 );
cipher_setiv ( cipher, ctx, iv );
okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
file, line );
cipher_setiv ( cipher, ctx, test->iv );
/* Perform encryption */
cipher_encrypt ( cipher, ctx, plaintext, ciphertext, len );
cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len );
/* Verify result */
return ( memcmp ( ciphertext, expected_ciphertext, len ) == 0 );
/* Compare against expected ciphertext */
okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line );
}
/**
* Test CBC decryption
* Report a cipher decryption test result
*
* @v cipher Cipher algorithm
* @v key Key
* @v key_len Length of key
* @v iv Initialisation vector
* @v ciphertext Ciphertext data
* @v expected_plaintext Expected plaintext data
* @v len Length of data
* @ret ok Plaintext is as expected
* @v test Cipher test
* @v file Test code file
* @v line Test code line
*/
int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key,
size_t key_len, const void *iv, const void *ciphertext,
const void *expected_plaintext, size_t len ) {
void cipher_decrypt_okx ( struct cipher_test *test, const char *file,
unsigned int line ) {
struct cipher_algorithm *cipher = test->cipher;
size_t len = test->len;
uint8_t ctx[cipher->ctxsize];
uint8_t plaintext[len];
int rc;
/* Initialise cipher */
rc = cipher_setkey ( cipher, ctx, key, key_len );
assert ( rc == 0 );
cipher_setiv ( cipher, ctx, iv );
okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
file, line );
cipher_setiv ( cipher, ctx, test->iv );
/* Perform encryption */
cipher_decrypt ( cipher, ctx, ciphertext, plaintext, len );
cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len );
/* Verify result */
return ( memcmp ( plaintext, expected_plaintext, len ) == 0 );
/* Compare against expected plaintext */
okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line );
}
/**
* Calculate CBC encryption or decryption cost
* Report a cipher encryption and decryption test result
*
* @v test Cipher test
* @v file Test code file
* @v line Test code line
*/
void cipher_okx ( struct cipher_test *test, const char *file,
unsigned int line ) {
cipher_encrypt_okx ( test, file, line );
cipher_decrypt_okx ( test, file, line );
}
/**
* Calculate cipher encryption or decryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @v op Encryption or decryption operation
* @ret cost Cost (in cycles per byte)
*/
static unsigned long cbc_cost ( struct cipher_algorithm *cipher,
size_t key_len,
void ( * op ) ( struct cipher_algorithm *cipher,
void *ctx, const void *src,
void *dst, size_t len ) ) {
static unsigned long
cipher_cost ( struct cipher_algorithm *cipher, size_t key_len,
void ( * op ) ( struct cipher_algorithm *cipher, void *ctx,
const void *src, void *dst, size_t len ) ) {
static uint8_t random[8192]; /* Too large for stack */
uint8_t key[key_len];
uint8_t iv[cipher->blocksize];
@ -157,25 +161,25 @@ static unsigned long cbc_cost ( struct cipher_algorithm *cipher,
}
/**
* Calculate CBC encryption cost
* Calculate cipher encryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @ret cost Cost (in cycles per byte)
*/
unsigned long cbc_cost_encrypt ( struct cipher_algorithm *cipher,
size_t key_len ) {
return cbc_cost ( cipher, key_len, cipher_encrypt );
unsigned long cipher_cost_encrypt ( struct cipher_algorithm *cipher,
size_t key_len ) {
return cipher_cost ( cipher, key_len, cipher_encrypt );
}
/**
* Calculate CBC decryption cost
* Calculate cipher decryption cost
*
* @v cipher Cipher algorithm
* @v key_len Length of key
* @ret cost Cost (in cycles per byte)
*/
unsigned long cbc_cost_decrypt ( struct cipher_algorithm *cipher,
size_t key_len ) {
return cbc_cost ( cipher, key_len, cipher_decrypt );
unsigned long cipher_cost_decrypt ( struct cipher_algorithm *cipher,
size_t key_len ) {
return cipher_cost ( cipher, key_len, cipher_decrypt );
}

111
src/tests/cipher_test.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef _CIPHER_TEST_H
#define _CIPHER_TEST_H
/** @file
*
* Cipher self-tests
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/test.h>
/** A cipher test */
struct cipher_test {
/** Cipher algorithm */
struct cipher_algorithm *cipher;
/** Key */
const void *key;
/** Length of key */
size_t key_len;
/** Initialisation vector */
const void *iv;
/** Length of initialisation vector */
size_t iv_len;
/** Plaintext */
const void *plaintext;
/** Ciphertext */
const void *ciphertext;
/** Length of text */
size_t len;
};
/** Define inline key */
#define KEY(...) { __VA_ARGS__ }
/** Define inline initialisation vector */
#define IV(...) { __VA_ARGS__ }
/** Define inline plaintext data */
#define PLAINTEXT(...) { __VA_ARGS__ }
/** Define inline ciphertext data */
#define CIPHERTEXT(...) { __VA_ARGS__ }
/**
* Define a cipher test
*
* @v name Test name
* @v CIPHER Cipher algorithm
* @v KEY Key
* @v IV Initialisation vector
* @v PLAINTEXT Plaintext
* @v CIPHERTEXT Ciphertext
* @ret test Cipher test
*/
#define CIPHER_TEST( name, CIPHER, KEY, IV, PLAINTEXT, CIPHERTEXT ) \
static const uint8_t name ## _key [] = KEY; \
static const uint8_t name ## _iv [] = IV; \
static const uint8_t name ## _plaintext [] = PLAINTEXT; \
static const uint8_t name ## _ciphertext \
[ sizeof ( name ## _plaintext ) ] = CIPHERTEXT; \
static struct cipher_test name = { \
.cipher = CIPHER, \
.key = name ## _key, \
.key_len = sizeof ( name ## _key ), \
.iv = name ## _iv, \
.iv_len = sizeof ( name ## _iv ), \
.plaintext = name ## _plaintext, \
.ciphertext = name ## _ciphertext, \
.len = sizeof ( name ## _plaintext ), \
}
extern void cipher_encrypt_okx ( struct cipher_test *test, const char *file,
unsigned int line );
extern void cipher_decrypt_okx ( struct cipher_test *test, const char *file,
unsigned int line );
extern void cipher_okx ( struct cipher_test *test, const char *file,
unsigned int line );
extern unsigned long cipher_cost_encrypt ( struct cipher_algorithm *cipher,
size_t key_len );
extern unsigned long cipher_cost_decrypt ( struct cipher_algorithm *cipher,
size_t key_len );
/**
* Report a cipher encryption test result
*
* @v test Cipher test
*/
#define cipher_encrypt_ok( test ) \
cipher_encrypt_okx ( test, __FILE__, __LINE__ )
/**
* Report a cipher decryption test result
*
* @v test Cipher test
*/
#define cipher_decrypt_ok( test ) \
cipher_decrypt_okx ( test, __FILE__, __LINE__ )
/**
* Report a cipher encryption and decryption test result
*
* @v test Cipher test
*/
#define cipher_ok( test ) \
cipher_okx ( test, __FILE__, __LINE__ )
#endif /* _CIPHER_TEST_H */

View File

@ -50,7 +50,7 @@ REQUIRE_OBJECT ( md5_test );
REQUIRE_OBJECT ( sha1_test );
REQUIRE_OBJECT ( sha256_test );
REQUIRE_OBJECT ( sha512_test );
REQUIRE_OBJECT ( aes_cbc_test );
REQUIRE_OBJECT ( aes_test );
REQUIRE_OBJECT ( hmac_drbg_test );
REQUIRE_OBJECT ( hash_df_test );
REQUIRE_OBJECT ( bigint_test );