2017-11-24 15:00:34 +01:00
// SPDX-License-Identifier: GPL-2.0
2011-04-19 21:29:18 +02:00
/*
* Cryptographic API .
*
* s390 implementation of the GHASH algorithm for GCM ( Galois / Counter Mode ) .
*
* Copyright IBM Corp . 2011
* Author ( s ) : Gerald Schaefer < gerald . schaefer @ de . ibm . com >
*/
# include <crypto/internal/hash.h>
# include <linux/module.h>
2015-02-19 17:34:07 +01:00
# include <linux/cpufeature.h>
2016-03-17 15:22:12 +01:00
# include <asm/cpacf.h>
2011-04-19 21:29:18 +02:00
# define GHASH_BLOCK_SIZE 16
# define GHASH_DIGEST_SIZE 16
struct ghash_ctx {
2015-05-21 10:01:11 +02:00
u8 key [ GHASH_BLOCK_SIZE ] ;
2011-04-19 21:29:18 +02:00
} ;
struct ghash_desc_ctx {
2015-05-21 10:01:11 +02:00
u8 icv [ GHASH_BLOCK_SIZE ] ;
u8 key [ GHASH_BLOCK_SIZE ] ;
2011-04-19 21:29:18 +02:00
u8 buffer [ GHASH_BLOCK_SIZE ] ;
u32 bytes ;
} ;
static int ghash_init ( struct shash_desc * desc )
{
struct ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
2015-05-21 10:01:11 +02:00
struct ghash_ctx * ctx = crypto_shash_ctx ( desc - > tfm ) ;
2011-04-19 21:29:18 +02:00
memset ( dctx , 0 , sizeof ( * dctx ) ) ;
2015-05-21 10:01:11 +02:00
memcpy ( dctx - > key , ctx - > key , GHASH_BLOCK_SIZE ) ;
2011-04-19 21:29:18 +02:00
return 0 ;
}
static int ghash_setkey ( struct crypto_shash * tfm ,
const u8 * key , unsigned int keylen )
{
struct ghash_ctx * ctx = crypto_shash_ctx ( tfm ) ;
if ( keylen ! = GHASH_BLOCK_SIZE ) {
crypto_shash_set_flags ( tfm , CRYPTO_TFM_RES_BAD_KEY_LEN ) ;
return - EINVAL ;
}
memcpy ( ctx - > key , key , GHASH_BLOCK_SIZE ) ;
return 0 ;
}
static int ghash_update ( struct shash_desc * desc ,
const u8 * src , unsigned int srclen )
{
struct ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
unsigned int n ;
u8 * buf = dctx - > buffer ;
if ( dctx - > bytes ) {
u8 * pos = buf + ( GHASH_BLOCK_SIZE - dctx - > bytes ) ;
n = min ( srclen , dctx - > bytes ) ;
dctx - > bytes - = n ;
srclen - = n ;
memcpy ( pos , src , n ) ;
src + = n ;
if ( ! dctx - > bytes ) {
2016-08-15 10:41:52 +02:00
cpacf_kimd ( CPACF_KIMD_GHASH , dctx , buf ,
GHASH_BLOCK_SIZE ) ;
2011-04-19 21:29:18 +02:00
}
}
n = srclen & ~ ( GHASH_BLOCK_SIZE - 1 ) ;
if ( n ) {
2016-08-15 10:41:52 +02:00
cpacf_kimd ( CPACF_KIMD_GHASH , dctx , src , n ) ;
2011-04-19 21:29:18 +02:00
src + = n ;
srclen - = n ;
}
if ( srclen ) {
dctx - > bytes = GHASH_BLOCK_SIZE - srclen ;
memcpy ( buf , src , srclen ) ;
}
return 0 ;
}
2015-05-21 10:01:11 +02:00
static int ghash_flush ( struct ghash_desc_ctx * dctx )
2011-04-19 21:29:18 +02:00
{
u8 * buf = dctx - > buffer ;
if ( dctx - > bytes ) {
u8 * pos = buf + ( GHASH_BLOCK_SIZE - dctx - > bytes ) ;
memset ( pos , 0 , dctx - > bytes ) ;
2016-08-15 10:41:52 +02:00
cpacf_kimd ( CPACF_KIMD_GHASH , dctx , buf , GHASH_BLOCK_SIZE ) ;
2015-05-21 10:01:11 +02:00
dctx - > bytes = 0 ;
2011-04-19 21:29:18 +02:00
}
2012-10-26 15:06:12 +02:00
return 0 ;
2011-04-19 21:29:18 +02:00
}
static int ghash_final ( struct shash_desc * desc , u8 * dst )
{
struct ghash_desc_ctx * dctx = shash_desc_ctx ( desc ) ;
2012-10-26 15:06:12 +02:00
int ret ;
2011-04-19 21:29:18 +02:00
2015-05-21 10:01:11 +02:00
ret = ghash_flush ( dctx ) ;
2012-10-26 15:06:12 +02:00
if ( ! ret )
2015-05-21 10:01:11 +02:00
memcpy ( dst , dctx - > icv , GHASH_BLOCK_SIZE ) ;
2012-10-26 15:06:12 +02:00
return ret ;
2011-04-19 21:29:18 +02:00
}
static struct shash_alg ghash_alg = {
. digestsize = GHASH_DIGEST_SIZE ,
. init = ghash_init ,
. update = ghash_update ,
. final = ghash_final ,
. setkey = ghash_setkey ,
. descsize = sizeof ( struct ghash_desc_ctx ) ,
. base = {
. cra_name = " ghash " ,
. cra_driver_name = " ghash-s390 " ,
2016-03-17 15:22:12 +01:00
. cra_priority = 300 ,
2011-04-19 21:29:18 +02:00
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = GHASH_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct ghash_ctx ) ,
. cra_module = THIS_MODULE ,
} ,
} ;
static int __init ghash_mod_init ( void )
{
2016-08-18 12:59:46 +02:00
if ( ! cpacf_query_func ( CPACF_KIMD , CPACF_KIMD_GHASH ) )
2011-04-19 21:29:18 +02:00
return - EOPNOTSUPP ;
return crypto_register_shash ( & ghash_alg ) ;
}
static void __exit ghash_mod_exit ( void )
{
crypto_unregister_shash ( & ghash_alg ) ;
}
2015-02-19 17:34:07 +01:00
module_cpu_feature_match ( MSA , ghash_mod_init ) ;
2011-04-19 21:29:18 +02:00
module_exit ( ghash_mod_exit ) ;
2014-11-20 17:05:53 -08:00
MODULE_ALIAS_CRYPTO ( " ghash " ) ;
2011-04-19 21:29:18 +02:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " GHASH Message Digest Algorithm, s390 implementation " ) ;