diff --git a/libtransmission/crypto.c b/libtransmission/crypto.c index 3bb2ba6e5..e12e843d2 100644 --- a/libtransmission/crypto.c +++ b/libtransmission/crypto.c @@ -355,21 +355,59 @@ tr_cryptoRandBuf( unsigned char *buf, ***/ char* -tr_crypt( const void * plaintext ) +tr_ssha1( const void * plaintext ) { static const char * salter = "0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "./"; static const size_t salter_len = 64; + static const size_t saltval_len = 8; int i; - char salt[12]; + char salt[saltval_len]; + char sha[SHA_DIGEST_LENGTH]; + char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2]; - memcpy( salt, "$1$", 3 ); - for( i=0; i<8; ++i ) - salt[3+i] = salter[ tr_cryptoRandInt( salter_len ) ]; - salt[11] = '\0'; + for( i=0; i<=saltval_len; ++i ) + salt[i] = salter[ tr_cryptoRandInt( salter_len ) ]; - return tr_strdup( DES_crypt( plaintext, salt ) ); + tr_sha1( sha, plaintext, strlen( plaintext ), salt, saltval_len, NULL ); + tr_sha1_to_hex( &buf[1], &sha ); + memcpy( &buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len ); + buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0'; + buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring + easier */ + + return tr_strdup( &buf ); +} + +tr_bool +tr_ssha1_matches( const char * source, const char * pass ) +{ + char * salt; + size_t saltlen; + char * hashed; + char buf[SHA_DIGEST_LENGTH]; + tr_bool result; + + /* extract the salt */ + saltlen = strlen( source ) - 2*SHA_DIGEST_LENGTH-1; + salt = tr_malloc( saltlen ); + memcpy( salt, source + 2*SHA_DIGEST_LENGTH+1, saltlen ); + + /* hash pass + salt */ + hashed = tr_malloc( 2*SHA_DIGEST_LENGTH + saltlen + 2 ); + tr_sha1( &buf, pass, strlen( pass ), salt, saltlen, NULL ); + tr_sha1_to_hex( &hashed[1], &buf ); + memcpy( hashed + 1+2*SHA_DIGEST_LENGTH, salt, saltlen ); + hashed[1+2*SHA_DIGEST_LENGTH + saltlen] = '\0'; + hashed[0] = '{'; + + result = strcmp( source, hashed ) == 0 ? TRUE : FALSE; + + tr_free( hashed ); + tr_free( salt ); + + return result; } diff --git a/libtransmission/crypto.h b/libtransmission/crypto.h index ef41c4103..48a39e7ab 100644 --- a/libtransmission/crypto.h +++ b/libtransmission/crypto.h @@ -95,7 +95,8 @@ int tr_cryptoWeakRandInt( int n ); void tr_cryptoRandBuf( unsigned char *buf, size_t len ); -char* tr_crypt( const void * plaintext ); +char* tr_ssha1( const void * plaintext ); +tr_bool tr_ssha1_matches( const char * source, const char * pass ); #endif diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index ef0ecc464..33edac717 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -465,7 +465,6 @@ handle_request( struct evhttp_request * req, { user = p; *pass++ = '\0'; - pass = tr_crypt( pass ); } } @@ -479,7 +478,8 @@ handle_request( struct evhttp_request * req, } else if( server->isPasswordEnabled && ( !pass || !user || strcmp( server->username, user ) - || strcmp( server->password, pass ) ) ) + || !tr_ssha1_matches( server->password, + pass ) ) ) { evhttp_add_header( req->output_headers, "WWW-Authenticate", @@ -511,7 +511,6 @@ handle_request( struct evhttp_request * req, send_simple_response( req, HTTP_NOTFOUND, req->uri ); } - tr_free( pass ); tr_free( user ); } } @@ -671,7 +670,10 @@ tr_rpcSetPassword( tr_rpc_server * server, const char * password ) { tr_free( server->password ); - server->password = tr_crypt( password ); + if( *password != '{' ) + server->password = tr_ssha1( password ); + else + server->password = strdup( password ); dbgmsg( "setting our Password to [%s]", server->password ); } @@ -762,7 +764,10 @@ tr_rpcInit( tr_session * session, found = tr_bencDictFindStr( settings, TR_PREFS_KEY_RPC_PASSWORD, &str ); assert( found ); - s->password = tr_strdup( str ); + if( *str != '{' ) + s->password = tr_ssha1( str ); + else + s->password = strdup( str ); #ifdef HAVE_ZLIB s->stream.zalloc = (alloc_func) Z_NULL;