use of com.biglybt.pif.messaging.MessageException in project BiglyBT by BiglySoftware.
the class SESTSConnectionImpl method send.
@Override
public void send(PooledByteBuffer message) throws MessageException {
if (failed) {
throw (new MessageException("Connection failed"));
}
try {
if (crypto_complete.isReleasedForever()) {
sendContent(message);
} else {
synchronized (this) {
if (pending_message == null) {
pending_message = message;
}
}
}
crypto_complete.reserve();
// if the pending message couldn't be piggy backed it'll still be allocated
boolean send_it = false;
synchronized (this) {
if (pending_message == message) {
pending_message = null;
send_it = true;
}
}
if (send_it) {
sendContent(message);
}
} catch (Throwable e) {
setFailed();
if (e instanceof MessageException) {
throw ((MessageException) e);
} else {
throw (new MessageException("Send failed", e));
}
}
}
use of com.biglybt.pif.messaging.MessageException in project BiglyBT by BiglySoftware.
the class SESTSConnectionImpl method setupBlockCrypto.
protected void setupBlockCrypto() throws MessageException {
if (!failed) {
if (block_crypto == SESecurityManager.BLOCK_ENCRYPTION_NONE) {
return;
}
try {
byte[] shared_secret = sts_engine.getSharedSecret();
SecretKeySpec secret_key_spec1 = new SecretKeySpec(shared_secret, 0, 16, "AES");
SecretKeySpec secret_key_spec2 = new SecretKeySpec(shared_secret, 8, 16, "AES");
AlgorithmParameterSpec param_spec1 = new IvParameterSpec(AES_IV1);
AlgorithmParameterSpec param_spec2 = new IvParameterSpec(AES_IV2);
Cipher cipher1 = Cipher.getInstance("AES/CBC/PKCS5Padding");
Cipher cipher2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
if (connection.isIncoming()) {
cipher1.init(Cipher.ENCRYPT_MODE, secret_key_spec1, param_spec1);
cipher2.init(Cipher.DECRYPT_MODE, secret_key_spec2, param_spec2);
incoming_cipher = cipher2;
outgoing_cipher = cipher1;
} else {
cipher1.init(Cipher.DECRYPT_MODE, secret_key_spec1, param_spec1);
cipher2.init(Cipher.ENCRYPT_MODE, secret_key_spec2, param_spec2);
incoming_cipher = cipher1;
outgoing_cipher = cipher2;
}
} catch (Throwable e) {
throw (new MessageException("Failed to setup block encryption", e));
}
}
}
use of com.biglybt.pif.messaging.MessageException in project BiglyBT by BiglySoftware.
the class SESTSConnectionImpl method receiveContent.
protected void receiveContent(PooledByteBuffer message) throws MessageException {
boolean buffer_handled = false;
try {
if (incoming_cipher != null) {
try {
byte[] enc = message.toByteArray();
byte[] plain = incoming_cipher.doFinal(enc);
PooledByteBuffer temp = new PooledByteBufferImpl(plain);
message.returnToPool();
buffer_handled = true;
message = temp;
} catch (Throwable e) {
throw (new MessageException("Failed to decrypt data", e));
}
} else if (block_crypto != SESecurityManager.BLOCK_ENCRYPTION_NONE) {
throw (new MessageException("Crypto isn't setup"));
}
List listeners_ref = listeners.getList();
MessageException last_error = null;
for (int i = 0; i < listeners_ref.size(); i++) {
PooledByteBuffer message_to_deliver;
if (i == 0) {
message_to_deliver = message;
} else {
// unlikely we'll ever have > 1 receiver....
message_to_deliver = new PooledByteBufferImpl(message.toByteArray());
}
try {
((GenericMessageConnectionListener) listeners_ref.get(i)).receive(this, message_to_deliver);
if (message_to_deliver == message) {
buffer_handled = true;
}
} catch (Throwable e) {
message_to_deliver.returnToPool();
if (message_to_deliver == message) {
buffer_handled = true;
}
if (e instanceof MessageException) {
last_error = (MessageException) e;
} else {
last_error = new MessageException("Failed to process message", e);
}
}
}
if (last_error != null) {
throw (last_error);
}
} finally {
if (!buffer_handled) {
message.returnToPool();
}
}
}
use of com.biglybt.pif.messaging.MessageException in project BiglyBT by BiglySoftware.
the class SESTSConnectionImpl method receive.
public void receive(PooledByteBuffer message) throws MessageException {
try {
boolean forward = false;
boolean crypto_completed = false;
ByteBuffer out_buffer = null;
synchronized (this) {
if (crypto_complete.isReleasedForever()) {
forward = true;
} else {
// basic sts flow:
// a -> puba -> b
// a <- pubb <- b
// a -> auta -> b
// a <- autb <- b
// a -> data -> b
// optimised
// a -> puba -> b
// a <- pubb + auta <- b
// a -> autb + data -> b
// therefore can be one or two messages in the payload
// 1 crypto
// 2 crypto (pub + auth)
// crypto + data
// initial a ->puba -> is done on first data send so data is ready for phase 3
ByteBuffer in_buffer = ByteBuffer.wrap(message.toByteArray());
message.returnToPool();
if (!sent_keys) {
// we've received
// a -> puba -> b
// reply with
// a <- puba + auta <- b
out_buffer = ByteBuffer.allocate(64 * 1024);
// write our keys
sts_engine.getKeys(out_buffer);
sent_keys = true;
// read their keys
sts_engine.putKeys(in_buffer);
// write our auth
sts_engine.getAuth(out_buffer);
sent_auth = true;
} else if (!sent_auth) {
out_buffer = ByteBuffer.allocate(64 * 1024);
// we've received
// a <- puba + auta <- b
// reply with
// a -> autb + data -> b
// read their keys
sts_engine.putKeys(in_buffer);
// write our auth
sts_engine.getAuth(out_buffer);
sent_auth = true;
// read their auth
sts_engine.putAuth(in_buffer);
// check we wanna talk to this person
byte[] rem_key = sts_engine.getRemotePublicKey();
if (!key_locator.accept(SESTSConnectionImpl.this, new SEPublicKeyImpl(my_public_key.getType(), rem_key))) {
throw (new MessageException("remote public key not accepted"));
}
setupBlockCrypto();
if (pending_message != null) {
byte[] pending_bytes = pending_message.toByteArray();
int pending_size = pending_bytes.length;
if (outgoing_cipher != null) {
pending_size = ((pending_size + AES_KEY_SIZE_BYTES - 1) / AES_KEY_SIZE_BYTES) * AES_KEY_SIZE_BYTES;
if (pending_size == 0) {
pending_size = AES_KEY_SIZE_BYTES;
}
}
if (out_buffer.remaining() >= pending_size) {
if (outgoing_cipher != null) {
out_buffer.put(outgoing_cipher.doFinal(pending_bytes));
} else {
out_buffer.put(pending_bytes);
}
// don't deallocate the pending message, the original caller does this
pending_message = null;
}
}
crypto_completed = true;
} else {
// we've received
// a -> autb + data -> b
// read their auth
sts_engine.putAuth(in_buffer);
// check we wanna talk to this person
byte[] rem_key = sts_engine.getRemotePublicKey();
if (!key_locator.accept(SESTSConnectionImpl.this, new SEPublicKeyImpl(my_public_key.getType(), rem_key))) {
// this is just here to prevent unwanted spew during closedown process
connection.closing();
throw (new MessageException("remote public key not accepted"));
}
setupBlockCrypto();
crypto_completed = true;
if (in_buffer.hasRemaining()) {
message = new PooledByteBufferImpl(new DirectByteBuffer(in_buffer.slice()));
forward = true;
}
}
}
}
if (out_buffer != null) {
out_buffer.flip();
connection.send(new PooledByteBufferImpl(new DirectByteBuffer(out_buffer)));
}
if (crypto_completed) {
cryptoComplete();
}
if (forward) {
receiveContent(message);
}
} catch (Throwable e) {
reportFailed(e);
if (e instanceof MessageException) {
throw ((MessageException) e);
} else {
throw (new MessageException("Receive failed", e));
}
}
}
use of com.biglybt.pif.messaging.MessageException in project BiglyBT by BiglySoftware.
the class GenericMessageConnectionImpl method receive.
protected void receive(GenericMessage message) {
boolean handled = false;
for (int i = 0; i < listeners.size(); i++) {
PooledByteBuffer buffer = new PooledByteBufferImpl(message.getPayload());
try {
((GenericMessageConnectionListener) listeners.get(i)).receive(this, buffer);
handled = true;
} catch (Throwable f) {
buffer.returnToPool();
if (!(f instanceof MessageException)) {
Debug.printStackTrace(f);
}
}
}
if (!handled && !(closed || closing)) {
Debug.out("GenericMessage: incoming message not handled");
}
}
Aggregations