📄 protocoldecoderphe.java
字号:
DHPublicKey dh_public_key = (DHPublicKey)key_pair.getPublic();
BigInteger dh_y = dh_public_key.getY();
dh_public_key_bytes = bigIntegerToBytes( dh_y, DH_SIZE_BYTES );
}catch( Throwable e ){
throw( new IOException( Debug.getNestedExceptionMessage(e)));
}
}
protected void
completeDH(
byte[] buffer )
throws IOException
{
try{
BigInteger other_dh_y = bytesToBigInteger( buffer, 0, DH_SIZE_BYTES );
KeyFactory dh_key_factory = KeyFactory.getInstance("DH");
PublicKey other_public_key = dh_key_factory.generatePublic( new DHPublicKeySpec( other_dh_y, DH_P_BI, DH_G_BI ));
key_agreement.doPhase( other_public_key, true );
secret_bytes = key_agreement.generateSecret();
adapter.gotSecret( secret_bytes );
// System.out.println( "secret = " + ByteFormatter.encodeString( secret_bytes ));
}catch( Throwable e ){
throw( new IOException( Debug.getNestedExceptionMessage(e)));
}
}
protected void
setupCrypto()
throws IOException
{
try{
//"HASH('keyA', S, SKEY)" if you're A
//"HASH('keyB', S, SKEY)" if you're B
SHA1Hasher hasher = new SHA1Hasher();
hasher.update( KEYA_IV );
hasher.update( secret_bytes );
hasher.update( shared_secret );
byte[] a_key = hasher.getDigest();
hasher = new SHA1Hasher();
hasher.update( KEYB_IV );
hasher.update( secret_bytes );
hasher.update( shared_secret );
byte[] b_key = hasher.getDigest();
SecretKeySpec secret_key_spec_a = new SecretKeySpec( a_key, RC4_STREAM_ALG );
SecretKeySpec secret_key_spec_b = new SecretKeySpec( b_key, RC4_STREAM_ALG );
write_cipher = new TransportCipher( RC4_STREAM_CIPHER, Cipher.ENCRYPT_MODE, outbound?secret_key_spec_a:secret_key_spec_b );
read_cipher = new TransportCipher( RC4_STREAM_CIPHER, Cipher.DECRYPT_MODE, outbound?secret_key_spec_b:secret_key_spec_a );
}catch( Throwable e ){
e.printStackTrace();
throw( new IOException( Debug.getNestedExceptionMessage(e)));
}
}
/*
protected void
completeDH(
byte[] buffer )
throws IOException
{
try{
BigInteger other_dh_y = bytesToBigInteger( buffer, 0, DH_SIZE_BYTES );
KeyFactory dh_key_factory = KeyFactory.getInstance("DH");
PublicKey other_public_key = dh_key_factory.generatePublic( new DHPublicKeySpec( other_dh_y, DH_P_BI, DH_G_BI ));
key_agreement.doPhase( other_public_key, true );
byte[] secret_bytes_64 = key_agreement.generateSecret();
// we only want the first 32 bytes of the secret
secret_bytes = new byte[32];
System.arraycopy( secret_bytes_64, 0, secret_bytes, 0, 32 );
sha1_secret_bytes = new SHA1Simple().calculateHash( secret_bytes );
SecretKeySpec secret_key_spec_a = new SecretKeySpec( secret_bytes, 0, RC4_STREAM_KEY_SIZE_BYTES, RC4_STREAM_ALG );
SecretKeySpec secret_key_spec_b = new SecretKeySpec( secret_bytes, 16, RC4_STREAM_KEY_SIZE_BYTES, RC4_STREAM_ALG );
write_cipher = new TCPTransportCipher( RC4_STREAM_CIPHER, Cipher.ENCRYPT_MODE, outbound?secret_key_spec_a:secret_key_spec_b );
read_cipher = new TCPTransportCipher( RC4_STREAM_CIPHER, Cipher.DECRYPT_MODE, outbound?secret_key_spec_b:secret_key_spec_a );
}catch( Throwable e ){
throw( new IOException( Debug.getNestedExceptionMessage(e)));
}
}
*/
protected void
handshakeComplete()
throws IOException
{
if ( selected_protocol == CRYPTO_PLAIN ){
filter = new TransportHelperFilterTransparent( transport, true );
}else if ( selected_protocol == CRYPTO_XOR ){
filter = new TransportHelperFilterStreamXOR( transport, secret_bytes );
}else if ( selected_protocol == CRYPTO_RC4 ){
filter = new TransportHelperFilterStreamCipher(
transport,
read_cipher,
write_cipher );
/*
}else if ( selected_protocol == CRYPTO_AES ){
try{
SecretKeySpec secret_key_spec = new SecretKeySpec( secret_bytes, 32, AES_STREAM_KEY_SIZE_BYTES, AES_STREAM_ALG );
AlgorithmParameterSpec spec = new IvParameterSpec( secret_bytes, 48, AES_STREAM_KEY_SIZE_BYTES );
write_cipher = new TCPTransportCipher( AES_STREAM_CIPHER, Cipher.ENCRYPT_MODE, secret_key_spec, spec );
read_cipher = new TCPTransportCipher( AES_STREAM_CIPHER, Cipher.DECRYPT_MODE, secret_key_spec, spec );
filter = new TCPTransportHelperFilterStreamCipher(
helper,
read_cipher,
write_cipher );
}catch( Throwable e ){
throw( new IOException( "AES crypto init failed: " + Debug.getNestedExceptionMessage(e)));
}
*/
}else{
throw( new IOException( "Invalid selected protocol '" + selected_protocol + "'" ));
}
if ( selected_protocol != CRYPTO_RC4 ){
filter =
new TransportHelperFilterSwitcher(
new TransportHelperFilterStreamCipher( transport, read_cipher, write_cipher ),
filter,
initial_data_in_len,
0 ); // any initial data out is dealt with entirely during cryto phase
}
handshake_complete = true;
}
/*
X_1
A->B: Diffie Hellman Ya, PadA
X_2
B->A: Diffie Hellman Yb, PadB
X_3
A->B: HASH('req1', S), HASH('req2', SKEY)^HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
X_4
B->A: ENCRYPT(VC, crypto_select, len(padD), padD ) // , len(IB)), ENCRYPT(IB)
*/
protected void
process()
throws IOException
{
try{
process_mon.enter();
if ( handshake_complete ){
Debug.out( "Handshake process already completed" );
return;
}
boolean loop = true;
while( loop ){
// System.out.println( this + ":" + (outbound?"out: ":"in : ") + protocol_state + "/" + protocol_substate + ": r " + bytes_read + " - " + read_buffer + ", w " + bytes_written + " - " + write_buffer );
if ( protocol_state == PS_OUTBOUND_1 ){
if ( write_buffer == null ){
// A sends B Ya + Pa
byte[] padding_a = getRandomPadding(getPaddingMax()/2); // note that /2 also used in calculating max initial packet size above
write_buffer = ByteBuffer.allocate( dh_public_key_bytes.length + padding_a.length );
write_buffer.put( dh_public_key_bytes );
write_buffer.put( padding_a );
write_buffer.flip();
}
write( write_buffer );
if ( !write_buffer.hasRemaining()){
write_buffer = null;
protocol_state = PS_INBOUND_2;
}
}else if ( protocol_state == PS_INBOUND_1 ){
// B receives Ya
read( read_buffer );
if ( !read_buffer.hasRemaining()){
read_buffer.flip();
byte[] other_dh_public_key_bytes = new byte[read_buffer.remaining()];
read_buffer.get( other_dh_public_key_bytes );
completeDH( other_dh_public_key_bytes );
read_buffer = null;
protocol_state = PS_OUTBOUND_2;
}
}else if ( protocol_state == PS_OUTBOUND_2 ){
// B->A: Yb PadB
if ( write_buffer == null ){
byte[] padding_b = getRandomPadding( getPaddingMax()/2 );
write_buffer = ByteBuffer.allocate( dh_public_key_bytes.length + padding_b.length );
write_buffer.put( dh_public_key_bytes );
write_buffer.put( padding_b );
write_buffer.flip();
}
write( write_buffer );
if ( !write_buffer.hasRemaining()){
write_buffer = null;
protocol_state = PS_INBOUND_3;
}
}else if ( protocol_state == PS_INBOUND_2 ){
// A receives: Yb
if ( read_buffer == null ){
read_buffer = ByteBuffer.allocate( dh_public_key_bytes.length );
}
read( read_buffer );
if ( !read_buffer.hasRemaining()){
read_buffer.flip();
byte[] other_dh_public_key_bytes = new byte[read_buffer.remaining()];
read_buffer.get( other_dh_public_key_bytes );
completeDH( other_dh_public_key_bytes );
// A initiates SKEY so we can now set up crypto
setupCrypto();
read_buffer = null;
protocol_state = PS_OUTBOUND_3;
}
}else if ( protocol_state == PS_OUTBOUND_3 ){
// A->B: HASH('req1', S), HASH('req2', SKEY)^HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
if ( write_buffer == null ){
// padding_a here is half of the padding from before
int pad_max = getPaddingMax();
byte[] padding_a = getRandomPadding(pad_max/2);
byte[] padding_c = getZeroPadding(pad_max);
write_buffer = ByteBuffer.allocate( padding_a.length + 20 + 20 + ( VC.length + 4 + 2 + padding_c.length + 2 ) + initial_data_out_len );
write_buffer.put( padding_a );
// HASH('req1', S)
SHA1Hasher hasher = new SHA1Hasher();
hasher.update( REQ1_IV );
hasher.update( secret_bytes );
byte[] sha1 = hasher.getDigest();
write_buffer.put( sha1 );
// HASH('req2', SKEY)^HASH('req3', S)
hasher = new SHA1Hasher();
hasher.update( REQ2_IV );
hasher.update( shared_secret );
byte[] sha1_1 = hasher.getDigest();
hasher = new SHA1Hasher();
hasher.update( REQ3_IV );
hasher.update( secret_bytes );
byte[] sha1_2 = hasher.getDigest();
for (int i=0;i<sha1_1.length;i++){
sha1_1[i] ^= sha1_2[i];
}
write_buffer.put( sha1_1 );
// ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)
write_buffer.put( write_cipher.update( VC ));
write_buffer.put( write_cipher.update( new byte[]{ 0, 0, 0, my_supported_protocols }));
write_buffer.put( write_cipher.update( new byte[]{ (byte)(padding_c.length>>8),(byte)padding_c.length }));
write_buffer.put( write_cipher.update( padding_c ));
write_buffer.put( write_cipher.update( new byte[]{ (byte)(initial_data_out_len>>8),(byte)initial_data_out_len }));
if ( initial_data_out_len > 0 ){
int save_pos = initial_data_out.position();
write_cipher.update( initial_data_out, write_buffer );
// reset in case buffer needs to be used again by caller
initial_data_out.position( save_pos );
initial_data_out = null;
}
write_buffer.flip();
}
write( write_buffer );
if ( !write_buffer.hasRemaining()){
write_buffer = null;
protocol_state = PS_INBOUND_4;
}
}else if ( protocol_state == PS_INBOUND_3 ){
// B receives: HASH('req1', S), HASH('req2', SKEY)^HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
if ( read_buffer == null ){
read_buffer = ByteBuffer.allocate( 20 + PADDING_MAX );
read_buffer.limit( 20 );
SHA1Hasher hasher = new SHA1Hasher();
hasher.update( REQ1_IV );
hasher.update( secret_bytes );
padding_skip_marker = hasher.getDigest();
protocol_substate = 1;
}
while( true ){
read( read_buffer );
if ( read_buffer.hasRemaining()){
break;
}
if ( protocol_substate == 1 ){
//skip up to HASH('req1', S)
int limit = read_buffer.limit();
read_buffer.position( limit - 20 );
boolean match = true;
for (int i=0;i<20;i++){
if ( read_buffer.get() != padding_skip_marker[i] ){
match = false;
break;
}
}
if ( match ){
read_buffer = ByteBuffer.allocate( 20 + VC.length + 4 + 2 );
protocol_substate = 2;
break;
}else{
if ( limit == read_buffer.capacity()){
throw( new IOException( "PHE skip to SHA1 marker failed" ));
}
read_buffer.limit( limit + 1 );
read_buffer.position( limit );
}
}else if ( protocol_substate == 2 ){
// find SKEY using HASH('req2', SKEY)^HASH('req3', S) , ENCRYPT(VC, crypto_provide, len(PadC),
read_buffer.flip();
final byte[] decode = new byte[20];
read_buffer.get( decode );
SHA1Hasher hasher = new SHA1Hasher();
hasher.update( REQ3_IV );
hasher.update( secret_bytes );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -