2004-04-07 11:20:53 +04:00
/*
Unix SMB / CIFS implementation .
code to encrypt / decrypt data using the user session key
Copyright ( C ) Andrew Tridgell 2004
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-04-07 11:20:53 +04:00
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-04-07 11:20:53 +04:00
*/
# include "includes.h"
2006-03-25 21:47:47 +03:00
# include "libcli/auth/libcli_auth.h"
2004-04-07 11:20:53 +04:00
/*
encrypt or decrypt a blob of data using the user session key
as used in lsa_SetSecret
before calling , the out blob must be initialised to be the same size
as the in blob
*/
2008-12-05 17:19:22 +03:00
void sess_crypt_blob ( DATA_BLOB * out , const DATA_BLOB * in , const DATA_BLOB * session_key ,
2007-10-07 02:28:14 +04:00
bool forward )
2004-04-07 11:20:53 +04:00
{
int i , k ;
for ( i = 0 , k = 0 ;
i < in - > length ;
i + = 8 , k + = 7 ) {
2004-05-25 21:50:17 +04:00
uint8_t bin [ 8 ] , bout [ 8 ] , key [ 7 ] ;
2004-04-07 11:20:53 +04:00
memset ( bin , 0 , 8 ) ;
memcpy ( bin , & in - > data [ i ] , MIN ( 8 , in - > length - i ) ) ;
2004-05-09 17:07:23 +04:00
if ( k + 7 > session_key - > length ) {
k = ( session_key - > length - k ) ;
2004-04-07 11:20:53 +04:00
}
2004-05-09 17:07:23 +04:00
memcpy ( key , & session_key - > data [ k ] , 7 ) ;
2004-04-07 11:20:53 +04:00
2004-06-04 03:15:16 +04:00
des_crypt56 ( bout , bin , key , forward ? 1 : 0 ) ;
2004-04-07 11:20:53 +04:00
memcpy ( & out - > data [ i ] , bout , MIN ( 8 , in - > length - i ) ) ;
}
}
/*
a convenient wrapper around sess_crypt_blob ( ) for strings , using the LSA convention
note that we round the length to a multiple of 8. This seems to be needed for
compatibility with windows
caller should free using data_blob_free ( )
*/
2004-05-09 17:07:23 +04:00
DATA_BLOB sess_encrypt_string ( const char * str , const DATA_BLOB * session_key )
2004-04-07 11:20:53 +04:00
{
DATA_BLOB ret , src ;
int slen = strlen ( str ) ;
int dlen = ( slen + 7 ) & ~ 7 ;
src = data_blob ( NULL , 8 + dlen ) ;
if ( ! src . data ) {
return data_blob ( NULL , 0 ) ;
}
ret = data_blob ( NULL , 8 + dlen ) ;
if ( ! ret . data ) {
data_blob_free ( & src ) ;
return data_blob ( NULL , 0 ) ;
}
SIVAL ( src . data , 0 , slen ) ;
SIVAL ( src . data , 4 , 1 ) ;
memset ( src . data + 8 , 0 , dlen ) ;
memcpy ( src . data + 8 , str , slen ) ;
2007-10-07 02:28:14 +04:00
sess_crypt_blob ( & ret , & src , session_key , true ) ;
2004-04-07 11:20:53 +04:00
data_blob_free ( & src ) ;
return ret ;
}
/*
a convenient wrapper around sess_crypt_blob ( ) for strings , using the LSA convention
caller should free the returned string
*/
2006-09-28 10:44:47 +04:00
char * sess_decrypt_string ( TALLOC_CTX * mem_ctx ,
DATA_BLOB * blob , const DATA_BLOB * session_key )
2004-04-07 11:20:53 +04:00
{
DATA_BLOB out ;
int slen ;
char * ret ;
if ( blob - > length < 8 ) {
return NULL ;
}
2006-09-28 10:44:47 +04:00
out = data_blob_talloc ( mem_ctx , NULL , blob - > length ) ;
2004-04-07 11:20:53 +04:00
if ( ! out . data ) {
return NULL ;
}
2007-10-07 02:28:14 +04:00
sess_crypt_blob ( & out , blob , session_key , false ) ;
2004-04-07 11:20:53 +04:00
if ( IVAL ( out . data , 4 ) ! = 1 ) {
DEBUG ( 0 , ( " Unexpected revision number %d in session crypted string \n " ,
IVAL ( out . data , 4 ) ) ) ;
2006-09-28 10:44:47 +04:00
data_blob_free ( & out ) ;
2004-04-07 11:20:53 +04:00
return NULL ;
}
2004-11-25 22:21:55 +03:00
2005-01-11 17:04:58 +03:00
slen = IVAL ( out . data , 0 ) ;
if ( slen > blob - > length - 8 ) {
DEBUG ( 0 , ( " Invalid crypt length %d \n " , slen ) ) ;
2006-09-28 10:44:47 +04:00
data_blob_free ( & out ) ;
2005-01-11 17:04:58 +03:00
return NULL ;
}
2006-09-28 10:44:47 +04:00
ret = talloc_strndup ( mem_ctx , ( const char * ) ( out . data + 8 ) , slen ) ;
2004-04-07 11:20:53 +04:00
data_blob_free ( & out ) ;
2006-09-28 10:44:47 +04:00
DEBUG ( 0 , ( " decrypted string '%s' of length %d \n " , ret , slen ) ) ;
2004-04-07 11:20:53 +04:00
return ret ;
}
2004-11-17 15:27:16 +03:00
/*
a convenient wrapper around sess_crypt_blob ( ) for DATA_BLOBs , using the LSA convention
note that we round the length to a multiple of 8. This seems to be needed for
compatibility with windows
caller should free using data_blob_free ( )
*/
DATA_BLOB sess_encrypt_blob ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob_in , const DATA_BLOB * session_key )
{
DATA_BLOB ret , src ;
int dlen = ( blob_in - > length + 7 ) & ~ 7 ;
src = data_blob_talloc ( mem_ctx , NULL , 8 + dlen ) ;
if ( ! src . data ) {
return data_blob ( NULL , 0 ) ;
}
2006-05-23 10:52:22 +04:00
ret = data_blob_talloc ( mem_ctx , NULL , 8 + dlen ) ;
2004-11-17 15:27:16 +03:00
if ( ! ret . data ) {
data_blob_free ( & src ) ;
return data_blob ( NULL , 0 ) ;
}
SIVAL ( src . data , 0 , blob_in - > length ) ;
SIVAL ( src . data , 4 , 1 ) ;
memset ( src . data + 8 , 0 , dlen ) ;
memcpy ( src . data + 8 , blob_in - > data , blob_in - > length ) ;
2007-10-07 02:28:14 +04:00
sess_crypt_blob ( & ret , & src , session_key , true ) ;
2004-11-17 15:27:16 +03:00
data_blob_free ( & src ) ;
return ret ;
}
/*
2005-01-11 17:04:58 +03:00
Decrypt a DATA_BLOB using the LSA convention
2004-11-17 15:27:16 +03:00
*/
2005-01-11 17:04:58 +03:00
NTSTATUS sess_decrypt_blob ( TALLOC_CTX * mem_ctx , const DATA_BLOB * blob , const DATA_BLOB * session_key ,
DATA_BLOB * ret )
2004-11-17 15:27:16 +03:00
{
DATA_BLOB out ;
int slen ;
if ( blob - > length < 8 ) {
2005-03-18 06:17:30 +03:00
DEBUG ( 0 , ( " Unexpected length %d in session crypted secret (BLOB) \n " ,
2005-07-17 13:20:52 +04:00
( int ) blob - > length ) ) ;
2005-01-11 17:04:58 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2004-11-17 15:27:16 +03:00
}
out = data_blob_talloc ( mem_ctx , NULL , blob - > length ) ;
if ( ! out . data ) {
2005-01-11 17:04:58 +03:00
return NT_STATUS_NO_MEMORY ;
2004-11-17 15:27:16 +03:00
}
2007-10-07 02:28:14 +04:00
sess_crypt_blob ( & out , blob , session_key , false ) ;
2004-11-17 15:27:16 +03:00
2005-01-11 17:04:58 +03:00
if ( IVAL ( out . data , 4 ) ! = 1 ) {
2005-06-19 00:32:21 +04:00
DEBUG ( 2 , ( " Unexpected revision number %d in session crypted secret (BLOB) \n " ,
2005-01-11 17:04:58 +03:00
IVAL ( out . data , 4 ) ) ) ;
return NT_STATUS_UNKNOWN_REVISION ;
}
2004-11-17 15:27:16 +03:00
slen = IVAL ( out . data , 0 ) ;
if ( slen > blob - > length - 8 ) {
2005-03-18 06:17:30 +03:00
DEBUG ( 0 , ( " Invalid crypt length %d in session crypted secret (BLOB) \n " , slen ) ) ;
2005-01-11 17:04:58 +03:00
return NT_STATUS_WRONG_PASSWORD ;
2004-11-17 15:27:16 +03:00
}
2005-01-11 17:04:58 +03:00
* ret = data_blob_talloc ( mem_ctx , out . data + 8 , slen ) ;
2005-03-18 06:17:30 +03:00
if ( slen & & ! ret - > data ) {
2005-01-11 17:04:58 +03:00
return NT_STATUS_NO_MEMORY ;
2004-11-17 15:27:16 +03:00
}
data_blob_free ( & out ) ;
2005-01-11 17:04:58 +03:00
return NT_STATUS_OK ;
2004-11-17 15:27:16 +03:00
}