@ -28,49 +28,87 @@
# include <hash.h>
# include <sha1.h>
# include <sha256.h>
# include <asm/io.h>
/*
* These are the hash algorithms we support . Chips which support accelerated
* crypto could perhaps add named version of these algorithms here .
* crypto could perhaps add named version of these algorithms here . Note that
* algorithm names must be in lower case .
*/
static struct hash_algo hash_algo [ ] = {
# ifdef CONFIG_SHA1
/*
* This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise
* it bloats the code for boards which use SHA1 but not the ' hash '
* or ' sha1sum ' commands .
*/
# ifdef CONFIG_CMD_SHA1SUM
{
" SHA1 " ,
" sha 1" ,
SHA1_SUM_LEN ,
sha1_csum_wd ,
CHUNKSZ_SHA1 ,
} ,
# define MULTI_HASH
# endif
# ifdef CONFIG_SHA256
{
" SHA 256" ,
" sha 256" ,
SHA256_SUM_LEN ,
sha256_csum_wd ,
CHUNKSZ_SHA256 ,
} ,
# define MULTI_HASH
# endif
{
" crc32 " ,
4 ,
crc32_wd_buf ,
CHUNKSZ_CRC32 ,
} ,
} ;
# if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH)
# define MULTI_HASH
# endif
/* Try to minimize code size for boards that don't want much hashing */
# ifdef MULTI_HASH
# define multi_hash() 1
# else
# define multi_hash() 0
# endif
/**
* store_result : Store the resulting sum to an address or variable
*
* @ algo : Hash algorithm being used
* @ sum : Hash digest ( algo - > digest_size bytes )
* @ dest : Destination , interpreted as a hex address if it starts
* with * or otherwise as an environment variable .
* with * ( or allow_env_vars is 0 ) or otherwise as an
* environment variable .
* @ allow_env_vars : non - zero to permit storing the result to an
* variable environment
*/
static void store_result ( struct hash_algo * algo , const u8 * sum ,
const char * dest )
const char * dest , int allow_env_vars )
{
unsigned int i ;
int env_var = 0 ;
if ( * dest = = ' * ' ) {
u8 * ptr ;
/*
* If environment variables are allowed , then we assume that ' dest '
* is an environment variable , unless it starts with * , in which
* case we assume it is an address . If not allowed , it is always an
* address . This is to support the crc32 command .
*/
if ( allow_env_vars ) {
if ( * dest = = ' * ' )
dest + + ;
else
env_var = 1 ;
}
ptr = ( u8 * ) simple_strtoul ( dest + 1 , NULL , 16 ) ;
memcpy ( ptr , sum , algo - > digest_size ) ;
} else {
if ( env_var ) {
char str_output [ HASH_MAX_DIGEST_SIZE * 2 + 1 ] ;
char * str_ptr = str_output ;
@ -80,6 +118,14 @@ static void store_result(struct hash_algo *algo, const u8 *sum,
}
str_ptr = ' \0 ' ;
setenv ( dest , str_output ) ;
} else {
ulong addr ;
void * buf ;
addr = simple_strtoul ( dest , NULL , 16 ) ;
buf = map_sysmem ( addr , algo - > digest_size ) ;
memcpy ( buf , sum , algo - > digest_size ) ;
unmap_sysmem ( buf ) ;
}
}
@ -94,15 +140,31 @@ static void store_result(struct hash_algo *algo, const u8 *sum,
* Otherwise we assume it is an environment variable , and
* look up its value ( it must contain a hex digest ) .
* @ vsum : Returns binary digest value ( algo - > digest_size bytes )
* @ allow_env_vars : non - zero to permit storing the result to an environment
* variable . If 0 then verify_str is assumed to be an
* address , and the * prefix is not expected .
* @ return 0 if ok , non - zero on error
*/
static int parse_verify_sum ( struct hash_algo * algo , char * verify_str , u8 * vsum )
static int parse_verify_sum ( struct hash_algo * algo , char * verify_str , u8 * vsum ,
int allow_env_vars )
{
if ( * verify_str = = ' * ' ) {
u8 * ptr ;
int env_var = 0 ;
/* See comment above in store_result() */
if ( allow_env_vars ) {
if ( * verify_str = = ' * ' )
verify_str + + ;
else
env_var = 1 ;
}
ptr = ( u8 * ) simple_strtoul ( verify_str + 1 , NULL , 16 ) ;
memcpy ( vsum , ptr , algo - > digest_size ) ;
if ( env_var ) {
ulong addr ;
void * buf ;
addr = simple_strtoul ( verify_str , NULL , 16 ) ;
buf = map_sysmem ( addr , algo - > digest_size ) ;
memcpy ( vsum , buf , algo - > digest_size ) ;
} else {
unsigned int i ;
char * vsum_str ;
@ -141,7 +203,7 @@ static struct hash_algo *find_hash_algo(const char *name)
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( hash_algo ) ; i + + ) {
if ( ! strcasec mp ( name , hash_algo [ i ] . name ) )
if ( ! strcmp ( name , hash_algo [ i ] . name ) )
return & hash_algo [ i ] ;
}
@ -158,63 +220,87 @@ static void show_hash(struct hash_algo *algo, ulong addr, ulong len,
printf ( " %02x " , output [ i ] ) ;
}
int hash_command ( const char * algo_name , int verify , cmd_tbl_t * cmdtp , int flag ,
int hash_command ( const char * algo_name , int flags , cmd_tbl_t * cmdtp , int flag ,
int argc , char * const argv [ ] )
{
struct hash_algo * algo ;
ulong addr , len ;
u8 output [ HASH_MAX_DIGEST_SIZE ] ;
u8 vsum [ HASH_MAX_DIGEST_SIZE ] ;
if ( argc < 2 )
return CMD_RET_USAGE ;
algo = find_hash_algo ( algo_name ) ;
if ( ! algo ) {
printf ( " Unknown hash algorithm '%s' \n " , algo_name ) ;
return CMD_RET_USAGE ;
}
addr = simple_strtoul ( * argv + + , NULL , 16 ) ;
len = simple_strtoul ( * argv + + , NULL , 16 ) ;
argc - = 2 ;
if ( algo - > digest_size > HASH_MAX_DIGEST_SIZE ) {
puts ( " HASH_MAX_DIGEST_SIZE exceeded \n " ) ;
return 1 ;
}
if ( multi_hash ( ) ) {
struct hash_algo * algo ;
u8 output [ HASH_MAX_DIGEST_SIZE ] ;
u8 vsum [ HASH_MAX_DIGEST_SIZE ] ;
void * buf ;
algo - > hash_func_ws ( ( const unsigned char * ) addr , len , output ,
algo - > chunk_size ) ;
algo = find_hash_algo ( algo_name ) ;
if ( ! algo ) {
printf ( " Unknown hash algorithm '%s' \n " , algo_name ) ;
return CMD_RET_USAGE ;
}
argc - = 2 ;
/* Try to avoid code bloat when verify is not needed */
if ( algo - > digest_size > HASH_MAX_DIGEST_SIZE ) {
puts ( " HASH_MAX_DIGEST_SIZE exceeded \n " ) ;
return 1 ;
}
buf = map_sysmem ( addr , len ) ;
algo - > hash_func_ws ( buf , len , output , algo - > chunk_size ) ;
unmap_sysmem ( buf ) ;
/* Try to avoid code bloat when verify is not needed */
# ifdef CONFIG_HASH_VERIFY
if ( verify ) {
if ( flags & HASH_FLAG_VERIFY ) {
# else
if ( 0 ) {
if ( 0 ) {
# endif
if ( ! argc )
return CMD_RET_USAGE ;
if ( parse_verify_sum ( algo , * argv , vsum ) ) {
printf ( " ERROR: %s does not contain a valid %s sum \n " ,
* argv , algo - > name ) ;
return 1 ;
}
if ( memcmp ( output , vsum , algo - > digest_size ) ! = 0 ) {
int i ;
if ( ! argc )
return CMD_RET_USAGE ;
if ( parse_verify_sum ( algo , * argv , vsum ,
flags & HASH_FLAG_ENV ) ) {
printf ( " ERROR: %s does not contain a valid "
" %s sum \n " , * argv , algo - > name ) ;
return 1 ;
}
if ( memcmp ( output , vsum , algo - > digest_size ) ! = 0 ) {
int i ;
show_hash ( algo , addr , len , output ) ;
printf ( " != " ) ;
for ( i = 0 ; i < algo - > digest_size ; i + + )
printf ( " %02x " , vsum [ i ] ) ;
puts ( " ** ERROR ** \n " ) ;
return 1 ;
}
} else {
show_hash ( algo , addr , len , output ) ;
printf ( " != " ) ;
for ( i = 0 ; i < algo - > digest_size ; i + + )
printf ( " %02x " , vsum [ i ] ) ;
puts ( " ** ERROR ** \n " ) ;
return 1 ;
printf ( " \n " ) ;
if ( argc ) {
store_result ( algo , output , * argv ,
flags & HASH_FLAG_ENV ) ;
}
}
/* Horrible code size hack for boards that just want crc32 */
} else {
show_hash ( algo , addr , len , output ) ;
printf ( " \n " ) ;
ulong crc ;
ulong * ptr ;
crc = crc32_wd ( 0 , ( const uchar * ) addr , len , CHUNKSZ_CRC32 ) ;
if ( argc )
store_result ( algo , output , * argv ) ;
printf ( " CRC32 for %08lx ... %08lx ==> %08lx \n " ,
addr , addr + len - 1 , crc ) ;
if ( argc > 3 ) {
ptr = ( ulong * ) simple_strtoul ( argv [ 3 ] , NULL , 16 ) ;
* ptr = crc ;
}
}
return 0 ;