package edu.washington.cs.oneswarm.f2f.messaging;
import org.gudy.azureus2.core3.util.DirectByteBuffer;
import org.gudy.azureus2.core3.util.DirectByteBufferPool;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.messaging.MessageException;
import edu.washington.cs.oneswarm.f2f.datagram.DatagramEncrytionBase;
/**
* This class encapsulates the information required at the remote end to set up
* a udp connection with the current friend.
*
* Information required:
* Encryption Key: symmectric AES 128 bit key
*
* Initialization vector, 128 bit iv
*
* Hmac key, 20 bytes
*
* @author isdal
*
*/
public class OSF2FDatagramInit implements OSF2FMessage {
private final byte version;
private String description;
private DirectByteBuffer buffer;
private final static int MESSAGE_LENGTH = 4 + DatagramEncrytionBase.HMAC_KEY_LENGTH + 2
* DatagramEncrytionBase.BLOCK_SIZE + 4;
private final byte[] encryptionKey;
private final byte[] iv;
private final byte[] hmacKey;
private final int localPort;
private final int cryptoAlgo;
public OSF2FDatagramInit(byte version, int cryptoAlgo, byte[] encryptionKey, byte[] iv,
byte[] hmacKey, int localPort) {
this.version = version;
this.cryptoAlgo = cryptoAlgo;
this.encryptionKey = encryptionKey;
this.iv = iv;
this.hmacKey = hmacKey;
this.localPort = localPort;
}
public byte[] getEncryptionKey() {
return encryptionKey;
}
public byte[] getIv() {
return iv;
}
public byte[] getHmacKey() {
return hmacKey;
}
public int getLocalPort() {
return localPort;
}
@Override
public String getID() {
return OSF2FMessage.ID_OS_DATAGRAM_INIT;
}
@Override
public byte[] getIDBytes() {
return OSF2FMessage.ID_OS_DATAGRAM_INIT_BYTES;
}
@Override
public String getFeatureID() {
return OSF2FMessage.OS_FEATURE_ID;
}
@Override
public int getFeatureSubID() {
return OSF2FMessage.SUBID_OS_DATAGRAM_INIT;
}
@Override
public int getType() {
return Message.TYPE_PROTOCOL_PAYLOAD;
}
@Override
public byte getVersion() {
return version;
};
@Override
public String getDescription() {
if (description == null) {
description = OSF2FMessage.ID_OS_DATAGRAM_INIT + "\t port=" + localPort;
}
return description;
}
@Override
public DirectByteBuffer[] getData() {
if (buffer == null) {
buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG, MESSAGE_LENGTH);
buffer.putInt(SS_MSG, cryptoAlgo);
buffer.put(DirectByteBuffer.SS_MSG, encryptionKey);
buffer.put(DirectByteBuffer.SS_MSG, iv);
buffer.put(DirectByteBuffer.SS_MSG, hmacKey);
buffer.putInt(DirectByteBuffer.SS_MSG, localPort);
buffer.flip(DirectByteBuffer.SS_MSG);
}
return new DirectByteBuffer[] { buffer };
}
@Override
public Message deserialize(DirectByteBuffer data, byte version) throws MessageException {
if (data == null) {
throw new MessageException("[" + getID() + "] decode error: data == null");
}
if (data.remaining(DirectByteBuffer.SS_MSG) != MESSAGE_LENGTH) {
throw new MessageException("[" + getID() + "] decode error: payload.remaining["
+ data.remaining(DirectByteBuffer.SS_MSG) + "] != " + MESSAGE_LENGTH);
}
int cryptoAlgo = data.getInt(SS_MSG);
byte[] eKey = new byte[DatagramEncrytionBase.BLOCK_SIZE];
data.get(SS_MSG, eKey);
byte[] initVector = new byte[DatagramEncrytionBase.BLOCK_SIZE];
data.get(SS_MSG, initVector);
byte[] hKey = new byte[DatagramEncrytionBase.HMAC_KEY_LENGTH];
data.get(SS_MSG, hKey);
int localport = data.getInt(SS_MSG);
data.returnToPool();
return new OSF2FDatagramInit(version, cryptoAlgo, eKey, initVector, hKey, localport);
}
@Override
public void destroy() {
if (buffer != null)
buffer.returnToPool();
}
@Override
public int getMessageSize() {
return MESSAGE_LENGTH;
}
}