2005-04-17 02:20:36 +04:00
/*
* Cryptographic API .
*
2006-01-06 11:19:17 +03:00
* s390 implementation of the SHA1 Secure Hash Algorithm .
2005-04-17 02:20:36 +04:00
*
* Derived from cryptoapi implementation , adapted for in - place
* scatterlist interface . Originally based on the public domain
* implementation written by Steve Reid .
*
* s390 Version :
* Copyright ( C ) 2003 IBM Deutschland GmbH , IBM Corporation
* Author ( s ) : Thomas Spatzier ( tspat @ de . ibm . com )
*
* Derived from " crypto/sha1.c "
* Copyright ( c ) Alan Smithee .
* Copyright ( c ) Andrew McDonald < andrew @ mcdonald . org . uk >
* Copyright ( c ) Jean - Francois Dive < jef @ linuxbe . org >
*
* 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/mm.h>
# include <linux/crypto.h>
# include <asm/scatterlist.h>
# include <asm/byteorder.h>
2006-01-06 11:19:17 +03:00
# include "crypt_s390.h"
2005-04-17 02:20:36 +04:00
# define SHA1_DIGEST_SIZE 20
# define SHA1_BLOCK_SIZE 64
2006-01-06 11:19:17 +03:00
struct crypt_s390_sha1_ctx {
u64 count ;
u32 state [ 5 ] ;
2005-04-17 02:20:36 +04:00
u32 buf_len ;
2006-01-06 11:19:17 +03:00
u8 buffer [ 2 * SHA1_BLOCK_SIZE ] ;
2005-04-17 02:20:36 +04:00
} ;
2006-05-16 16:09:29 +04:00
static void sha1_init ( struct crypto_tfm * tfm )
2005-04-17 02:20:36 +04:00
{
2006-05-16 16:09:29 +04:00
struct crypt_s390_sha1_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
2006-05-16 16:06:54 +04:00
static const u32 initstate [ 5 ] = {
0x67452301 ,
0xEFCDAB89 ,
0x98BADCFE ,
0x10325476 ,
0xC3D2E1F0
2005-04-17 02:20:36 +04:00
} ;
2006-05-16 16:06:54 +04:00
ctx - > count = 0 ;
memcpy ( ctx - > state , & initstate , sizeof ( initstate ) ) ;
ctx - > buf_len = 0 ;
2005-04-17 02:20:36 +04:00
}
2006-05-16 16:09:29 +04:00
static void sha1_update ( struct crypto_tfm * tfm , const u8 * data ,
unsigned int len )
2005-04-17 02:20:36 +04:00
{
2006-01-06 11:19:17 +03:00
struct crypt_s390_sha1_ctx * sctx ;
2005-04-17 02:20:36 +04:00
long imd_len ;
2006-05-16 16:09:29 +04:00
sctx = crypto_tfm_ctx ( tfm ) ;
2005-04-17 02:20:36 +04:00
sctx - > count + = len * 8 ; //message bit length
//anything in buffer yet? -> must be completed
if ( sctx - > buf_len & & ( sctx - > buf_len + len ) > = SHA1_BLOCK_SIZE ) {
//complete full block and hash
memcpy ( sctx - > buffer + sctx - > buf_len , data ,
SHA1_BLOCK_SIZE - sctx - > buf_len ) ;
2006-01-06 11:19:17 +03:00
crypt_s390_kimd ( KIMD_SHA_1 , sctx - > state , sctx - > buffer ,
2005-04-17 02:20:36 +04:00
SHA1_BLOCK_SIZE ) ;
data + = SHA1_BLOCK_SIZE - sctx - > buf_len ;
len - = SHA1_BLOCK_SIZE - sctx - > buf_len ;
sctx - > buf_len = 0 ;
}
//rest of data contains full blocks?
imd_len = len & ~ 0x3ful ;
if ( imd_len ) {
2006-01-06 11:19:17 +03:00
crypt_s390_kimd ( KIMD_SHA_1 , sctx - > state , data , imd_len ) ;
2005-04-17 02:20:36 +04:00
data + = imd_len ;
len - = imd_len ;
}
//anything left? store in buffer
if ( len ) {
memcpy ( sctx - > buffer + sctx - > buf_len , data , len ) ;
sctx - > buf_len + = len ;
}
}
static void
2006-01-06 11:19:17 +03:00
pad_message ( struct crypt_s390_sha1_ctx * sctx )
2005-04-17 02:20:36 +04:00
{
int index ;
index = sctx - > buf_len ;
sctx - > buf_len = ( sctx - > buf_len < 56 ) ?
SHA1_BLOCK_SIZE : 2 * SHA1_BLOCK_SIZE ;
//start pad with 1
sctx - > buffer [ index ] = 0x80 ;
//pad with zeros
index + + ;
memset ( sctx - > buffer + index , 0x00 , sctx - > buf_len - index ) ;
//append length
memcpy ( sctx - > buffer + sctx - > buf_len - 8 , & sctx - > count ,
sizeof sctx - > count ) ;
}
/* Add padding and return the message digest. */
2006-05-16 16:09:29 +04:00
static void sha1_final ( struct crypto_tfm * tfm , u8 * out )
2005-04-17 02:20:36 +04:00
{
2006-05-16 16:09:29 +04:00
struct crypt_s390_sha1_ctx * sctx = crypto_tfm_ctx ( tfm ) ;
2005-04-17 02:20:36 +04:00
//must perform manual padding
pad_message ( sctx ) ;
2006-01-06 11:19:17 +03:00
crypt_s390_kimd ( KIMD_SHA_1 , sctx - > state , sctx - > buffer , sctx - > buf_len ) ;
2005-04-17 02:20:36 +04:00
//copy digest to out
memcpy ( out , sctx - > state , SHA1_DIGEST_SIZE ) ;
/* Wipe context */
memset ( sctx , 0 , sizeof * sctx ) ;
}
static struct crypto_alg alg = {
. cra_name = " sha1 " ,
2006-08-21 15:18:50 +04:00
. cra_driver_name = " sha1-s390 " ,
. cra_priority = CRYPT_S390_PRIORITY ,
2005-04-17 02:20:36 +04:00
. cra_flags = CRYPTO_ALG_TYPE_DIGEST ,
. cra_blocksize = SHA1_BLOCK_SIZE ,
2006-01-06 11:19:17 +03:00
. cra_ctxsize = sizeof ( struct crypt_s390_sha1_ctx ) ,
2005-04-17 02:20:36 +04:00
. cra_module = THIS_MODULE ,
. cra_list = LIST_HEAD_INIT ( alg . cra_list ) ,
. cra_u = { . digest = {
. dia_digestsize = SHA1_DIGEST_SIZE ,
. dia_init = sha1_init ,
. dia_update = sha1_update ,
. dia_final = sha1_final } }
} ;
static int
init ( void )
{
int ret = - ENOSYS ;
2006-01-06 11:19:17 +03:00
if ( crypt_s390_func_available ( KIMD_SHA_1 ) ) {
2005-04-17 02:20:36 +04:00
ret = crypto_register_alg ( & alg ) ;
if ( ret = = 0 ) {
2006-01-06 11:19:17 +03:00
printk ( KERN_INFO " crypt_s390: sha1_s390 loaded. \n " ) ;
2005-04-17 02:20:36 +04:00
}
}
return ret ;
}
static void __exit
fini ( void )
{
crypto_unregister_alg ( & alg ) ;
}
module_init ( init ) ;
module_exit ( fini ) ;
MODULE_ALIAS ( " sha1 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " SHA1 Secure Hash Algorithm " ) ;