2006-01-06 11:19:18 +03:00
/*
* Cryptographic API .
*
* s390 implementation of the SHA256 Secure Hash Algorithm .
*
* s390 Version :
2007-02-05 23:18:14 +03:00
* Copyright IBM Corp . 2005 , 2007
2006-01-06 11:19:18 +03:00
* Author ( s ) : Jan Glauber ( jang @ de . ibm . com )
*
2007-10-08 07:45:10 +04:00
* Derived from " crypto/sha256_generic.c "
2006-01-06 11:19:18 +03:00
* and " arch/s390/crypto/sha1_s390.c "
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/crypto.h>
2007-10-09 18:43:13 +04:00
# include <crypto/sha.h>
2006-01-06 11:19:18 +03:00
# include "crypt_s390.h"
struct s390_sha256_ctx {
2007-04-27 18:01:54 +04:00
u64 count ; /* message length */
2006-01-06 11:19:18 +03:00
u32 state [ 8 ] ;
u8 buf [ 2 * SHA256_BLOCK_SIZE ] ;
} ;
2006-05-16 16:09:29 +04:00
static void sha256_init ( struct crypto_tfm * tfm )
2006-01-06 11:19:18 +03:00
{
2006-05-16 16:09:29 +04:00
struct s390_sha256_ctx * sctx = crypto_tfm_ctx ( tfm ) ;
2006-01-06 11:19:18 +03:00
2007-10-09 18:43:13 +04:00
sctx - > state [ 0 ] = SHA256_H0 ;
sctx - > state [ 1 ] = SHA256_H1 ;
sctx - > state [ 2 ] = SHA256_H2 ;
sctx - > state [ 3 ] = SHA256_H3 ;
sctx - > state [ 4 ] = SHA256_H4 ;
sctx - > state [ 5 ] = SHA256_H5 ;
sctx - > state [ 6 ] = SHA256_H6 ;
sctx - > state [ 7 ] = SHA256_H7 ;
2006-01-06 11:19:18 +03:00
sctx - > count = 0 ;
}
2006-05-16 16:09:29 +04:00
static void sha256_update ( struct crypto_tfm * tfm , const u8 * data ,
unsigned int len )
2006-01-06 11:19:18 +03:00
{
2006-05-16 16:09:29 +04:00
struct s390_sha256_ctx * sctx = crypto_tfm_ctx ( tfm ) ;
2006-01-06 11:19:18 +03:00
unsigned int index ;
2006-01-15 00:20:56 +03:00
int ret ;
2006-01-06 11:19:18 +03:00
/* how much is already in the buffer? */
2007-04-27 18:01:54 +04:00
index = sctx - > count & 0x3f ;
2006-01-06 11:19:18 +03:00
2007-04-27 18:01:54 +04:00
sctx - > count + = len ;
2006-01-06 11:19:18 +03:00
2006-01-15 00:20:56 +03:00
if ( ( index + len ) < SHA256_BLOCK_SIZE )
goto store ;
/* process one stored block */
if ( index ) {
2006-01-06 11:19:18 +03:00
memcpy ( sctx - > buf + index , data , SHA256_BLOCK_SIZE - index ) ;
2006-01-15 00:20:56 +03:00
ret = crypt_s390_kimd ( KIMD_SHA_256 , sctx - > state , sctx - > buf ,
SHA256_BLOCK_SIZE ) ;
BUG_ON ( ret ! = SHA256_BLOCK_SIZE ) ;
2006-01-06 11:19:18 +03:00
data + = SHA256_BLOCK_SIZE - index ;
len - = SHA256_BLOCK_SIZE - index ;
}
2006-01-15 00:20:56 +03:00
/* process as many blocks as possible */
if ( len > = SHA256_BLOCK_SIZE ) {
ret = crypt_s390_kimd ( KIMD_SHA_256 , sctx - > state , data ,
len & ~ ( SHA256_BLOCK_SIZE - 1 ) ) ;
BUG_ON ( ret ! = ( len & ~ ( SHA256_BLOCK_SIZE - 1 ) ) ) ;
data + = ret ;
len - = ret ;
}
store :
2006-01-06 11:19:18 +03:00
/* anything left? */
if ( len )
memcpy ( sctx - > buf + index , data , len ) ;
}
2007-04-27 18:01:54 +04:00
/* Add padding and return the message digest */
static void sha256_final ( struct crypto_tfm * tfm , u8 * out )
2006-01-06 11:19:18 +03:00
{
2007-04-27 18:01:54 +04:00
struct s390_sha256_ctx * sctx = crypto_tfm_ctx ( tfm ) ;
u64 bits ;
unsigned int index , end ;
int ret ;
2006-01-06 11:19:18 +03:00
2007-04-27 18:01:54 +04:00
/* must perform manual padding */
index = sctx - > count & 0x3f ;
end = ( index < 56 ) ? SHA256_BLOCK_SIZE : ( 2 * SHA256_BLOCK_SIZE ) ;
2006-01-06 11:19:18 +03:00
/* start pad with 1 */
sctx - > buf [ index ] = 0x80 ;
/* pad with zeros */
index + + ;
memset ( sctx - > buf + index , 0x00 , end - index - 8 ) ;
/* append message length */
2007-04-27 18:01:54 +04:00
bits = sctx - > count * 8 ;
memcpy ( sctx - > buf + end - 8 , & bits , sizeof ( bits ) ) ;
2006-01-06 11:19:18 +03:00
2007-04-27 18:01:54 +04:00
ret = crypt_s390_kimd ( KIMD_SHA_256 , sctx - > state , sctx - > buf , end ) ;
BUG_ON ( ret ! = end ) ;
2006-01-06 11:19:18 +03:00
/* copy digest to out */
memcpy ( out , sctx - > state , SHA256_DIGEST_SIZE ) ;
/* wipe context */
memset ( sctx , 0 , sizeof * sctx ) ;
}
static struct crypto_alg alg = {
. cra_name = " sha256 " ,
2006-08-21 15:18:50 +04:00
. cra_driver_name = " sha256-s390 " ,
. cra_priority = CRYPT_S390_PRIORITY ,
2006-01-06 11:19:18 +03:00
. cra_flags = CRYPTO_ALG_TYPE_DIGEST ,
. cra_blocksize = SHA256_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct s390_sha256_ctx ) ,
. cra_module = THIS_MODULE ,
. cra_list = LIST_HEAD_INIT ( alg . cra_list ) ,
. cra_u = { . digest = {
. dia_digestsize = SHA256_DIGEST_SIZE ,
2006-01-15 00:20:56 +03:00
. dia_init = sha256_init ,
. dia_update = sha256_update ,
. dia_final = sha256_final } }
2006-01-06 11:19:18 +03:00
} ;
static int init ( void )
{
if ( ! crypt_s390_func_available ( KIMD_SHA_256 ) )
2007-02-05 23:18:14 +03:00
return - EOPNOTSUPP ;
2006-01-06 11:19:18 +03:00
2007-02-05 23:18:14 +03:00
return crypto_register_alg ( & alg ) ;
2006-01-06 11:19:18 +03:00
}
static void __exit fini ( void )
{
crypto_unregister_alg ( & alg ) ;
}
module_init ( init ) ;
module_exit ( fini ) ;
MODULE_ALIAS ( " sha256 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA256 Secure Hash Algorithm " ) ;