iPXE
cipher_test.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 /** @file
00027  *
00028  * Cipher self-tests
00029  *
00030  */
00031 
00032 /* Forcibly enable assertions */
00033 #undef NDEBUG
00034 
00035 #include <stdint.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 #include <assert.h>
00039 #include <ipxe/crypto.h>
00040 #include <ipxe/profile.h>
00041 #include <ipxe/test.h>
00042 #include "cipher_test.h"
00043 
00044 /** Number of sample iterations for profiling */
00045 #define PROFILE_COUNT 16
00046 
00047 /**
00048  * Report a cipher encryption test result
00049  *
00050  * @v test              Cipher test
00051  * @v file              Test code file
00052  * @v line              Test code line
00053  */
00054 void cipher_encrypt_okx ( struct cipher_test *test, const char *file,
00055                           unsigned int line ) {
00056         struct cipher_algorithm *cipher = test->cipher;
00057         size_t len = test->len;
00058         uint8_t ctx[cipher->ctxsize];
00059         uint8_t ciphertext[len];
00060 
00061         /* Initialise cipher */
00062         okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
00063               file, line );
00064         cipher_setiv ( cipher, ctx, test->iv );
00065 
00066         /* Perform encryption */
00067         cipher_encrypt ( cipher, ctx, test->plaintext, ciphertext, len );
00068 
00069         /* Compare against expected ciphertext */
00070         okx ( memcmp ( ciphertext, test->ciphertext, len ) == 0, file, line );
00071 }
00072 
00073 /**
00074  * Report a cipher decryption test result
00075  *
00076  * @v test              Cipher test
00077  * @v file              Test code file
00078  * @v line              Test code line
00079  */
00080 void cipher_decrypt_okx ( struct cipher_test *test, const char *file,
00081                           unsigned int line ) {
00082         struct cipher_algorithm *cipher = test->cipher;
00083         size_t len = test->len;
00084         uint8_t ctx[cipher->ctxsize];
00085         uint8_t plaintext[len];
00086 
00087         /* Initialise cipher */
00088         okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0,
00089               file, line );
00090         cipher_setiv ( cipher, ctx, test->iv );
00091 
00092         /* Perform encryption */
00093         cipher_decrypt ( cipher, ctx, test->ciphertext, plaintext, len );
00094 
00095         /* Compare against expected plaintext */
00096         okx ( memcmp ( plaintext, test->plaintext, len ) == 0, file, line );
00097 }
00098 
00099 /**
00100  * Report a cipher encryption and decryption test result
00101  *
00102  * @v test              Cipher test
00103  * @v file              Test code file
00104  * @v line              Test code line
00105  */
00106 void cipher_okx ( struct cipher_test *test, const char *file,
00107                   unsigned int line ) {
00108 
00109         cipher_encrypt_okx ( test, file, line );
00110         cipher_decrypt_okx ( test, file, line );
00111 }
00112 
00113 /**
00114  * Calculate cipher encryption or decryption cost
00115  *
00116  * @v cipher                    Cipher algorithm
00117  * @v key_len                   Length of key
00118  * @v op                        Encryption or decryption operation
00119  * @ret cost                    Cost (in cycles per byte)
00120  */
00121 static unsigned long
00122 cipher_cost ( struct cipher_algorithm *cipher, size_t key_len,
00123               void ( * op ) ( struct cipher_algorithm *cipher, void *ctx,
00124                               const void *src, void *dst, size_t len ) ) {
00125         static uint8_t random[8192]; /* Too large for stack */
00126         uint8_t key[key_len];
00127         uint8_t iv[cipher->blocksize];
00128         uint8_t ctx[cipher->ctxsize];
00129         struct profiler profiler;
00130         unsigned long cost;
00131         unsigned int i;
00132         int rc;
00133 
00134         /* Fill buffer with pseudo-random data */
00135         srand ( 0x1234568 );
00136         for ( i = 0 ; i < sizeof ( random ) ; i++ )
00137                 random[i] = rand();
00138         for ( i = 0 ; i < sizeof ( key ) ; i++ )
00139                 key[i] = rand();
00140         for ( i = 0 ; i < sizeof ( iv ) ; i++ )
00141                 iv[i] = rand();
00142 
00143         /* Initialise cipher */
00144         rc = cipher_setkey ( cipher, ctx, key, key_len );
00145         assert ( rc == 0 );
00146         cipher_setiv ( cipher, ctx, iv );
00147 
00148         /* Profile cipher operation */
00149         memset ( &profiler, 0, sizeof ( profiler ) );
00150         for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
00151                 profile_start ( &profiler );
00152                 op ( cipher, ctx, random, random, sizeof ( random ) );
00153                 profile_stop ( &profiler );
00154         }
00155 
00156         /* Round to nearest whole number of cycles per byte */
00157         cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) /
00158                  sizeof ( random ) );
00159 
00160         return cost;
00161 }
00162 
00163 /**
00164  * Calculate cipher encryption cost
00165  *
00166  * @v cipher                    Cipher algorithm
00167  * @v key_len                   Length of key
00168  * @ret cost                    Cost (in cycles per byte)
00169  */
00170 unsigned long cipher_cost_encrypt ( struct cipher_algorithm *cipher,
00171                                     size_t key_len ) {
00172         return cipher_cost ( cipher, key_len, cipher_encrypt );
00173 }
00174 
00175 /**
00176  * Calculate cipher decryption cost
00177  *
00178  * @v cipher                    Cipher algorithm
00179  * @v key_len                   Length of key
00180  * @ret cost                    Cost (in cycles per byte)
00181  */
00182 unsigned long cipher_cost_decrypt ( struct cipher_algorithm *cipher,
00183                                     size_t key_len ) {
00184         return cipher_cost ( cipher, key_len, cipher_decrypt );
00185 }