diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java index 35bd662..59bb55e 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java @@ -75,7 +75,8 @@ public abstract class AbstractTeamspeakClientSocket private Identity identity = null; private ClientConnectionState connectionState = null; - private PacketTransformation transformation = new InitPacketTransformation(); + private final PacketTransformation initTransformation = new InitPacketTransformation(); + private PacketTransformation transformation = initTransformation; private PacketHandler handler; private int clientId = 0; @@ -543,15 +544,11 @@ public abstract class AbstractTeamspeakClientSocket + " generation=" + networkPacket.getHeader().getGeneration()); PacketTransformation transformation = getTransformation(); + int dataLen = networkPacket.getDatagram().getLength() - networkPacket.getHeader().getSize(); try { packetBuffer = ByteBuffer.wrap( - transformation.decrypt( - networkPacket.getHeader(), - packetBuffer, - networkPacket.getDatagram().getLength() - - networkPacket.getHeader().getSize() - ) + decrypt(transformation, networkPacket.getHeader(), packetBuffer, dataLen) ).order(ByteOrder.BIG_ENDIAN); } catch (InvalidCipherTextException e) { throw new IOException( @@ -604,6 +601,20 @@ public abstract class AbstractTeamspeakClientSocket return packet; } + /** + * Decrypts with the session key, falling back to the handshake key: the server encrypts initivexpand2 with + * the latter, so its retransmits (sent when our ACK was lost) still arrive under it after the key switch. + */ + private byte[] decrypt(PacketTransformation transformation, PacketHeader header, ByteBuffer buffer, int dataLen) + throws InvalidCipherTextException { + try { + return transformation.decrypt(header, buffer, dataLen); + } catch (InvalidCipherTextException e) { + if (transformation instanceof InitPacketTransformation || header.getGeneration() != 0) throw e; + return initTransformation.decrypt(header, buffer, dataLen); + } + } + @Override public Packet readPacket() throws IOException,