2012-08-19 17:37:56 -07:00
/* Glue code for SHA512 hashing optimized for sparc64 crypto opcodes.
*
* This is based largely upon crypto / sha512_generic . c
*
* Copyright ( c ) Jean - Luc Cooke < jlcooke @ certainkey . com >
* Copyright ( c ) Andrew McDonald < andrew @ mcdonald . org . uk >
* Copyright ( c ) 2003 Kyle McMartin < kyle @ debian . org >
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <crypto/internal/hash.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mm.h>
# include <linux/cryptohash.h>
# include <linux/types.h>
# include <crypto/sha.h>
# include <asm/pstate.h>
# include <asm/elf.h>
2012-09-15 09:06:30 -07:00
# include "opcodes.h"
2012-08-19 17:37:56 -07:00
asmlinkage void sha512_sparc64_transform ( u64 * digest , const char * data ,
unsigned int rounds ) ;
static int sha512_sparc64_init ( struct shash_desc * desc )
{
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
sctx - > state [ 0 ] = SHA512_H0 ;
sctx - > state [ 1 ] = SHA512_H1 ;
sctx - > state [ 2 ] = SHA512_H2 ;
sctx - > state [ 3 ] = SHA512_H3 ;
sctx - > state [ 4 ] = SHA512_H4 ;
sctx - > state [ 5 ] = SHA512_H5 ;
sctx - > state [ 6 ] = SHA512_H6 ;
sctx - > state [ 7 ] = SHA512_H7 ;
sctx - > count [ 0 ] = sctx - > count [ 1 ] = 0 ;
return 0 ;
}
static int sha384_sparc64_init ( struct shash_desc * desc )
{
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
sctx - > state [ 0 ] = SHA384_H0 ;
sctx - > state [ 1 ] = SHA384_H1 ;
sctx - > state [ 2 ] = SHA384_H2 ;
sctx - > state [ 3 ] = SHA384_H3 ;
sctx - > state [ 4 ] = SHA384_H4 ;
sctx - > state [ 5 ] = SHA384_H5 ;
sctx - > state [ 6 ] = SHA384_H6 ;
sctx - > state [ 7 ] = SHA384_H7 ;
sctx - > count [ 0 ] = sctx - > count [ 1 ] = 0 ;
return 0 ;
}
static void __sha512_sparc64_update ( struct sha512_state * sctx , const u8 * data ,
unsigned int len , unsigned int partial )
{
unsigned int done = 0 ;
if ( ( sctx - > count [ 0 ] + = len ) < len )
sctx - > count [ 1 ] + + ;
if ( partial ) {
done = SHA512_BLOCK_SIZE - partial ;
memcpy ( sctx - > buf + partial , data , done ) ;
sha512_sparc64_transform ( sctx - > state , sctx - > buf , 1 ) ;
}
if ( len - done > = SHA512_BLOCK_SIZE ) {
const unsigned int rounds = ( len - done ) / SHA512_BLOCK_SIZE ;
sha512_sparc64_transform ( sctx - > state , data + done , rounds ) ;
done + = rounds * SHA512_BLOCK_SIZE ;
}
memcpy ( sctx - > buf , data + done , len - done ) ;
}
static int sha512_sparc64_update ( struct shash_desc * desc , const u8 * data ,
unsigned int len )
{
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
unsigned int partial = sctx - > count [ 0 ] % SHA512_BLOCK_SIZE ;
/* Handle the fast case right here */
if ( partial + len < SHA512_BLOCK_SIZE ) {
if ( ( sctx - > count [ 0 ] + = len ) < len )
sctx - > count [ 1 ] + + ;
memcpy ( sctx - > buf + partial , data , len ) ;
} else
__sha512_sparc64_update ( sctx , data , len , partial ) ;
return 0 ;
}
static int sha512_sparc64_final ( struct shash_desc * desc , u8 * out )
{
struct sha512_state * sctx = shash_desc_ctx ( desc ) ;
unsigned int i , index , padlen ;
__be64 * dst = ( __be64 * ) out ;
__be64 bits [ 2 ] ;
static const u8 padding [ SHA512_BLOCK_SIZE ] = { 0x80 , } ;
/* Save number of bits */
bits [ 1 ] = cpu_to_be64 ( sctx - > count [ 0 ] < < 3 ) ;
bits [ 0 ] = cpu_to_be64 ( sctx - > count [ 1 ] < < 3 | sctx - > count [ 0 ] > > 61 ) ;
/* Pad out to 112 mod 128 and append length */
index = sctx - > count [ 0 ] % SHA512_BLOCK_SIZE ;
padlen = ( index < 112 ) ? ( 112 - index ) : ( ( SHA512_BLOCK_SIZE + 112 ) - index ) ;
/* We need to fill a whole block for __sha512_sparc64_update() */
if ( padlen < = 112 ) {
if ( ( sctx - > count [ 0 ] + = padlen ) < padlen )
sctx - > count [ 1 ] + + ;
memcpy ( sctx - > buf + index , padding , padlen ) ;
} else {
__sha512_sparc64_update ( sctx , padding , padlen , index ) ;
}
__sha512_sparc64_update ( sctx , ( const u8 * ) & bits , sizeof ( bits ) , 112 ) ;
/* Store state in digest */
for ( i = 0 ; i < 8 ; i + + )
dst [ i ] = cpu_to_be64 ( sctx - > state [ i ] ) ;
/* Wipe context */
memset ( sctx , 0 , sizeof ( * sctx ) ) ;
return 0 ;
}
static int sha384_sparc64_final ( struct shash_desc * desc , u8 * hash )
{
u8 D [ 64 ] ;
sha512_sparc64_final ( desc , D ) ;
memcpy ( hash , D , 48 ) ;
memset ( D , 0 , 64 ) ;
return 0 ;
}
static struct shash_alg sha512 = {
. digestsize = SHA512_DIGEST_SIZE ,
. init = sha512_sparc64_init ,
. update = sha512_sparc64_update ,
. final = sha512_sparc64_final ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha512 " ,
. cra_driver_name = " sha512-sparc64 " ,
2012-09-15 09:06:30 -07:00
. cra_priority = SPARC_CR_OPCODE_PRIORITY ,
2012-08-19 17:37:56 -07:00
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = SHA512_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} ;
static struct shash_alg sha384 = {
. digestsize = SHA384_DIGEST_SIZE ,
. init = sha384_sparc64_init ,
. update = sha512_sparc64_update ,
. final = sha384_sparc64_final ,
. descsize = sizeof ( struct sha512_state ) ,
. base = {
. cra_name = " sha384 " ,
. cra_driver_name = " sha384-sparc64 " ,
2012-09-15 09:06:30 -07:00
. cra_priority = SPARC_CR_OPCODE_PRIORITY ,
2012-08-19 17:37:56 -07:00
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = SHA384_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
} ;
static bool __init sparc64_has_sha512_opcode ( void )
{
unsigned long cfr ;
if ( ! ( sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO ) )
return false ;
__asm__ __volatile__ ( " rd %%asr26, %0 " : " =r " ( cfr ) ) ;
if ( ! ( cfr & CFR_SHA512 ) )
return false ;
return true ;
}
static int __init sha512_sparc64_mod_init ( void )
{
if ( sparc64_has_sha512_opcode ( ) ) {
int ret = crypto_register_shash ( & sha384 ) ;
if ( ret < 0 )
return ret ;
ret = crypto_register_shash ( & sha512 ) ;
if ( ret < 0 ) {
crypto_unregister_shash ( & sha384 ) ;
return ret ;
}
pr_info ( " Using sparc64 sha512 opcode optimized SHA-512/SHA-384 implementation \n " ) ;
return 0 ;
}
pr_info ( " sparc64 sha512 opcode not available. \n " ) ;
return - ENODEV ;
}
static void __exit sha512_sparc64_mod_fini ( void )
{
crypto_unregister_shash ( & sha384 ) ;
crypto_unregister_shash ( & sha512 ) ;
}
module_init ( sha512_sparc64_mod_init ) ;
module_exit ( sha512_sparc64_mod_fini ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA-384 and SHA-512 Secure Hash Algorithm, sparc64 sha512 opcode accelerated " ) ;
MODULE_ALIAS ( " sha384 " ) ;
MODULE_ALIAS ( " sha512 " ) ;
2012-11-09 20:53:32 -08:00
# include "crop_devid.c"