2005-04-17 02:20:36 +04:00
/*
* Cryptographic API .
*
* MD5 Message Digest Algorithm ( RFC1321 ) .
*
* Derived from cryptoapi implementation , originally based on the
* public domain implementation written by Colin Plumb in 1993.
*
* Copyright ( c ) Cryptoapi developers .
* 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 .
*
*/
2008-12-03 14:57:12 +03:00
# include <crypto/internal/hash.h>
2010-01-17 13:55:31 +03:00
# include <crypto/md5.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/string.h>
2005-10-30 13:25:15 +03:00
# include <linux/types.h>
2011-08-04 06:45:10 +04:00
# include <linux/cryptohash.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
2015-12-17 15:45:39 +03:00
const u8 md5_zero_message_hash [ MD5_DIGEST_SIZE ] = {
0xd4 , 0x1d , 0x8c , 0xd9 , 0x8f , 0x00 , 0xb2 , 0x04 ,
0xe9 , 0x80 , 0x09 , 0x98 , 0xec , 0xf8 , 0x42 , 0x7e ,
} ;
EXPORT_SYMBOL_GPL ( md5_zero_message_hash ) ;
2005-04-17 02:20:36 +04:00
/* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array ( u32 * buf , unsigned int words )
{
while ( words - - ) {
__le32_to_cpus ( buf ) ;
buf + + ;
}
}
static inline void cpu_to_le32_array ( u32 * buf , unsigned int words )
{
while ( words - - ) {
__cpu_to_le32s ( buf ) ;
buf + + ;
}
}
2010-01-17 13:55:31 +03:00
static inline void md5_transform_helper ( struct md5_state * ctx )
2005-04-17 02:20:36 +04:00
{
le32_to_cpu_array ( ctx - > block , sizeof ( ctx - > block ) / sizeof ( u32 ) ) ;
md5_transform ( ctx - > hash , ctx - > block ) ;
}
2008-12-03 14:57:12 +03:00
static int md5_init ( struct shash_desc * desc )
2005-04-17 02:20:36 +04:00
{
2010-01-17 13:55:31 +03:00
struct md5_state * mctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
2015-05-17 13:54:13 +03:00
mctx - > hash [ 0 ] = MD5_H0 ;
mctx - > hash [ 1 ] = MD5_H1 ;
mctx - > hash [ 2 ] = MD5_H2 ;
mctx - > hash [ 3 ] = MD5_H3 ;
2005-04-17 02:20:36 +04:00
mctx - > byte_count = 0 ;
2008-12-03 14:57:12 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-03 14:57:12 +03:00
static int md5_update ( struct shash_desc * desc , const u8 * data , unsigned int len )
2005-04-17 02:20:36 +04:00
{
2010-01-17 13:55:31 +03:00
struct md5_state * mctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
const u32 avail = sizeof ( mctx - > block ) - ( mctx - > byte_count & 0x3f ) ;
mctx - > byte_count + = len ;
if ( avail > len ) {
memcpy ( ( char * ) mctx - > block + ( sizeof ( mctx - > block ) - avail ) ,
data , len ) ;
2008-12-03 14:57:12 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
memcpy ( ( char * ) mctx - > block + ( sizeof ( mctx - > block ) - avail ) ,
data , avail ) ;
md5_transform_helper ( mctx ) ;
data + = avail ;
len - = avail ;
while ( len > = sizeof ( mctx - > block ) ) {
memcpy ( mctx - > block , data , sizeof ( mctx - > block ) ) ;
md5_transform_helper ( mctx ) ;
data + = sizeof ( mctx - > block ) ;
len - = sizeof ( mctx - > block ) ;
}
memcpy ( mctx - > block , data , len ) ;
2008-12-03 14:57:12 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-12-03 14:57:12 +03:00
static int md5_final ( struct shash_desc * desc , u8 * out )
2005-04-17 02:20:36 +04:00
{
2010-01-17 13:55:31 +03:00
struct md5_state * mctx = shash_desc_ctx ( desc ) ;
2005-04-17 02:20:36 +04:00
const unsigned int offset = mctx - > byte_count & 0x3f ;
char * p = ( char * ) mctx - > block + offset ;
int padding = 56 - ( offset + 1 ) ;
* p + + = 0x80 ;
if ( padding < 0 ) {
memset ( p , 0x00 , padding + sizeof ( u64 ) ) ;
md5_transform_helper ( mctx ) ;
p = ( char * ) mctx - > block ;
padding = 56 ;
}
memset ( p , 0 , padding ) ;
mctx - > block [ 14 ] = mctx - > byte_count < < 3 ;
mctx - > block [ 15 ] = mctx - > byte_count > > 29 ;
le32_to_cpu_array ( mctx - > block , ( sizeof ( mctx - > block ) -
sizeof ( u64 ) ) / sizeof ( u32 ) ) ;
md5_transform ( mctx - > hash , mctx - > block ) ;
cpu_to_le32_array ( mctx - > hash , sizeof ( mctx - > hash ) / sizeof ( u32 ) ) ;
memcpy ( out , mctx - > hash , sizeof ( mctx - > hash ) ) ;
memset ( mctx , 0 , sizeof ( * mctx ) ) ;
2008-12-03 14:57:12 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-01-17 13:55:31 +03:00
static int md5_export ( struct shash_desc * desc , void * out )
{
struct md5_state * ctx = shash_desc_ctx ( desc ) ;
memcpy ( out , ctx , sizeof ( * ctx ) ) ;
return 0 ;
}
static int md5_import ( struct shash_desc * desc , const void * in )
{
struct md5_state * ctx = shash_desc_ctx ( desc ) ;
memcpy ( ctx , in , sizeof ( * ctx ) ) ;
return 0 ;
}
2008-12-03 14:57:12 +03:00
static struct shash_alg alg = {
. digestsize = MD5_DIGEST_SIZE ,
. init = md5_init ,
. update = md5_update ,
. final = md5_final ,
2010-01-17 13:55:31 +03:00
. export = md5_export ,
. import = md5_import ,
. descsize = sizeof ( struct md5_state ) ,
2010-03-02 16:58:16 +03:00
. statesize = sizeof ( struct md5_state ) ,
2008-12-03 14:57:12 +03:00
. base = {
. cra_name = " md5 " ,
. cra_flags = CRYPTO_ALG_TYPE_SHASH ,
. cra_blocksize = MD5_HMAC_BLOCK_SIZE ,
. cra_module = THIS_MODULE ,
}
2005-04-17 02:20:36 +04:00
} ;
2008-04-05 17:00:57 +04:00
static int __init md5_mod_init ( void )
2005-04-17 02:20:36 +04:00
{
2008-12-03 14:57:12 +03:00
return crypto_register_shash ( & alg ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-05 17:00:57 +04:00
static void __exit md5_mod_fini ( void )
2005-04-17 02:20:36 +04:00
{
2008-12-03 14:57:12 +03:00
crypto_unregister_shash ( & alg ) ;
2005-04-17 02:20:36 +04:00
}
2008-04-05 17:00:57 +04:00
module_init ( md5_mod_init ) ;
module_exit ( md5_mod_fini ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " MD5 Message Digest Algorithm " ) ;
2014-11-21 04:05:53 +03:00
MODULE_ALIAS_CRYPTO ( " md5 " ) ;