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 );
byte[] sha1 = hasher.getDigest();
for (int i=0;i<decode.length;i++){
decode[i] ^= sha1[i];
}