diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 30783c4e6d..8a3c8f9346 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,23 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-01-08 14:00 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/contrib/hbnetio/netiocli.c + * pacified BCC warning + + * harbour/include/hbznet.h + * harbour/src/rtl/hbznet.c + + added support for blowfish encryption in HB_ZNETSTREAM + + added C function + void hb_znetEncryptKey( PHB_ZNETSTREAM pStream, + const void * keydata, int keylen ); + which enables data encryption in HB_ZNETSTREAM + + added 4-th parameter to to .PRG HB_INETCOMPRESS() function: + HB_INETCOMPRESS( , [], [], + [] ) + is initial value to create blowfish key. + Please test. + 2010-01-08 12:25 UTC+0100 Viktor Szakats (harbour.01 syenar.hu) * config/wce/msvcarm.mk ! Fixed typo in prev modification. diff --git a/harbour/contrib/hbnetio/netiocli.c b/harbour/contrib/hbnetio/netiocli.c index b23523197d..6700ac09fd 100644 --- a/harbour/contrib/hbnetio/netiocli.c +++ b/harbour/contrib/hbnetio/netiocli.c @@ -499,7 +499,7 @@ static const char * s_netio_params( int iMsg, const char * pszName, UINT32 * pSi { int iPCount = iMsg == NETIO_PROCIS ? 0 : hb_pcount(), i; char * data = NULL, * itmData; - ULONG size = 0, itmSize; + ULONG size, itmSize; size = ( ULONG ) strlen( pszName ) + 1; diff --git a/harbour/include/hbznet.h b/harbour/include/hbznet.h index 34e13f5f52..26acd0ab5c 100644 --- a/harbour/include/hbznet.h +++ b/harbour/include/hbznet.h @@ -72,6 +72,7 @@ typedef void ( * HB_INET_CFUNC ) ( PHB_ZNETSTREAM ); extern HB_EXPORT int hb_znetError( PHB_ZNETSTREAM pStream ); extern HB_EXPORT PHB_ZNETSTREAM hb_znetOpen( int level, int strategy ); +extern HB_EXPORT void hb_znetEncryptKey( PHB_ZNETSTREAM pStream, const void * keydata, int keylen ); extern HB_EXPORT void hb_znetClose( PHB_ZNETSTREAM pStream ); extern HB_EXPORT int hb_znetError( PHB_ZNETSTREAM pStream ); extern HB_EXPORT long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_LONG timeout ); diff --git a/harbour/src/rtl/hbznet.c b/harbour/src/rtl/hbznet.c index 9233dafb16..127c545982 100644 --- a/harbour/src/rtl/hbznet.c +++ b/harbour/src/rtl/hbznet.c @@ -56,6 +56,7 @@ #include "hbapiitm.h" #include "hbapierr.h" #include "hbsocket.h" +#include "hbbfish.h" #include "hbznet.h" #include "hbzlib.ch" @@ -66,8 +67,15 @@ typedef struct _HB_ZNETSTREAM z_stream rd; /* input stream */ z_stream wr; /* output stream */ int err; /* error code for last stream operation */ + int crypt; /* encryption */ + uInt crypt_in; /* number of encrypted characters in buffer */ + uInt crypt_size; /* size of encrypted block */ + uInt skip_in; /* encryption block padding bytes */ + uInt skip_out; /* room for block size */ + Bytef * crypt_out; /* block size offset for encrypted blocks */ Bytef * inbuf; /* input buffer */ Bytef * outbuf; /* output buffer */ + HB_BLOWFISH * bf; } HB_ZNETSTREAM; @@ -95,6 +103,9 @@ void hb_znetClose( PHB_ZNETSTREAM pStream ) if( pStream->outbuf ) hb_xfree( pStream->outbuf ); + if( pStream->bf ) + hb_xfree( pStream->bf ); + deflateEnd( &pStream->wr ); inflateEnd( &pStream->rd ); @@ -124,6 +135,55 @@ PHB_ZNETSTREAM hb_znetOpen( int level, int strategy ) return NULL; } +/* set encryption key + */ +void hb_znetEncryptKey( PHB_ZNETSTREAM pStream, const void * keydata, int keylen ) +{ + if( pStream->crypt == 0 ) + { + pStream->crypt = 1; + + /* initialize encryption key */ + pStream->bf = ( HB_BLOWFISH * ) hb_xgrab( sizeof( HB_BLOWFISH ) ); + hb_blowfishInit( pStream->bf, keydata, keylen ); + + /* initialize input buffer */ + pStream->skip_in = 0; + pStream->crypt_size = 0; + pStream->crypt_in = pStream->rd.avail_in; + pStream->rd.avail_in = 0; + + /* initialize output buffer */ + pStream->crypt_out = pStream->wr.next_out; + pStream->wr.next_out += 2; + if( pStream->wr.avail_out < 2 ) + pStream->skip_out = 2 - pStream->wr.avail_out; + else + pStream->skip_out = 0; + pStream->wr.avail_out -= 2 - pStream->skip_out; + } +} + +static void hb_znetDecrypt( PHB_ZNETSTREAM pStream, Bytef * data ) +{ + UINT32 xl, xr; + xl = HB_GET_BE_UINT32( data ); + xr = HB_GET_BE_UINT32( data + 4 ); + hb_blowfishDecrypt( pStream->bf, &xl, &xr ); + HB_PUT_BE_UINT32( data, xl ); + HB_PUT_BE_UINT32( data + 4, xr ); +} + +static void hb_znetEncrypt( PHB_ZNETSTREAM pStream, Bytef * data ) +{ + UINT32 xl, xr; + xl = HB_GET_BE_UINT32( data ); + xr = HB_GET_BE_UINT32( data + 4 ); + hb_blowfishEncrypt( pStream->bf, &xl, &xr ); + HB_PUT_BE_UINT32( data, xl ); + HB_PUT_BE_UINT32( data + 4, xr ); +} + /* read data using stream structure */ long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, HB_LONG timeout ) @@ -138,17 +198,67 @@ long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, { if( pStream->rd.avail_in == 0 && pStream->err == Z_STREAM_END ) { - if( pStream->rd.avail_out != ( uInt ) len ) - timeout = 0; - rec = hb_socketRecv( sd, pStream->inbuf, HB_ZNET_BUFSIZE, 0, timeout ); - if( rec <= 0 ) - break; - pStream->rd.avail_in = ( uInt ) rec; + if( pStream->skip_in ) + { + pStream->rd.next_in += pStream->skip_in; + pStream->skip_in = 0; + } + if( pStream->crypt_in && pStream->rd.next_in > pStream->inbuf ) + memmove( pStream->inbuf, pStream->rd.next_in, pStream->crypt_in ); pStream->rd.next_in = pStream->inbuf; + + if( !pStream->crypt || pStream->crypt_in < 8 ) + { + if( pStream->rd.avail_out != ( uInt ) len ) + timeout = 0; + rec = hb_socketRecv( sd, pStream->inbuf + pStream->crypt_in, HB_ZNET_BUFSIZE - pStream->crypt_in, 0, timeout ); + if( rec <= 0 ) + break; + } + + if( pStream->crypt ) + { + pStream->crypt_in += rec; + if( pStream->crypt_size == 0 ) + { + if( pStream->crypt_in >= 8 ) + { + hb_znetDecrypt( pStream, pStream->rd.next_in ); + pStream->crypt_size = HB_GET_BE_UINT16( pStream->rd.next_in ); + pStream->rd.next_in += 2; + pStream->crypt_in -= 8; + rec = HB_MIN( pStream->crypt_size, 6 ); + pStream->crypt_size -= ( uInt ) rec; + pStream->rd.avail_in += ( uInt ) rec; + pStream->skip_in = ( uInt ) ( 6 - rec ); + rec = 0; + } + } + if( pStream->skip_in == 0 ) + { + long l = ( pStream->crypt_size + 0x07 ) & ~0x07; + rec = pStream->crypt_in & ~0x07; + if( rec > l ) + rec = l; + /* decrypt the buffer */ + for( l = 0; l < rec; l += 8 ) + hb_znetDecrypt( pStream, pStream->rd.next_in + pStream->rd.avail_in + l ); + pStream->crypt_in -= rec; + if( rec > pStream->crypt_size ) + { + pStream->skip_in = rec - pStream->crypt_size; + rec = pStream->crypt_size; + } + pStream->crypt_size -= rec; + } + } + pStream->rd.avail_in += ( uInt ) rec; + if( pStream->rd.avail_in == 0 ) + break; rec = 0; } pStream->err = inflate( &pStream->rd, Z_SYNC_FLUSH ); - if( pStream->err == Z_BUF_ERROR ) + if( pStream->err == Z_BUF_ERROR && pStream->rd.avail_in == 0 ) pStream->err = Z_STREAM_END; if( pStream->err != Z_OK && pStream->err != Z_STREAM_END ) break; @@ -162,17 +272,71 @@ long hb_znetRead( PHB_ZNETSTREAM pStream, HB_SOCKET sd, void * buffer, long len, static long hb_znetStreamWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG timeout ) { long tosnd = HB_ZNET_BUFSIZE - pStream->wr.avail_out; - long snd = 0; + long snd = 0, rest = 0; + + if( pStream->crypt ) + { + long size = ( long ) ( pStream->wr.next_out - pStream->crypt_out ); + + if( size > 2 ) + { + UINT16 uiLen = ( UINT16 ) ( size - 2 ); + HB_PUT_BE_UINT16( pStream->crypt_out, uiLen ); + uiLen = ( UINT16 ) ( ( ( size + 7 ) ^ 0x07 ) & 0x07 ); + if( uiLen > pStream->wr.avail_out ) + { + /* it may happen only if encryption was enabled in non empty + * buffer and the unencrypted part has not been flushed yet. + */ + rest = size; + } + else + { + while( uiLen-- ) + { + *pStream->wr.next_out++ = ( Byte ) 0; /* TODO: use better hashing data */ + pStream->wr.avail_out--; + size++; + } + /* encrypt the buffer */ + for( tosnd = 0; tosnd < size; tosnd += 8 ) + hb_znetEncrypt( pStream, pStream->crypt_out + tosnd ); + pStream->crypt_out = pStream->wr.next_out; + pStream->wr.next_out += 2; + if( pStream->wr.avail_out < 2 ) + pStream->skip_out = 2 - pStream->wr.avail_out; + pStream->wr.avail_out -= 2 - pStream->skip_out; + } + tosnd = ( long ) ( pStream->crypt_out - pStream->outbuf ); + } + else + tosnd -= 2; + } if( tosnd > 0 ) { snd = hb_socketSend( sd, pStream->outbuf, tosnd, 0, timeout ); if( snd > 0 ) { - if( snd < tosnd ) - memmove( pStream->outbuf, pStream->outbuf + snd, tosnd - snd ); + tosnd += rest - snd; + if( tosnd > 0 ) + memmove( pStream->outbuf, pStream->outbuf + snd, tosnd ); pStream->wr.avail_out += ( uInt ) snd; - pStream->wr.next_out = pStream->outbuf + tosnd - snd; + pStream->wr.next_out -= snd; + pStream->crypt_out -= snd; + if( pStream->skip_out ) + { + if( pStream->skip_out <= pStream->wr.avail_out ) + { + pStream->wr.avail_out -= pStream->skip_out; + pStream->skip_out = 0; + } + else + { + pStream->skip_out -= pStream->wr.avail_out; + pStream->wr.avail_out = 0; + } + } } } return snd; @@ -183,12 +347,14 @@ static long hb_znetStreamWrite( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG ti */ long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG timeout ) { + uInt uiSize = HB_ZNET_BUFSIZE - ( pStream->crypt ? -2 : 0 ); + if( pStream->wr.avail_out > 0 ) pStream->err = deflate( &pStream->wr, Z_SYNC_FLUSH ); else pStream->err = Z_OK; - while( pStream->wr.avail_out < HB_ZNET_BUFSIZE ) + while( pStream->wr.avail_out < uiSize ) { if( hb_znetStreamWrite( pStream, sd, timeout ) <= 0 ) break; @@ -197,7 +363,7 @@ long hb_znetFlush( PHB_ZNETSTREAM pStream, HB_SOCKET sd, HB_LONG timeout ) pStream->err = deflate( &pStream->wr, Z_SYNC_FLUSH ); } - return HB_ZNET_BUFSIZE - pStream->wr.avail_out; + return uiSize - pStream->wr.avail_out; } /* write data using stream structure @@ -263,11 +429,14 @@ HB_FUNC( HB_INETCOMPRESS ) PHB_ZNETSTREAM pStream = hb_znetOpen( iLevel, iStrategy ); if( pStream == NULL ) pItem = NULL; /* to force RTE */ - if( ! hb_znetInetInitialize( pItem, pStream, hb_znetRead, hb_znetWrite, - hb_znetFlush, hb_znetClose ) ) + if( hb_znetInetInitialize( pItem, pStream, hb_znetRead, hb_znetWrite, + hb_znetFlush, hb_znetClose ) ) { - if( pStream ) - hb_znetClose( pStream ); + int keylen = ( int ) hb_parclen( 4 ); + if( keylen ) + hb_znetEncryptKey( pStream, hb_parc( 4 ), keylen ); } + else if( pStream ) + hb_znetClose( pStream ); } }