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>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# define F1(x, y, z) (z ^ (x & (y ^ z)))
# define F2(x, y, z) F1(z, x, y)
# define F3(x, y, z) (x ^ y ^ z)
# define F4(x, y, z) (y ^ (x | ~z))
# define MD5STEP(f, w, x, y, z, in, s) \
( w + = f ( x , y , z ) + in , w = ( w < < s | w > > ( 32 - s ) ) + x )
static void md5_transform ( u32 * hash , u32 const * in )
{
u32 a , b , c , d ;
a = hash [ 0 ] ;
b = hash [ 1 ] ;
c = hash [ 2 ] ;
d = hash [ 3 ] ;
MD5STEP ( F1 , a , b , c , d , in [ 0 ] + 0xd76aa478 , 7 ) ;
MD5STEP ( F1 , d , a , b , c , in [ 1 ] + 0xe8c7b756 , 12 ) ;
MD5STEP ( F1 , c , d , a , b , in [ 2 ] + 0x242070db , 17 ) ;
MD5STEP ( F1 , b , c , d , a , in [ 3 ] + 0xc1bdceee , 22 ) ;
MD5STEP ( F1 , a , b , c , d , in [ 4 ] + 0xf57c0faf , 7 ) ;
MD5STEP ( F1 , d , a , b , c , in [ 5 ] + 0x4787c62a , 12 ) ;
MD5STEP ( F1 , c , d , a , b , in [ 6 ] + 0xa8304613 , 17 ) ;
MD5STEP ( F1 , b , c , d , a , in [ 7 ] + 0xfd469501 , 22 ) ;
MD5STEP ( F1 , a , b , c , d , in [ 8 ] + 0x698098d8 , 7 ) ;
MD5STEP ( F1 , d , a , b , c , in [ 9 ] + 0x8b44f7af , 12 ) ;
MD5STEP ( F1 , c , d , a , b , in [ 10 ] + 0xffff5bb1 , 17 ) ;
MD5STEP ( F1 , b , c , d , a , in [ 11 ] + 0x895cd7be , 22 ) ;
MD5STEP ( F1 , a , b , c , d , in [ 12 ] + 0x6b901122 , 7 ) ;
MD5STEP ( F1 , d , a , b , c , in [ 13 ] + 0xfd987193 , 12 ) ;
MD5STEP ( F1 , c , d , a , b , in [ 14 ] + 0xa679438e , 17 ) ;
MD5STEP ( F1 , b , c , d , a , in [ 15 ] + 0x49b40821 , 22 ) ;
MD5STEP ( F2 , a , b , c , d , in [ 1 ] + 0xf61e2562 , 5 ) ;
MD5STEP ( F2 , d , a , b , c , in [ 6 ] + 0xc040b340 , 9 ) ;
MD5STEP ( F2 , c , d , a , b , in [ 11 ] + 0x265e5a51 , 14 ) ;
MD5STEP ( F2 , b , c , d , a , in [ 0 ] + 0xe9b6c7aa , 20 ) ;
MD5STEP ( F2 , a , b , c , d , in [ 5 ] + 0xd62f105d , 5 ) ;
MD5STEP ( F2 , d , a , b , c , in [ 10 ] + 0x02441453 , 9 ) ;
MD5STEP ( F2 , c , d , a , b , in [ 15 ] + 0xd8a1e681 , 14 ) ;
MD5STEP ( F2 , b , c , d , a , in [ 4 ] + 0xe7d3fbc8 , 20 ) ;
MD5STEP ( F2 , a , b , c , d , in [ 9 ] + 0x21e1cde6 , 5 ) ;
MD5STEP ( F2 , d , a , b , c , in [ 14 ] + 0xc33707d6 , 9 ) ;
MD5STEP ( F2 , c , d , a , b , in [ 3 ] + 0xf4d50d87 , 14 ) ;
MD5STEP ( F2 , b , c , d , a , in [ 8 ] + 0x455a14ed , 20 ) ;
MD5STEP ( F2 , a , b , c , d , in [ 13 ] + 0xa9e3e905 , 5 ) ;
MD5STEP ( F2 , d , a , b , c , in [ 2 ] + 0xfcefa3f8 , 9 ) ;
MD5STEP ( F2 , c , d , a , b , in [ 7 ] + 0x676f02d9 , 14 ) ;
MD5STEP ( F2 , b , c , d , a , in [ 12 ] + 0x8d2a4c8a , 20 ) ;
MD5STEP ( F3 , a , b , c , d , in [ 5 ] + 0xfffa3942 , 4 ) ;
MD5STEP ( F3 , d , a , b , c , in [ 8 ] + 0x8771f681 , 11 ) ;
MD5STEP ( F3 , c , d , a , b , in [ 11 ] + 0x6d9d6122 , 16 ) ;
MD5STEP ( F3 , b , c , d , a , in [ 14 ] + 0xfde5380c , 23 ) ;
MD5STEP ( F3 , a , b , c , d , in [ 1 ] + 0xa4beea44 , 4 ) ;
MD5STEP ( F3 , d , a , b , c , in [ 4 ] + 0x4bdecfa9 , 11 ) ;
MD5STEP ( F3 , c , d , a , b , in [ 7 ] + 0xf6bb4b60 , 16 ) ;
MD5STEP ( F3 , b , c , d , a , in [ 10 ] + 0xbebfbc70 , 23 ) ;
MD5STEP ( F3 , a , b , c , d , in [ 13 ] + 0x289b7ec6 , 4 ) ;
MD5STEP ( F3 , d , a , b , c , in [ 0 ] + 0xeaa127fa , 11 ) ;
MD5STEP ( F3 , c , d , a , b , in [ 3 ] + 0xd4ef3085 , 16 ) ;
MD5STEP ( F3 , b , c , d , a , in [ 6 ] + 0x04881d05 , 23 ) ;
MD5STEP ( F3 , a , b , c , d , in [ 9 ] + 0xd9d4d039 , 4 ) ;
MD5STEP ( F3 , d , a , b , c , in [ 12 ] + 0xe6db99e5 , 11 ) ;
MD5STEP ( F3 , c , d , a , b , in [ 15 ] + 0x1fa27cf8 , 16 ) ;
MD5STEP ( F3 , b , c , d , a , in [ 2 ] + 0xc4ac5665 , 23 ) ;
MD5STEP ( F4 , a , b , c , d , in [ 0 ] + 0xf4292244 , 6 ) ;
MD5STEP ( F4 , d , a , b , c , in [ 7 ] + 0x432aff97 , 10 ) ;
MD5STEP ( F4 , c , d , a , b , in [ 14 ] + 0xab9423a7 , 15 ) ;
MD5STEP ( F4 , b , c , d , a , in [ 5 ] + 0xfc93a039 , 21 ) ;
MD5STEP ( F4 , a , b , c , d , in [ 12 ] + 0x655b59c3 , 6 ) ;
MD5STEP ( F4 , d , a , b , c , in [ 3 ] + 0x8f0ccc92 , 10 ) ;
MD5STEP ( F4 , c , d , a , b , in [ 10 ] + 0xffeff47d , 15 ) ;
MD5STEP ( F4 , b , c , d , a , in [ 1 ] + 0x85845dd1 , 21 ) ;
MD5STEP ( F4 , a , b , c , d , in [ 8 ] + 0x6fa87e4f , 6 ) ;
MD5STEP ( F4 , d , a , b , c , in [ 15 ] + 0xfe2ce6e0 , 10 ) ;
MD5STEP ( F4 , c , d , a , b , in [ 6 ] + 0xa3014314 , 15 ) ;
MD5STEP ( F4 , b , c , d , a , in [ 13 ] + 0x4e0811a1 , 21 ) ;
MD5STEP ( F4 , a , b , c , d , in [ 4 ] + 0xf7537e82 , 6 ) ;
MD5STEP ( F4 , d , a , b , c , in [ 11 ] + 0xbd3af235 , 10 ) ;
MD5STEP ( F4 , c , d , a , b , in [ 2 ] + 0x2ad7d2bb , 15 ) ;
MD5STEP ( F4 , b , c , d , a , in [ 9 ] + 0xeb86d391 , 21 ) ;
hash [ 0 ] + = a ;
hash [ 1 ] + = b ;
hash [ 2 ] + = c ;
hash [ 3 ] + = d ;
}
/* 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
mctx - > hash [ 0 ] = 0x67452301 ;
mctx - > hash [ 1 ] = 0xefcdab89 ;
mctx - > hash [ 2 ] = 0x98badcfe ;
mctx - > hash [ 3 ] = 0x10325476 ;
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 " ) ;