2016-06-22 19:49:14 +03:00
/* Diffie-Hellman Key Agreement Method [RFC2631]
*
* Copyright ( c ) 2016 , Intel Corporation
* Authors : Salvatore Benedetto < salvatore . benedetto @ intel . com >
*
* This program is free software ; you can redistribute it and / or
2017-05-25 10:18:03 +03:00
* modify it under the terms of the GNU General Public License
2016-06-22 19:49:14 +03:00
* as published by the Free Software Foundation ; either version
2017-05-25 10:18:03 +03:00
* 2 of the License , or ( at your option ) any later version .
2016-06-22 19:49:14 +03:00
*/
# include <linux/module.h>
# include <crypto/internal/kpp.h>
# include <crypto/kpp.h>
# include <crypto/dh.h>
# include <linux/mpi.h>
struct dh_ctx {
MPI p ;
MPI g ;
MPI xa ;
} ;
2017-11-06 05:30:44 +03:00
static void dh_clear_ctx ( struct dh_ctx * ctx )
2016-06-22 19:49:14 +03:00
{
mpi_free ( ctx - > p ) ;
mpi_free ( ctx - > g ) ;
mpi_free ( ctx - > xa ) ;
2017-11-06 05:30:44 +03:00
memset ( ctx , 0 , sizeof ( * ctx ) ) ;
2016-06-22 19:49:14 +03:00
}
/*
* If base is g we compute the public key
* ya = g ^ xa mod p ; [ RFC2631 sec 2.1 .1 ]
* else if base if the counterpart public key we compute the shared secret
* ZZ = yb ^ xa mod p ; [ RFC2631 sec 2.1 .1 ]
*/
static int _compute_val ( const struct dh_ctx * ctx , MPI base , MPI val )
{
/* val = base^xa mod p */
return mpi_powm ( val , base , ctx - > xa , ctx - > p ) ;
}
static inline struct dh_ctx * dh_get_ctx ( struct crypto_kpp * tfm )
{
return kpp_tfm_ctx ( tfm ) ;
}
static int dh_check_params_length ( unsigned int p_len )
{
return ( p_len < 1536 ) ? - EINVAL : 0 ;
}
static int dh_set_params ( struct dh_ctx * ctx , struct dh * params )
{
if ( dh_check_params_length ( params - > p_size < < 3 ) )
return - EINVAL ;
ctx - > p = mpi_read_raw_data ( params - > p , params - > p_size ) ;
if ( ! ctx - > p )
return - EINVAL ;
ctx - > g = mpi_read_raw_data ( params - > g , params - > g_size ) ;
2017-11-06 05:30:44 +03:00
if ( ! ctx - > g )
2016-06-22 19:49:14 +03:00
return - EINVAL ;
return 0 ;
}
2017-02-25 02:46:58 +03:00
static int dh_set_secret ( struct crypto_kpp * tfm , const void * buf ,
unsigned int len )
2016-06-22 19:49:14 +03:00
{
struct dh_ctx * ctx = dh_get_ctx ( tfm ) ;
struct dh params ;
2017-05-25 10:18:07 +03:00
/* Free the old MPI key if any */
2017-11-06 05:30:44 +03:00
dh_clear_ctx ( ctx ) ;
2017-05-25 10:18:07 +03:00
2016-06-22 19:49:14 +03:00
if ( crypto_dh_decode_key ( buf , len , & params ) < 0 )
2017-11-06 05:30:44 +03:00
goto err_clear_ctx ;
2016-06-22 19:49:14 +03:00
if ( dh_set_params ( ctx , & params ) < 0 )
2017-11-06 05:30:44 +03:00
goto err_clear_ctx ;
2016-06-22 19:49:14 +03:00
ctx - > xa = mpi_read_raw_data ( params . key , params . key_size ) ;
2017-11-06 05:30:44 +03:00
if ( ! ctx - > xa )
goto err_clear_ctx ;
2016-06-22 19:49:14 +03:00
return 0 ;
2017-11-06 05:30:44 +03:00
err_clear_ctx :
dh_clear_ctx ( ctx ) ;
return - EINVAL ;
2016-06-22 19:49:14 +03:00
}
static int dh_compute_value ( struct kpp_request * req )
{
struct crypto_kpp * tfm = crypto_kpp_reqtfm ( req ) ;
struct dh_ctx * ctx = dh_get_ctx ( tfm ) ;
MPI base , val = mpi_alloc ( 0 ) ;
int ret = 0 ;
int sign ;
if ( ! val )
return - ENOMEM ;
if ( unlikely ( ! ctx - > xa ) ) {
ret = - EINVAL ;
goto err_free_val ;
}
if ( req - > src ) {
base = mpi_read_raw_from_sgl ( req - > src , req - > src_len ) ;
if ( ! base ) {
2016-11-09 02:48:22 +03:00
ret = - EINVAL ;
2016-06-22 19:49:14 +03:00
goto err_free_val ;
}
} else {
base = ctx - > g ;
}
ret = _compute_val ( ctx , base , val ) ;
if ( ret )
goto err_free_base ;
2016-06-29 14:32:21 +03:00
ret = mpi_write_to_sgl ( val , req - > dst , req - > dst_len , & sign ) ;
2016-06-22 19:49:14 +03:00
if ( ret )
goto err_free_base ;
if ( sign < 0 )
ret = - EBADMSG ;
err_free_base :
if ( req - > src )
mpi_free ( base ) ;
err_free_val :
mpi_free ( val ) ;
return ret ;
}
2017-05-25 10:18:09 +03:00
static unsigned int dh_max_size ( struct crypto_kpp * tfm )
2016-06-22 19:49:14 +03:00
{
struct dh_ctx * ctx = dh_get_ctx ( tfm ) ;
return mpi_get_size ( ctx - > p ) ;
}
static void dh_exit_tfm ( struct crypto_kpp * tfm )
{
struct dh_ctx * ctx = dh_get_ctx ( tfm ) ;
2017-11-06 05:30:44 +03:00
dh_clear_ctx ( ctx ) ;
2016-06-22 19:49:14 +03:00
}
static struct kpp_alg dh = {
. set_secret = dh_set_secret ,
. generate_public_key = dh_compute_value ,
. compute_shared_secret = dh_compute_value ,
. max_size = dh_max_size ,
. exit = dh_exit_tfm ,
. base = {
. cra_name = " dh " ,
. cra_driver_name = " dh-generic " ,
. cra_priority = 100 ,
. cra_module = THIS_MODULE ,
. cra_ctxsize = sizeof ( struct dh_ctx ) ,
} ,
} ;
static int dh_init ( void )
{
return crypto_register_kpp ( & dh ) ;
}
static void dh_exit ( void )
{
crypto_unregister_kpp ( & dh ) ;
}
module_init ( dh_init ) ;
module_exit ( dh_exit ) ;
MODULE_ALIAS_CRYPTO ( " dh " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " DH generic algorithm " ) ;