⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 protocoldecoderphe.java

📁 这是一个基于java编写的torrent的P2P源码
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/*
 * Created on 17-Jan-2006
 * Created by Paul Gardner
 * Copyright (C) 2006 Aelitis, All Rights Reserved.
 *
 * 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.
 * 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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * AELITIS, SAS au capital de 46,603.30 euros
 * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
 *
 */

package com.aelitis.azureus.core.networkmanager.impl;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.*;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.logging.LogAlert;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.ByteFormatter;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.HashWrapper;
import org.gudy.azureus2.core3.util.SHA1Hasher;
import org.gudy.azureus2.core3.util.SystemTime;

import com.aelitis.azureus.core.networkmanager.NetworkManager;
import com.aelitis.azureus.core.util.bloom.BloomFilter;
import com.aelitis.azureus.core.util.bloom.BloomFilterFactory;

public class 
ProtocolDecoderPHE 
	extends ProtocolDecoder
{
	private static final LogIDs LOGID = LogIDs.NWMAN;

	private static final byte		CRYPTO_PLAIN	= 0x01;
	private static final byte		CRYPTO_RC4		= 0x02;
	private static final byte		CRYPTO_XOR		= 0x04;
	private static final byte		CRYPTO_AES		= 0x08;

	
	//private static final String 	DH_P = "92d862b3a95bff4e6cbdce3a266ff4b46e6e1ecad76c0a877d92a3dae4999e6414efde56fc14d1cca6d5408a8ef9ea248389168876b6e8f4503845dfe373549f";
	//private static final String 	DH_G = "4383b53ee650fd73e41e8c9e8527997ab8cb41e1cbd73ac7685493e1e5d091e3e3789dea03ab9d5b2c368faa617bb30e427cbaeb23c268edb38eb8c747756080";
	// private static final String 	DH_P = "f3f90c790c63b119f9c1be43fdb12dc6ed6f26325999c01ba6ed373e75d6b2dee8d1c0475652a987c8df57b23d395bdb142be316d780b9361f85629535030873";
	
	private static final String 	DH_P = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563";
	private static final String 	DH_G = "02";
	private static final int		DH_L = 160;
	
	private static final int		DH_SIZE_BYTES	= DH_P.length()/2;

	public static final int MIN_INCOMING_INITIAL_PACKET_SIZE	= DH_SIZE_BYTES;
	

	private static final BigInteger	DH_P_BI = new BigInteger( DH_P, 16 );
	private static final BigInteger	DH_G_BI = new BigInteger( DH_G, 16 );
	
	private static KeyPairGenerator		dh_key_generator;
	private static long					last_dh_incoming_key_generate;
	
	private static final int			BLOOM_RECREATE				= 30*1000;
	private static final int			BLOOM_INCREASE				= 1000;
	private static BloomFilter			generate_bloom				= BloomFilterFactory.createAddRemove4Bit(BLOOM_INCREASE);
	private static long					generate_bloom_create_time	= SystemTime.getCurrentTime();
	
	private static boolean	crypto_ok;
	//private static boolean	aes_ok;
	
	/*
	private static final String		AES_STREAM_ALG				= "AES";
	private static final String		AES_STREAM_CIPHER			= "AES/CFB8/NoPadding";
	private static final int		AES_STREAM_KEY_SIZE			= 128;
	private static final int		AES_STREAM_KEY_SIZE_BYTES	= AES_STREAM_KEY_SIZE/8;
   	*/
	
	//private static final byte[]		AES_STREAM_IV				= 
    //	{ 	(byte)0x15, (byte)0xE0, (byte)0x6B, (byte)0x7E, (byte)0x98, (byte)0x59, (byte)0xE4, (byte)0xA7, 
    //		(byte)0x34, (byte)0x66, (byte)0xAD, (byte)0x48, (byte)0x35, (byte)0xE2, (byte)0xD0, (byte)0x24 };
    
    
	private static final String		RC4_STREAM_ALG				= "RC4";
	private static final String		RC4_STREAM_CIPHER			= "RC4";
	private static final int		RC4_STREAM_KEY_SIZE			= 128;
	private static final int		RC4_STREAM_KEY_SIZE_BYTES	= RC4_STREAM_KEY_SIZE/8;
    
    
    private static final int		PADDING_MAX	= 512;
    
    private static final int		PADDING_MAX_NORMAL	= PADDING_MAX;
    private static final int		PADDING_MAX_LIMITED	= 128;
       
    public static int 
    getMaxIncomingInitialPacketSize(
    	boolean	min_overheads )
    {
    	return( MIN_INCOMING_INITIAL_PACKET_SIZE + (min_overheads?PADDING_MAX_LIMITED:PADDING_MAX_NORMAL)/2 );
    }
    
	private static final Random	random = new SecureRandom();
	
	private static Map	global_shared_secrets	= new HashMap();
	
	static{
		try{
			DHParameterSpec dh_param_spec = new DHParameterSpec( DH_P_BI, DH_G_BI, DH_L );
			
			dh_key_generator = KeyPairGenerator.getInstance("DH");
	        
			dh_key_generator.initialize(dh_param_spec);
	        
			dh_key_generator.generateKeyPair();
	               	
		    byte[]	rc4_test_secret = new byte[RC4_STREAM_KEY_SIZE_BYTES];

		    SecretKeySpec	rc4_test_secret_key_spec = new SecretKeySpec(rc4_test_secret, 0, RC4_STREAM_KEY_SIZE_BYTES, RC4_STREAM_ALG );
		        		        
		    TransportCipher rc4_cipher = new TransportCipher( RC4_STREAM_CIPHER, Cipher.ENCRYPT_MODE, rc4_test_secret_key_spec );
		         
		    rc4_cipher = new TransportCipher( RC4_STREAM_CIPHER, Cipher.DECRYPT_MODE, rc4_test_secret_key_spec );
	        
		    /*
			try{
				byte[]	aes_test_secret = new byte[AES_STREAM_KEY_SIZE_BYTES];
	        	 
				SecretKeySpec	aes_test_secret_key_spec = new SecretKeySpec(aes_test_secret, 0, AES_STREAM_KEY_SIZE_BYTES, AES_STREAM_ALG );
		        	        
				AlgorithmParameterSpec	spec = 	new IvParameterSpec( aes_test_secret );
		        
		        TCPTransportCipher aes_cipher = new TCPTransportCipher( AES_STREAM_CIPHER, Cipher.ENCRYPT_MODE, aes_test_secret_key_spec, spec );
		        
		        aes_cipher = new TCPTransportCipher( AES_STREAM_CIPHER, Cipher.DECRYPT_MODE, aes_test_secret_key_spec, spec );
		        
		        aes_ok	= true;
		        
			}catch( Throwable e ){
				
				Logger.log(	new LogEvent(LOGID, "AES Unavailable", e ));
			}
	        */
		    
	        crypto_ok	= true;
	        
	     	if (Logger.isEnabled()){
	     		
        		Logger.log(	new LogEvent(LOGID, "PHE crypto initialised" ));
	     	}
		}catch( NoClassDefFoundError e ){
			
				// running without PHE classes, not such a severe error
      	
			Logger.log(	new LogEvent(LOGID, "PHE crypto disabled as classes unavailable" ));
			
			crypto_ok	= false;
			
		}catch( Throwable e ){
				     		
        	Logger.log(	new LogEvent(LOGID, "PHE crypto initialisation failed", e ));
			
			crypto_ok	= false;
		}
	}
	
	public static boolean
	isCryptoOK()
	{
		return( crypto_ok );
	}
	
	public static void
	addSecretsSupport(
		byte[][]		secrets )
	{
		for (int i=0;i<secrets.length;i++){
			
			SHA1Hasher hasher = new SHA1Hasher();
	   		
	   		hasher.update( REQ2_IV );
	   		hasher.update( secrets[i] );
	   		
	   		byte[]	encoded = hasher.getDigest();
			                  	
			synchronized( global_shared_secrets ){
				
				global_shared_secrets.put( new HashWrapper( encoded ), secrets[i] );
			}
		}
	}
	
	public static void
	removeSecretsSupport(
		byte[][]		secrets )
	{
		for (int i=0;i<secrets.length;i++){

			SHA1Hasher hasher = new SHA1Hasher();
	   		
	   		hasher.update( REQ2_IV );
	   		hasher.update( secrets[i] );
	   		
	   		byte[]	encoded = hasher.getDigest();
			                  	
			synchronized( global_shared_secrets ){
				
				global_shared_secrets.remove( new HashWrapper( encoded ));
			}
		}
	}
	
	// private static final byte SUPPORTED_PROTOCOLS = (byte)((aes_ok?CRYPTO_AES:0) | CRYPTO_RC4 | CRYPTO_XOR | CRYPTO_PLAIN );
	private static final byte SUPPORTED_PROTOCOLS = (byte)(CRYPTO_RC4 | CRYPTO_PLAIN );

	
	private static byte 	MIN_CRYPTO;
	
	static{
	    COConfigurationManager.addAndFireParameterListeners(
	    		new String[]{ "network.transport.encrypted.min_level" },
	    		new ParameterListener()
	    		{
	    			 public void 
	    			 parameterChanged(
	    				String ignore )
	    			 {
	    				 if ( NetworkManager.REQUIRE_CRYPTO_HANDSHAKE && !isCryptoOK() ){	    					 
	    					 Logger.log( new LogAlert(true,LogAlert.AT_ERROR,"Connection encryption unavailable, please update your Java version" ));
	    				 }
	    				 
	    				 String	min	= COConfigurationManager.getStringParameter( "network.transport.encrypted.min_level");
	    				 
	    				 if ( min.equals( "XOR" )){
	    					 
	    					 MIN_CRYPTO	= CRYPTO_XOR | CRYPTO_RC4 | CRYPTO_AES;
	    					 
	    				 }else if ( min.equals( "RC4" )){
	    					 
	    					 MIN_CRYPTO	= CRYPTO_RC4 | CRYPTO_AES;
	    					 
	    				 }else if ( min.equals( "AES" )){
	    					
	    					 MIN_CRYPTO	= CRYPTO_AES;
	    					 
	    				 }else{
	    					 
	    					 MIN_CRYPTO	= CRYPTO_PLAIN | CRYPTO_XOR | CRYPTO_RC4 | CRYPTO_AES;
	    				 } 
	    				 
	    				 MIN_CRYPTO = (byte)(MIN_CRYPTO & SUPPORTED_PROTOCOLS);
	    			 }
	    		});
	}
	
		
	private static final int		PS_OUTBOUND_1	= 0;
	private static final int		PS_OUTBOUND_2	= 1;
	private static final int		PS_OUTBOUND_3	= 2;
	private static final int		PS_OUTBOUND_4	= 3;
	
	private static final int		PS_INBOUND_1	= 10;
	private static final int		PS_INBOUND_2	= 11;
	private static final int		PS_INBOUND_3	= 12;
	private static final int		PS_INBOUND_4	= 13;

	public static final byte[]	KEYA_IV	= "keyA".getBytes();
	public static final byte[]	KEYB_IV	= "keyB".getBytes();
	public static final byte[]	REQ1_IV	= "req1".getBytes();
	public static final byte[]	REQ2_IV	= "req2".getBytes();
	public static final byte[]	REQ3_IV	= "req3".getBytes();
	public static final byte[]	VC		= { 0,0,0,0,0,0,0,0};
	
	
	
	private TransportHelper		transport;
	private ByteBuffer			write_buffer;
	private ByteBuffer			read_buffer;
	

	private ProtocolDecoderAdapter	adapter;
	
	private KeyAgreement 	key_agreement;
	private byte[]			dh_public_key_bytes;
	
	private byte[]			shared_secret;
	private byte[]			secret_bytes;
	
	private ByteBuffer		initial_data_out; 
	
	private int				initial_data_out_len;
	private int				initial_data_in_len;
	
	private TransportCipher		write_cipher;
	private TransportCipher		read_cipher;

	private byte[]			padding_skip_marker;
	
	private byte			my_supported_protocols;
	private byte			selected_protocol;
		
	private boolean	outbound;
	
	private int		protocol_state;
	private int		protocol_substate;
	
	private boolean	handshake_complete;

	private int		bytes_read;
	private int		bytes_written;
	
	private long	last_read_time	= SystemTime.getCurrentTime();
	
	private TransportHelperFilter		filter;
	
	private boolean processing_complete;
	
	private AEMonitor	process_mon	= new AEMonitor( "ProtocolDecoderPHE:process" );
	
	public 
	ProtocolDecoderPHE(
		TransportHelper				_transport,
		byte[][]					_shared_secrets,
		ByteBuffer					_header,
		ByteBuffer					_initial_data,
		ProtocolDecoderAdapter		_adapter )
	
		throws IOException
	{
		super( false );
		
		if ( !isCryptoOK()){
			
			throw( new IOException( "PHE crypto broken" ));
		}
		
		transport			= _transport;
		initial_data_out	= _initial_data;
		adapter				= _adapter;
		
		if ( _shared_secrets == null || _shared_secrets.length == 0 ){
			
			shared_secret	= new byte[0];
			
		}else{
			
			if ( _shared_secrets.length == 1 ){
			
				shared_secret	= _shared_secrets[0];

			}else{
			
				shared_secret	= _shared_secrets[random.nextInt( _shared_secrets.length )];
			}

			// System.out.println( "outbound - using crypto secret " + ByteFormatter.encodeString( shared_secret ));     
		}
		
		outbound	= _header == null;
		
		if ( outbound ){
			
			initial_data_out_len	= initial_data_out==null?0:initial_data_out.remaining();
		}
		
		my_supported_protocols = SUPPORTED_PROTOCOLS;
				
		if ( outbound ){
			
			//if ( !NetworkManager.REQUIRE_CRYPTO_HANDSHAKE ){				
			//	throw( new IOException( "Crypto encoder selected for outbound but crypto not required" ));
			//}
			
				// outbound connection, we require a certain minimal level of support
			
			my_supported_protocols = MIN_CRYPTO;
			
		}else{
			
				// incoming. If we require crypto then we use minimum otherwise available
			
			if ( NetworkManager.REQUIRE_CRYPTO_HANDSHAKE ){
				
				my_supported_protocols = MIN_CRYPTO;
			}
		}
		
		initCrypto();

		try{
			process_mon.enter();
		
			transport.registerForReadSelects(
				new TransportHelper.selectListener()
				{
				   	public boolean 
			    	selectSuccess(
			    		TransportHelper	helper, 
			    		Object 			attachment )
				   	{
				   		return( ProtocolDecoderPHE.this.selectSuccess( helper, attachment, false ));
				   	}
	
			        public void 
			        selectFailure(
			        	TransportHelper	helper,
			        	Object 			attachment, 
			        	Throwable 		msg)
			        {
			        	ProtocolDecoderPHE.this.selectFailure( helper, attachment, msg );
			        }
				},
				null );
			
			transport.registerForWriteSelects(
					new TransportHelper.selectListener()
					{
					   	public boolean 
				    	selectSuccess(
				    		TransportHelper	helper, 
				    		Object 			attachment )
					   	{
					   		return( ProtocolDecoderPHE.this.selectSuccess( helper, attachment, true ));
					   	}
	
				        public void 
				        selectFailure(
				        	TransportHelper	helper,
				        	Object 			attachment, 
				        	Throwable 		msg)
				        {
				        	ProtocolDecoderPHE.this.selectFailure( helper, attachment, msg );
				        }
					},
					null );
			
			transport.pauseWriteSelects();
			
			if ( outbound ){
			
				protocol_state	= PS_OUTBOUND_1;
	
				transport.pauseReadSelects();
				
			}else{
				
				protocol_state	= PS_INBOUND_1;
	
				read_buffer = ByteBuffer.allocate( dh_public_key_bytes.length );					
					
				read_buffer.put( _header );
			
				bytes_read += _header.limit();
			}
		}finally{
			
			process_mon.exit();
		}
		
		process();
	}
	
	protected void
	initCrypto()
	
		throws IOException
	{
		try{
	        KeyPair key_pair = generateDHKeyPair( transport, outbound );
	    	    
	        key_agreement = KeyAgreement.getInstance("DH");
	        
	        key_agreement.init(key_pair.getPrivate());
	       

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -