2005-04-17 02:20:36 +04:00
/*
* Cryptographic API .
*
* Digest operations .
*
* Copyright ( c ) 2002 James Morris < jmorris @ intercode . com . au >
*
* 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 .
*
*/
2006-08-19 16:24:23 +04:00
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/errno.h>
# include <linux/highmem.h>
2006-08-19 16:24:23 +04:00
# include <linux/module.h>
# include <linux/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include "internal.h"
2006-08-19 16:24:23 +04:00
# include "scatterwalk.h"
2005-04-17 02:20:36 +04:00
2006-08-19 16:24:23 +04:00
void crypto_digest_init ( struct crypto_tfm * tfm )
2005-04-17 02:20:36 +04:00
{
2006-08-19 16:24:23 +04:00
struct crypto_hash * hash = crypto_hash_cast ( tfm ) ;
struct hash_desc desc = { . tfm = hash , . flags = tfm - > crt_flags } ;
crypto_hash_init ( & desc ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-19 16:24:23 +04:00
EXPORT_SYMBOL_GPL ( crypto_digest_init ) ;
2005-04-17 02:20:36 +04:00
2006-08-19 16:24:23 +04:00
void crypto_digest_update ( struct crypto_tfm * tfm ,
struct scatterlist * sg , unsigned int nsg )
2005-04-17 02:20:36 +04:00
{
2006-08-19 16:24:23 +04:00
struct crypto_hash * hash = crypto_hash_cast ( tfm ) ;
struct hash_desc desc = { . tfm = hash , . flags = tfm - > crt_flags } ;
unsigned int nbytes = 0 ;
2005-04-17 02:20:36 +04:00
unsigned int i ;
2006-08-19 16:24:23 +04:00
for ( i = 0 ; i < nsg ; i + + )
nbytes + = sg [ i ] . length ;
crypto_hash_update ( & desc , sg , nbytes ) ;
}
EXPORT_SYMBOL_GPL ( crypto_digest_update ) ;
void crypto_digest_final ( struct crypto_tfm * tfm , u8 * out )
{
struct crypto_hash * hash = crypto_hash_cast ( tfm ) ;
struct hash_desc desc = { . tfm = hash , . flags = tfm - > crt_flags } ;
crypto_hash_final ( & desc , out ) ;
}
EXPORT_SYMBOL_GPL ( crypto_digest_final ) ;
void crypto_digest_digest ( struct crypto_tfm * tfm ,
struct scatterlist * sg , unsigned int nsg , u8 * out )
{
struct crypto_hash * hash = crypto_hash_cast ( tfm ) ;
struct hash_desc desc = { . tfm = hash , . flags = tfm - > crt_flags } ;
unsigned int nbytes = 0 ;
unsigned int i ;
for ( i = 0 ; i < nsg ; i + + )
nbytes + = sg [ i ] . length ;
crypto_hash_digest ( & desc , sg , nbytes , out ) ;
}
EXPORT_SYMBOL_GPL ( crypto_digest_digest ) ;
static int init ( struct hash_desc * desc )
{
struct crypto_tfm * tfm = crypto_hash_tfm ( desc - > tfm ) ;
tfm - > __crt_alg - > cra_digest . dia_init ( tfm ) ;
return 0 ;
}
static int update ( struct hash_desc * desc ,
struct scatterlist * sg , unsigned int nbytes )
{
struct crypto_tfm * tfm = crypto_hash_tfm ( desc - > tfm ) ;
2006-04-10 02:42:35 +04:00
unsigned int alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
2005-04-17 02:20:36 +04:00
2006-08-19 16:24:23 +04:00
if ( ! nbytes )
return 0 ;
for ( ; ; ) {
struct page * pg = sg - > page ;
unsigned int offset = sg - > offset ;
unsigned int l = sg - > length ;
2005-04-17 02:20:36 +04:00
2006-08-19 16:24:23 +04:00
if ( unlikely ( l > nbytes ) )
l = nbytes ;
nbytes - = l ;
2005-04-17 02:20:36 +04:00
do {
unsigned int bytes_from_page = min ( l , ( ( unsigned int )
( PAGE_SIZE ) ) -
offset ) ;
2006-04-10 02:42:35 +04:00
char * src = crypto_kmap ( pg , 0 ) ;
char * p = src + offset ;
2005-04-17 02:20:36 +04:00
2006-04-10 02:42:35 +04:00
if ( unlikely ( offset & alignmask ) ) {
unsigned int bytes =
alignmask + 1 - ( offset & alignmask ) ;
bytes = min ( bytes , bytes_from_page ) ;
2006-05-16 16:09:29 +04:00
tfm - > __crt_alg - > cra_digest . dia_update ( tfm , p ,
bytes ) ;
2006-04-10 02:42:35 +04:00
p + = bytes ;
bytes_from_page - = bytes ;
l - = bytes ;
}
2006-05-16 16:09:29 +04:00
tfm - > __crt_alg - > cra_digest . dia_update ( tfm , p ,
bytes_from_page ) ;
2006-04-10 02:42:35 +04:00
crypto_kunmap ( src , 0 ) ;
2006-08-19 16:24:23 +04:00
crypto_yield ( desc - > flags ) ;
2005-04-17 02:20:36 +04:00
offset = 0 ;
pg + + ;
l - = bytes_from_page ;
} while ( l > 0 ) ;
2006-08-19 16:24:23 +04:00
if ( ! nbytes )
break ;
sg = sg_next ( sg ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-19 16:24:23 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-08-19 16:24:23 +04:00
static int final ( struct hash_desc * desc , u8 * out )
2005-04-17 02:20:36 +04:00
{
2006-08-19 16:24:23 +04:00
struct crypto_tfm * tfm = crypto_hash_tfm ( desc - > tfm ) ;
2006-04-10 02:42:35 +04:00
unsigned long alignmask = crypto_tfm_alg_alignmask ( tfm ) ;
2006-07-09 08:49:42 +04:00
struct digest_alg * digest = & tfm - > __crt_alg - > cra_digest ;
2006-04-10 02:42:35 +04:00
if ( unlikely ( ( unsigned long ) out & alignmask ) ) {
2006-07-09 08:49:42 +04:00
unsigned long align = alignmask + 1 ;
unsigned long addr = ( unsigned long ) crypto_tfm_ctx ( tfm ) ;
u8 * dst = ( u8 * ) ALIGN ( addr , align ) +
ALIGN ( tfm - > __crt_alg - > cra_ctxsize , align ) ;
digest - > dia_final ( tfm , dst ) ;
memcpy ( out , dst , digest - > dia_digestsize ) ;
2006-04-10 02:42:35 +04:00
} else
2006-07-09 08:49:42 +04:00
digest - > dia_final ( tfm , out ) ;
2006-08-19 16:24:23 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-08-19 16:24:23 +04:00
static int nosetkey ( struct crypto_hash * tfm , const u8 * key , unsigned int keylen )
2006-08-13 08:16:39 +04:00
{
2006-08-19 16:24:23 +04:00
crypto_hash_clear_flags ( tfm , CRYPTO_TFM_RES_MASK ) ;
2006-08-13 08:16:39 +04:00
return - ENOSYS ;
}
2006-08-19 16:24:23 +04:00
static int setkey ( struct crypto_hash * hash , const u8 * key , unsigned int keylen )
2005-04-17 02:20:36 +04:00
{
2006-08-19 16:24:23 +04:00
struct crypto_tfm * tfm = crypto_hash_tfm ( hash ) ;
crypto_hash_clear_flags ( hash , CRYPTO_TFM_RES_MASK ) ;
2006-08-13 08:16:39 +04:00
return tfm - > __crt_alg - > cra_digest . dia_setkey ( tfm , key , keylen ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-19 16:24:23 +04:00
static int digest ( struct hash_desc * desc ,
struct scatterlist * sg , unsigned int nbytes , u8 * out )
2005-04-17 02:20:36 +04:00
{
2006-08-19 16:24:23 +04:00
init ( desc ) ;
update ( desc , sg , nbytes ) ;
return final ( desc , out ) ;
2005-04-17 02:20:36 +04:00
}
int crypto_init_digest_flags ( struct crypto_tfm * tfm , u32 flags )
{
return flags ? - EINVAL : 0 ;
}
int crypto_init_digest_ops ( struct crypto_tfm * tfm )
{
2006-08-19 16:24:23 +04:00
struct hash_tfm * ops = & tfm - > crt_hash ;
2006-08-13 08:16:39 +04:00
struct digest_alg * dalg = & tfm - > __crt_alg - > cra_digest ;
2006-08-19 16:24:23 +04:00
if ( dalg - > dia_digestsize > crypto_tfm_alg_blocksize ( tfm ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-08-19 16:24:23 +04:00
ops - > init = init ;
ops - > update = update ;
ops - > final = final ;
ops - > digest = digest ;
ops - > setkey = dalg - > dia_setkey ? setkey : nosetkey ;
ops - > digestsize = dalg - > dia_digestsize ;
2005-04-17 02:20:36 +04:00
2006-08-20 09:25:22 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
void crypto_exit_digest_ops ( struct crypto_tfm * tfm )
{
}