2011-06-08 17:26:00 +04:00
/*
2005-04-17 02:20:36 +04:00
* Cryptographic API
*
* ARC4 Cipher Algorithm
*
* Jon Oberheide < jon @ oberheide . 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 .
*
*/
2012-06-09 19:25:40 +04:00
# include <crypto/algapi.h>
2019-02-08 16:50:08 +03:00
# include <crypto/arc4.h>
2019-01-04 07:16:23 +03:00
# include <crypto/internal/skcipher.h>
# include <linux/init.h>
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
struct arc4_ctx {
2012-06-09 19:25:46 +04:00
u32 S [ 256 ] ;
u32 x , y ;
2005-04-17 02:20:36 +04:00
} ;
2006-05-16 16:09:29 +04:00
static int arc4_set_key ( struct crypto_tfm * tfm , const u8 * in_key ,
2006-08-13 08:16:39 +04:00
unsigned int key_len )
2005-04-17 02:20:36 +04:00
{
2006-05-16 16:09:29 +04:00
struct arc4_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
2005-04-17 02:20:36 +04:00
int i , j = 0 , k = 0 ;
ctx - > x = 1 ;
ctx - > y = 0 ;
2011-06-08 17:26:00 +04:00
for ( i = 0 ; i < 256 ; i + + )
2005-04-17 02:20:36 +04:00
ctx - > S [ i ] = i ;
2011-06-08 17:26:00 +04:00
for ( i = 0 ; i < 256 ; i + + ) {
2012-06-09 19:25:46 +04:00
u32 a = ctx - > S [ i ] ;
2005-04-17 02:20:36 +04:00
j = ( j + in_key [ k ] + a ) & 0xff ;
ctx - > S [ i ] = ctx - > S [ j ] ;
ctx - > S [ j ] = a ;
2011-06-08 17:26:00 +04:00
if ( + + k > = key_len )
2005-04-17 02:20:36 +04:00
k = 0 ;
}
return 0 ;
}
2019-01-04 07:16:23 +03:00
static int arc4_set_key_skcipher ( struct crypto_skcipher * tfm , const u8 * in_key ,
unsigned int key_len )
{
return arc4_set_key ( & tfm - > base , in_key , key_len ) ;
}
2012-06-09 19:25:40 +04:00
static void arc4_crypt ( struct arc4_ctx * ctx , u8 * out , const u8 * in ,
unsigned int len )
2005-04-17 02:20:36 +04:00
{
2012-06-09 19:25:46 +04:00
u32 * const S = ctx - > S ;
u32 x , y , a , b ;
u32 ty , ta , tb ;
2012-06-09 19:25:40 +04:00
if ( len = = 0 )
return ;
x = ctx - > x ;
y = ctx - > y ;
2005-04-17 02:20:36 +04:00
a = S [ x ] ;
y = ( y + a ) & 0xff ;
b = S [ y ] ;
2012-06-09 19:25:40 +04:00
do {
S [ y ] = a ;
a = ( a + b ) & 0xff ;
S [ x ] = b ;
x = ( x + 1 ) & 0xff ;
ta = S [ x ] ;
ty = ( y + ta ) & 0xff ;
tb = S [ ty ] ;
* out + + = * in + + ^ S [ a ] ;
if ( - - len = = 0 )
break ;
y = ty ;
a = ta ;
b = tb ;
} while ( true ) ;
2005-04-17 02:20:36 +04:00
ctx - > x = x ;
ctx - > y = y ;
}
2012-06-09 19:25:40 +04:00
static void arc4_crypt_one ( struct crypto_tfm * tfm , u8 * out , const u8 * in )
{
arc4_crypt ( crypto_tfm_ctx ( tfm ) , out , in , 1 ) ;
}
2019-01-04 07:16:23 +03:00
static int ecb_arc4_crypt ( struct skcipher_request * req )
2012-06-09 19:25:40 +04:00
{
2019-01-04 07:16:23 +03:00
struct crypto_skcipher * tfm = crypto_skcipher_reqtfm ( req ) ;
struct arc4_ctx * ctx = crypto_skcipher_ctx ( tfm ) ;
struct skcipher_walk walk ;
2012-06-09 19:25:40 +04:00
int err ;
2019-01-04 07:16:23 +03:00
err = skcipher_walk_virt ( & walk , req , false ) ;
2012-06-09 19:25:40 +04:00
while ( walk . nbytes > 0 ) {
2019-01-04 07:16:23 +03:00
arc4_crypt ( ctx , walk . dst . virt . addr , walk . src . virt . addr ,
walk . nbytes ) ;
err = skcipher_walk_done ( & walk , 0 ) ;
2012-06-09 19:25:40 +04:00
}
return err ;
}
2019-01-04 07:16:23 +03:00
static struct crypto_alg arc4_cipher = {
2005-04-17 02:20:36 +04:00
. cra_name = " arc4 " ,
. cra_flags = CRYPTO_ALG_TYPE_CIPHER ,
. cra_blocksize = ARC4_BLOCK_SIZE ,
. cra_ctxsize = sizeof ( struct arc4_ctx ) ,
. cra_module = THIS_MODULE ,
2012-06-09 19:25:40 +04:00
. cra_u = {
. cipher = {
. cia_min_keysize = ARC4_MIN_KEY_SIZE ,
. cia_max_keysize = ARC4_MAX_KEY_SIZE ,
. cia_setkey = arc4_set_key ,
. cia_encrypt = arc4_crypt_one ,
. cia_decrypt = arc4_crypt_one ,
} ,
} ,
2019-01-04 07:16:23 +03:00
} ;
static struct skcipher_alg arc4_skcipher = {
. base . cra_name = " ecb(arc4) " ,
. base . cra_priority = 100 ,
. base . cra_blocksize = ARC4_BLOCK_SIZE ,
. base . cra_ctxsize = sizeof ( struct arc4_ctx ) ,
. base . cra_module = THIS_MODULE ,
. min_keysize = ARC4_MIN_KEY_SIZE ,
. max_keysize = ARC4_MAX_KEY_SIZE ,
. setkey = arc4_set_key_skcipher ,
. encrypt = ecb_arc4_crypt ,
. decrypt = ecb_arc4_crypt ,
} ;
2005-04-17 02:20:36 +04:00
static int __init arc4_init ( void )
{
2019-01-04 07:16:23 +03:00
int err ;
err = crypto_register_alg ( & arc4_cipher ) ;
if ( err )
return err ;
err = crypto_register_skcipher ( & arc4_skcipher ) ;
if ( err )
crypto_unregister_alg ( & arc4_cipher ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
static void __exit arc4_exit ( void )
{
2019-01-04 07:16:23 +03:00
crypto_unregister_alg ( & arc4_cipher ) ;
crypto_unregister_skcipher ( & arc4_skcipher ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( arc4_init ) ;
module_exit ( arc4_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " ARC4 Cipher Algorithm " ) ;
MODULE_AUTHOR ( " Jon Oberheide <jon@oberheide.org> " ) ;
2014-11-21 04:05:53 +03:00
MODULE_ALIAS_CRYPTO ( " arc4 " ) ;