2007-07-07 23:25:05 +04:00
/*
2005-04-17 02:20:36 +04:00
Unix SMB / Netbios implementation .
Version 1.9 .
SMB parameters and setup
Copyright ( C ) Andrew Tridgell 1992 - 2000
Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 2000
Modified by Jeremy Allison 1995.
Copyright ( C ) Andrew Bartlett < abartlet @ samba . org > 2002 - 2003
Modified by Steve French ( sfrench @ us . ibm . com ) 2002 - 2003
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
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 .
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2007-07-13 04:33:32 +04:00
2005-04-17 02:20:36 +04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/random.h>
# include "cifs_unicode.h"
# include "cifspdu.h"
2006-06-01 02:40:51 +04:00
# include "cifsglob.h"
2005-04-17 02:20:36 +04:00
# include "md5.h"
# include "cifs_debug.h"
# include "cifsencrypt.h"
2008-04-29 04:06:05 +04:00
# ifndef false
# define false 0
2005-04-17 02:20:36 +04:00
# endif
2008-04-29 04:06:05 +04:00
# ifndef true
# define true 1
2005-04-17 02:20:36 +04:00
# endif
/* following came from the other byteorder.h to avoid include conflicts */
# define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
# define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
# define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
/*The following definitions come from libsmb/smbencrypt.c */
2008-12-06 04:41:21 +03:00
void SMBencrypt ( unsigned char * passwd , const unsigned char * c8 ,
unsigned char * p24 ) ;
2005-04-17 02:20:36 +04:00
void E_md4hash ( const unsigned char * passwd , unsigned char * p16 ) ;
2008-12-06 04:41:21 +03:00
static void SMBOWFencrypt ( unsigned char passwd [ 16 ] , const unsigned char * c8 ,
2005-04-17 02:20:36 +04:00
unsigned char p24 [ 24 ] ) ;
void SMBNTencrypt ( unsigned char * passwd , unsigned char * c8 , unsigned char * p24 ) ;
/*
This implements the X / Open SMB password encryption
2007-07-07 23:25:05 +04:00
It takes a password , a 8 byte " crypt key " and puts 24 bytes of
2005-04-17 02:20:36 +04:00
encrypted password into p24 */
/* Note that password must be uppercased and null terminated */
void
2008-12-06 04:41:21 +03:00
SMBencrypt ( unsigned char * passwd , const unsigned char * c8 , unsigned char * p24 )
2005-04-17 02:20:36 +04:00
{
unsigned char p14 [ 15 ] , p21 [ 21 ] ;
memset ( p21 , ' \0 ' , 21 ) ;
memset ( p14 , ' \0 ' , 14 ) ;
strncpy ( ( char * ) p14 , ( char * ) passwd , 14 ) ;
/* strupper((char *)p14); */ /* BB at least uppercase the easy range */
E_P16 ( p14 , p21 ) ;
SMBOWFencrypt ( p21 , c8 , p24 ) ;
2007-07-13 04:33:32 +04:00
2007-07-07 23:25:05 +04:00
memset ( p14 , 0 , 15 ) ;
memset ( p21 , 0 , 21 ) ;
2005-04-17 02:20:36 +04:00
}
/* Routines for Windows NT MD4 Hash functions. */
static int
2007-11-06 00:46:10 +03:00
_my_wcslen ( __u16 * str )
2005-04-17 02:20:36 +04:00
{
int len = 0 ;
while ( * str + + ! = 0 )
len + + ;
return len ;
}
/*
* Convert a string into an NT UNICODE string .
2007-07-07 23:25:05 +04:00
* Note that regardless of processor type
2005-04-17 02:20:36 +04:00
* this must be in intel ( little - endian )
* format .
*/
static int
2007-11-06 00:46:10 +03:00
_my_mbstowcs ( __u16 * dst , const unsigned char * src , int len )
2007-07-07 23:25:05 +04:00
{ /* BB not a very good conversion routine - change/fix */
2005-04-17 02:20:36 +04:00
int i ;
__u16 val ;
for ( i = 0 ; i < len ; i + + ) {
val = * src ;
SSVAL ( dst , 0 , val ) ;
dst + + ;
src + + ;
if ( val = = 0 )
break ;
}
return i ;
}
2007-07-07 23:25:05 +04:00
/*
2005-04-17 02:20:36 +04:00
* Creates the MD4 Hash of the users password in NT UNICODE .
*/
void
E_md4hash ( const unsigned char * passwd , unsigned char * p16 )
{
int len ;
__u16 wpwd [ 129 ] ;
/* Password cannot be longer than 128 characters */
2007-07-07 23:25:05 +04:00
if ( passwd ) {
2005-04-17 02:20:36 +04:00
len = strlen ( ( char * ) passwd ) ;
2007-11-06 00:46:10 +03:00
if ( len > 128 )
2005-04-17 02:20:36 +04:00
len = 128 ;
2007-11-06 00:46:10 +03:00
2005-04-17 02:20:36 +04:00
/* Password must be converted to NT unicode */
_my_mbstowcs ( wpwd , passwd , len ) ;
} else
len = 0 ;
wpwd [ len ] = 0 ; /* Ensure string is null terminated */
/* Calculate length in bytes */
2007-10-26 01:17:17 +04:00
len = _my_wcslen ( wpwd ) * sizeof ( __u16 ) ;
2005-04-17 02:20:36 +04:00
mdfour ( p16 , ( unsigned char * ) wpwd , len ) ;
2007-07-07 23:25:05 +04:00
memset ( wpwd , 0 , 129 * 2 ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-29 00:49:01 +04:00
#if 0 /* currently unused */
2005-04-17 02:20:36 +04:00
/* Does both the NT and LM owfs of a user's password */
2006-09-28 23:43:08 +04:00
static void
2005-04-17 02:20:36 +04:00
nt_lm_owf_gen ( char * pwd , unsigned char nt_p16 [ 16 ] , unsigned char p16 [ 16 ] )
{
char passwd [ 514 ] ;
memset ( passwd , ' \0 ' , 514 ) ;
if ( strlen ( pwd ) < 513 )
strcpy ( passwd , pwd ) ;
else
memcpy ( passwd , pwd , 512 ) ;
/* Calculate the MD4 hash (NT compatible) of the password */
memset ( nt_p16 , ' \0 ' , 16 ) ;
E_md4hash ( passwd , nt_p16 ) ;
/* Mangle the passwords into Lanman format */
passwd [ 14 ] = ' \0 ' ;
/* strupper(passwd); */
/* Calculate the SMB (lanman) hash functions of the password */
memset ( p16 , ' \0 ' , 16 ) ;
E_P16 ( ( unsigned char * ) passwd , ( unsigned char * ) p16 ) ;
/* clear out local copy of user's password (just being paranoid). */
2007-10-26 01:17:17 +04:00
memset ( passwd , ' \0 ' , sizeof ( passwd ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-29 00:49:01 +04:00
# endif
2005-04-17 02:20:36 +04:00
/* Does the NTLMv2 owfs of a user's password */
#if 0 /* function not needed yet - but will be soon */
static void
ntv2_owf_gen ( const unsigned char owf [ 16 ] , const char * user_n ,
const char * domain_n , unsigned char kr_buf [ 16 ] ,
const struct nls_table * nls_codepage )
{
2007-07-13 04:33:32 +04:00
wchar_t * user_u ;
wchar_t * dom_u ;
2005-04-17 02:20:36 +04:00
int user_l , domain_l ;
struct HMACMD5Context ctx ;
/* might as well do one alloc to hold both (user_u and dom_u) */
2007-07-07 23:25:05 +04:00
user_u = kmalloc ( 2048 * sizeof ( wchar_t ) , GFP_KERNEL ) ;
if ( user_u = = NULL )
2005-04-17 02:20:36 +04:00
return ;
dom_u = user_u + 1024 ;
2007-07-13 04:33:32 +04:00
2007-11-06 00:46:10 +03:00
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2,
STR_UNICODE | STR_NOALIGN | STR_TERMINATE | STR_UPPER ) ;
push_ucs2 ( NULL , dom_u , domain_n , ( domain_l + 1 ) * 2 ,
STR_UNICODE | STR_NOALIGN | STR_TERMINATE | STR_UPPER ) ; */
2005-04-17 02:20:36 +04:00
/* BB user and domain may need to be uppercased */
user_l = cifs_strtoUCS ( user_u , user_n , 511 , nls_codepage ) ;
domain_l = cifs_strtoUCS ( dom_u , domain_n , 511 , nls_codepage ) ;
user_l + + ; /* trailing null */
domain_l + + ;
hmac_md5_init_limK_to_64 ( owf , 16 , & ctx ) ;
hmac_md5_update ( ( const unsigned char * ) user_u , user_l * 2 , & ctx ) ;
hmac_md5_update ( ( const unsigned char * ) dom_u , domain_l * 2 , & ctx ) ;
hmac_md5_final ( kr_buf , & ctx ) ;
kfree ( user_u ) ;
}
2007-07-07 23:25:05 +04:00
# endif
2005-04-17 02:20:36 +04:00
/* Does the des encryption from the NT or LM MD4 hash. */
static void
2008-12-06 04:41:21 +03:00
SMBOWFencrypt ( unsigned char passwd [ 16 ] , const unsigned char * c8 ,
2005-04-17 02:20:36 +04:00
unsigned char p24 [ 24 ] )
{
unsigned char p21 [ 21 ] ;
memset ( p21 , ' \0 ' , 21 ) ;
memcpy ( p21 , passwd , 16 ) ;
E_P24 ( p21 , c8 , p24 ) ;
}
/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
2006-09-29 00:49:01 +04:00
#if 0 /* currently unused */
2006-09-28 23:43:08 +04:00
static void
2005-04-17 02:20:36 +04:00
NTLMSSPOWFencrypt ( unsigned char passwd [ 8 ] ,
unsigned char * ntlmchalresp , unsigned char p24 [ 24 ] )
{
unsigned char p21 [ 21 ] ;
memset ( p21 , ' \0 ' , 21 ) ;
memcpy ( p21 , passwd , 8 ) ;
memset ( p21 + 8 , 0xbd , 8 ) ;
E_P24 ( p21 , ntlmchalresp , p24 ) ;
}
2006-09-29 00:49:01 +04:00
# endif
2005-04-17 02:20:36 +04:00
/* Does the NT MD4 hash then des encryption. */
void
SMBNTencrypt ( unsigned char * passwd , unsigned char * c8 , unsigned char * p24 )
{
unsigned char p21 [ 21 ] ;
memset ( p21 , ' \0 ' , 21 ) ;
E_md4hash ( passwd , p21 ) ;
SMBOWFencrypt ( p21 , c8 , p24 ) ;
}
/* Does the md5 encryption from the NT hash for NTLMv2. */
/* These routines will be needed later */
#if 0
static void
SMBOWFencrypt_ntv2 ( const unsigned char kr [ 16 ] ,
2007-07-07 23:25:05 +04:00
const struct data_blob * srv_chal ,
const struct data_blob * cli_chal , unsigned char resp_buf [ 16 ] )
2005-04-17 02:20:36 +04:00
{
2007-07-07 23:25:05 +04:00
struct HMACMD5Context ctx ;
2005-04-17 02:20:36 +04:00
2007-07-07 23:25:05 +04:00
hmac_md5_init_limK_to_64 ( kr , 16 , & ctx ) ;
hmac_md5_update ( srv_chal - > data , srv_chal - > length , & ctx ) ;
hmac_md5_update ( cli_chal - > data , cli_chal - > length , & ctx ) ;
hmac_md5_final ( resp_buf , & ctx ) ;
2005-04-17 02:20:36 +04:00
}
static void
SMBsesskeygen_ntv2 ( const unsigned char kr [ 16 ] ,
const unsigned char * nt_resp , __u8 sess_key [ 16 ] )
{
struct HMACMD5Context ctx ;
hmac_md5_init_limK_to_64 ( kr , 16 , & ctx ) ;
hmac_md5_update ( nt_resp , 16 , & ctx ) ;
hmac_md5_final ( ( unsigned char * ) sess_key , & ctx ) ;
}
static void
SMBsesskeygen_ntv1 ( const unsigned char kr [ 16 ] ,
const unsigned char * nt_resp , __u8 sess_key [ 16 ] )
{
mdfour ( ( unsigned char * ) sess_key , ( unsigned char * ) kr , 16 ) ;
}
# endif