Compare commits
2 Commits
dfa921fa41
...
b0bb4057f6
Author | SHA1 | Date | |
---|---|---|---|
b0bb4057f6 | |||
bde5860b47 |
23
src/com/captainalm/lib/calmnet/packet/IInternalCache.java
Normal file
23
src/com/captainalm/lib/calmnet/packet/IInternalCache.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.captainalm.lib.calmnet.packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows getting and setting if the
|
||||||
|
* internal cache should be used within a class instance.
|
||||||
|
*
|
||||||
|
* @author Captain ALM
|
||||||
|
*/
|
||||||
|
public interface IInternalCache {
|
||||||
|
/**
|
||||||
|
* Gets if the internal cache is used.
|
||||||
|
*
|
||||||
|
* @return If the internal cache is used.
|
||||||
|
*/
|
||||||
|
boolean isCacheUsed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the internal cache is used.
|
||||||
|
*
|
||||||
|
* @param used If the internal cache is used.
|
||||||
|
*/
|
||||||
|
void setCacheUsed(boolean used);
|
||||||
|
}
|
@ -23,7 +23,7 @@ import static com.captainalm.lib.calmnet.packet.PacketLoader.readByteFromInputSt
|
|||||||
*
|
*
|
||||||
* @author Captain ALM
|
* @author Captain ALM
|
||||||
*/
|
*/
|
||||||
public class EncryptedPacket implements IStreamedPacket {
|
public class EncryptedPacket implements IStreamedPacket, IInternalCache {
|
||||||
/*
|
/*
|
||||||
* Packet Format:
|
* Packet Format:
|
||||||
*
|
*
|
||||||
@ -356,10 +356,7 @@ public class EncryptedPacket implements IStreamedPacket {
|
|||||||
int flag = readByteFromInputStream(inputStream) & 0xff;
|
int flag = readByteFromInputStream(inputStream) & 0xff;
|
||||||
|
|
||||||
if (size < 5) throw new IOException("inputStream end of stream");
|
if (size < 5) throw new IOException("inputStream end of stream");
|
||||||
int cipherLenCache = (readByteFromInputStream(inputStream) & 0xff) * 16777216;
|
int cipherLenCache = PacketLoader.readInteger(inputStream);
|
||||||
cipherLenCache += (readByteFromInputStream(inputStream) & 0xff) * 65536;
|
|
||||||
cipherLenCache += (readByteFromInputStream(inputStream) & 0xff) * 256;
|
|
||||||
cipherLenCache += (readByteFromInputStream(inputStream) & 0xff);
|
|
||||||
if (cipherLenCache < 1) throw new PacketException("cipher length less than 1");
|
if (cipherLenCache < 1) throw new PacketException("cipher length less than 1");
|
||||||
|
|
||||||
if (size < 5 + cipherLenCache) throw new IOException("inputStream end of stream");
|
if (size < 5 + cipherLenCache) throw new IOException("inputStream end of stream");
|
||||||
@ -378,10 +375,7 @@ public class EncryptedPacket implements IStreamedPacket {
|
|||||||
trailingArrayLengthCache = 0;
|
trailingArrayLengthCache = 0;
|
||||||
if ((flag & 1) == 1) {
|
if ((flag & 1) == 1) {
|
||||||
if (size < 9 + cipherLenCache) throw new IOException("inputStream end of stream");
|
if (size < 9 + cipherLenCache) throw new IOException("inputStream end of stream");
|
||||||
trailingArrayLengthCache = (readByteFromInputStream(inputStream) & 0xff) * 16777216;
|
trailingArrayLengthCache = PacketLoader.readByteFromInputStream(inputStream);
|
||||||
trailingArrayLengthCache += (readByteFromInputStream(inputStream) & 0xff) * 65536;
|
|
||||||
trailingArrayLengthCache += (readByteFromInputStream(inputStream) & 0xff) * 256;
|
|
||||||
trailingArrayLengthCache += (readByteFromInputStream(inputStream) & 0xff);
|
|
||||||
if (trailingArrayLengthCache < 1) throw new PacketException("trailer length less than 1");
|
if (trailingArrayLengthCache < 1) throw new PacketException("trailer length less than 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,6 +532,7 @@ public class EncryptedPacket implements IStreamedPacket {
|
|||||||
*
|
*
|
||||||
* @return If the encrypted data is cached.
|
* @return If the encrypted data is cached.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isCacheUsed() {
|
public boolean isCacheUsed() {
|
||||||
return useCache;
|
return useCache;
|
||||||
}
|
}
|
||||||
@ -547,6 +542,7 @@ public class EncryptedPacket implements IStreamedPacket {
|
|||||||
*
|
*
|
||||||
* @param used If the encrypted data should be cached.
|
* @param used If the encrypted data should be cached.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void setCacheUsed(boolean used) {
|
public void setCacheUsed(boolean used) {
|
||||||
synchronized (slock) {
|
synchronized (slock) {
|
||||||
useCache = used;
|
useCache = used;
|
||||||
|
@ -0,0 +1,315 @@
|
|||||||
|
package com.captainalm.lib.calmnet.packet.core;
|
||||||
|
|
||||||
|
import com.captainalm.lib.calmnet.packet.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the ability for supporting streams to negotiate a cipher.
|
||||||
|
* <p>
|
||||||
|
* Major ID: 255
|
||||||
|
* Minor ID: 250
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Captain ALM
|
||||||
|
*/
|
||||||
|
public class NetworkEncryptionCipherPacket implements IStreamedPacket, IAcknowledgement, IInternalCache {
|
||||||
|
private static final PacketProtocolInformation protocol = new PacketProtocolInformation((byte) 255, (byte) 250);
|
||||||
|
|
||||||
|
protected Boolean acknowledgement;
|
||||||
|
protected String[] ciphers;
|
||||||
|
|
||||||
|
protected byte[] cipherData;
|
||||||
|
protected boolean useCache;
|
||||||
|
|
||||||
|
protected final Object slock = new Object();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new instance of NetworkEncryptionCipherPacket with the specified acknowledgement value and the specified ciphers.
|
||||||
|
*
|
||||||
|
* @param acknowledgement The acknowledgement value to use (Can be null).
|
||||||
|
* @param cipherNames The cipher names.
|
||||||
|
* @throws NullPointerException cipherNames is null.
|
||||||
|
*/
|
||||||
|
public NetworkEncryptionCipherPacket(Boolean acknowledgement, String[] cipherNames) {
|
||||||
|
if (cipherNames == null) throw new NullPointerException("cipherNames is null");
|
||||||
|
this.acknowledgement = acknowledgement;
|
||||||
|
this.ciphers = cipherNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the class instance is an Acknowledgement.
|
||||||
|
*
|
||||||
|
* @return If the class instance is an Acknowledgement.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isAcknowledgement() {
|
||||||
|
return (acknowledgement != null && acknowledgement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the packet is valid.
|
||||||
|
*
|
||||||
|
* @return Is the packet valid?
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return (acknowledgement != null && ciphers != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the protocol information.
|
||||||
|
*
|
||||||
|
* @return The protocol information.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PacketProtocolInformation getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the protocol information statically.
|
||||||
|
*
|
||||||
|
* @return The protocol information.
|
||||||
|
*/
|
||||||
|
public static PacketProtocolInformation getTheProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processCache() throws PacketException {
|
||||||
|
if (cipherData == null) {
|
||||||
|
if (acknowledgement == null || ciphers == null) throw new PacketException("no data");
|
||||||
|
|
||||||
|
ByteArrayOutputStream arrayData = new ByteArrayOutputStream();
|
||||||
|
arrayData.write((acknowledgement) ? (byte) 1 : (byte) 0);
|
||||||
|
try {
|
||||||
|
PacketLoader.writeInteger(arrayData, ciphers.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PacketException(e);
|
||||||
|
}
|
||||||
|
for (String c : ciphers) {
|
||||||
|
if (c == null) throw new PacketException("no data in entry");
|
||||||
|
try {
|
||||||
|
if (c.length() < 1) {
|
||||||
|
PacketLoader.writeInteger(arrayData, 0);
|
||||||
|
} else {
|
||||||
|
byte[] d = c.getBytes(StandardCharsets.UTF_8);
|
||||||
|
PacketLoader.writeInteger(arrayData, d.length);
|
||||||
|
arrayData.write(d);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PacketException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cipherData = arrayData.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the packet payload to a byte array.
|
||||||
|
*
|
||||||
|
* @return The packet payload data.
|
||||||
|
* @throws PacketException An Exception has occurred.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] savePayload() throws PacketException {
|
||||||
|
synchronized (slock) {
|
||||||
|
processCache();
|
||||||
|
if (useCache) return cipherData; else {
|
||||||
|
byte[] toret = cipherData;
|
||||||
|
cipherData = null;
|
||||||
|
return toret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the packet payload from save data.
|
||||||
|
*
|
||||||
|
* @param packetData The packet payload data.
|
||||||
|
* @throws NullPointerException The new store data is null.
|
||||||
|
* @throws PacketException An Exception has occurred.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void loadPayload(byte[] packetData) throws PacketException {
|
||||||
|
if (packetData == null) throw new NullPointerException("packetData is null");
|
||||||
|
if (packetData.length < 5) throw new PacketException("no data");
|
||||||
|
synchronized (slock) {
|
||||||
|
acknowledgement = (packetData[0] == 1);
|
||||||
|
if (!acknowledgement && packetData[0] != 0) acknowledgement = null;
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
int recordCount = (packetData[index++] & 0xff) * 16777216;
|
||||||
|
recordCount += (packetData[index++] & 0xff) * 65536;
|
||||||
|
recordCount += (packetData[index++] & 0xff) * 256;
|
||||||
|
recordCount += (packetData[index++] & 0xff);
|
||||||
|
if (recordCount < 0) throw new PacketException("record count less than 0");
|
||||||
|
|
||||||
|
if (useCache) cipherData = packetData;
|
||||||
|
ciphers = new String[recordCount];
|
||||||
|
for (int i = 0; i < recordCount; i++) {
|
||||||
|
int recordLength = (packetData[index++] & 0xff) * 16777216;
|
||||||
|
recordLength += (packetData[index++] & 0xff) * 65536;
|
||||||
|
recordLength += (packetData[index++] & 0xff) * 256;
|
||||||
|
recordLength += (packetData[index++] & 0xff);
|
||||||
|
if (recordLength < 0) throw new PacketException("record length less than 0");
|
||||||
|
byte[] currentRecord = new byte[recordLength];
|
||||||
|
if (recordLength > 0) {
|
||||||
|
System.arraycopy(packetData, index, currentRecord, 0, recordLength);
|
||||||
|
index += recordLength;
|
||||||
|
ciphers[i] = new String(currentRecord, StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
ciphers[i] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads payload data to an {@link OutputStream}.
|
||||||
|
*
|
||||||
|
* @param outputStream The output stream to read data to.
|
||||||
|
* @throws NullPointerException outputStream is null.
|
||||||
|
* @throws IOException An IO Exception has occurred.
|
||||||
|
* @throws PacketException An Exception has occurred.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void readData(OutputStream outputStream) throws IOException, PacketException {
|
||||||
|
if (outputStream == null) throw new NullPointerException("outputStream is null");
|
||||||
|
synchronized (slock) {
|
||||||
|
if (useCache) {
|
||||||
|
processCache();
|
||||||
|
outputStream.write(cipherData);
|
||||||
|
} else {
|
||||||
|
outputStream.write((acknowledgement) ? (byte) 1 : (byte) 0);
|
||||||
|
try {
|
||||||
|
PacketLoader.writeInteger(outputStream, ciphers.length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PacketException(e);
|
||||||
|
}
|
||||||
|
for (String c : ciphers) {
|
||||||
|
if (c == null) throw new PacketException("no data in entry");
|
||||||
|
try {
|
||||||
|
if (c.length() < 1) {
|
||||||
|
PacketLoader.writeInteger(outputStream, 0);
|
||||||
|
} else {
|
||||||
|
byte[] d = c.getBytes(StandardCharsets.UTF_8);
|
||||||
|
PacketLoader.writeInteger(outputStream, d.length);
|
||||||
|
outputStream.write(d);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PacketException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes payload data from an {@link InputStream}.
|
||||||
|
*
|
||||||
|
* @param inputStream The input stream to write data from.
|
||||||
|
* @param size The size of the input payload in bytes.
|
||||||
|
* @throws NullPointerException inputStream is null.
|
||||||
|
* @throws IllegalArgumentException size is less than 0.
|
||||||
|
* @throws IOException An IO Exception has occurred.
|
||||||
|
* @throws PacketException An Exception has occurred.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void writeData(InputStream inputStream, int size) throws IOException, PacketException {
|
||||||
|
if (inputStream == null) throw new NullPointerException("inputStream is null");
|
||||||
|
if (size < 0) throw new IllegalArgumentException("size is less than 0");
|
||||||
|
synchronized (slock) {
|
||||||
|
if (size < 1) throw new IOException("inputStream end of stream");
|
||||||
|
byte aknByte = PacketLoader.readByteFromInputStream(inputStream);
|
||||||
|
acknowledgement = (aknByte == 1);
|
||||||
|
if (!acknowledgement && aknByte != 0) acknowledgement = null;
|
||||||
|
if (size < 5) throw new IOException("inputStream end of stream");
|
||||||
|
|
||||||
|
int recordCount = PacketLoader.readInteger(inputStream);
|
||||||
|
if (recordCount < 0) throw new PacketException("record count less than 0");
|
||||||
|
|
||||||
|
cipherData = null;
|
||||||
|
ciphers = new String[recordCount];
|
||||||
|
for (int i = 0; i < recordCount; i++) {
|
||||||
|
int recordLength = PacketLoader.readInteger(inputStream);
|
||||||
|
if (recordLength < 0) throw new PacketException("record length less than 0");
|
||||||
|
if (recordLength > 0) {
|
||||||
|
byte[] currentRecord = PacketLoader.readArrayFromInputStream(inputStream, recordLength);
|
||||||
|
ciphers[i] = new String(currentRecord, StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
ciphers[i] = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size of the output data.
|
||||||
|
*
|
||||||
|
* @return The size of the output data in bytes.
|
||||||
|
* @throws PacketException An Exception has occurred.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getSize() throws PacketException {
|
||||||
|
synchronized (slock) {
|
||||||
|
processCache();
|
||||||
|
if (useCache) return cipherData.length; else {
|
||||||
|
int toret = cipherData.length;
|
||||||
|
cipherData = null;
|
||||||
|
return toret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cipher names this packet contains.
|
||||||
|
*
|
||||||
|
* @return An array of cipher names.
|
||||||
|
*/
|
||||||
|
public String[] getCiphers() {
|
||||||
|
return ciphers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cipher names this packet contains.
|
||||||
|
*
|
||||||
|
* @param cipherNames The array of cipher names.
|
||||||
|
* @throws NullPointerException cipherNames is null.
|
||||||
|
*/
|
||||||
|
public void setCiphers(String[] cipherNames) {
|
||||||
|
if (cipherNames == null) throw new NullPointerException("cipherNames is null");
|
||||||
|
synchronized (slock) {
|
||||||
|
ciphers = cipherNames;
|
||||||
|
cipherData = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the cipher information is cached.
|
||||||
|
*
|
||||||
|
* @return If the cipher information is cached.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isCacheUsed() {
|
||||||
|
return useCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the cipher information is cached.
|
||||||
|
*
|
||||||
|
* @param used If the cipher information is cached.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setCacheUsed(boolean used) {
|
||||||
|
synchronized (slock) {
|
||||||
|
useCache = used;
|
||||||
|
if (!useCache)
|
||||||
|
cipherData = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@ public class NetworkEncryptionUpgradePacket implements IPacket, IAcknowledgement
|
|||||||
protected boolean upgrade;
|
protected boolean upgrade;
|
||||||
protected boolean base64ed;
|
protected boolean base64ed;
|
||||||
protected ICipherFactory cipherFactory;
|
protected ICipherFactory cipherFactory;
|
||||||
|
protected boolean sendSecrets;
|
||||||
|
|
||||||
protected final Object slock = new Object();
|
protected final Object slock = new Object();
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ public class NetworkEncryptionUpgradePacket implements IPacket, IAcknowledgement
|
|||||||
synchronized (slock) {
|
synchronized (slock) {
|
||||||
if (acknowledgement == null) throw new PacketException("no data");
|
if (acknowledgement == null) throw new PacketException("no data");
|
||||||
|
|
||||||
byte[] cipherBytes = (cipherFactory == null) ? null : cipherFactory.getSettings();
|
byte[] cipherBytes = (cipherFactory == null) ? null : (sendSecrets) ? cipherFactory.getSettings() : cipherFactory.getSettingsNoSecrets();
|
||||||
byte[] toret = new byte[2 + ((cipherBytes == null) ? 0 : cipherBytes.length)];
|
byte[] toret = new byte[2 + ((cipherBytes == null) ? 0 : cipherBytes.length)];
|
||||||
toret[0] = (acknowledgement) ? (byte) 1 : (byte) 0;
|
toret[0] = (acknowledgement) ? (byte) 1 : (byte) 0;
|
||||||
toret[1] = (byte) (((upgrade) ? 1 : 0) + ((base64ed) ? 2 : 0));
|
toret[1] = (byte) (((upgrade) ? 1 : 0) + ((base64ed) ? 2 : 0));
|
||||||
@ -196,4 +197,24 @@ public class NetworkEncryptionUpgradePacket implements IPacket, IAcknowledgement
|
|||||||
public boolean isAcknowledgement() {
|
public boolean isAcknowledgement() {
|
||||||
return (acknowledgement != null && acknowledgement);
|
return (acknowledgement != null && acknowledgement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if secrets are sent as part of cipher settings.
|
||||||
|
*
|
||||||
|
* @return If the secrets are part of the cipher settings.
|
||||||
|
*/
|
||||||
|
public boolean areSecretsSent() {
|
||||||
|
return sendSecrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if secrets should be sent as part of cipher settings.
|
||||||
|
*
|
||||||
|
* @param sendSecrets If secrets are part of the cipher settings.
|
||||||
|
*/
|
||||||
|
public void setIfSecretsSent(boolean sendSecrets) {
|
||||||
|
synchronized (slock) {
|
||||||
|
this.sendSecrets = sendSecrets;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ public class CALMNETPacketFactory implements IPacketFactory {
|
|||||||
public IPacket getPacket(PacketProtocolInformation information) {
|
public IPacket getPacket(PacketProtocolInformation information) {
|
||||||
if (information == null) throw new NullPointerException("information is null");
|
if (information == null) throw new NullPointerException("information is null");
|
||||||
|
|
||||||
|
if (information.equals(NetworkEncryptionCipherPacket.getTheProtocol())) return new NetworkEncryptionCipherPacket(null, new String[0]);
|
||||||
if (information.equals(Base64Packet.getTheProtocol())) return new Base64Packet(factoryToUse, loaderToUse);
|
if (information.equals(Base64Packet.getTheProtocol())) return new Base64Packet(factoryToUse, loaderToUse);
|
||||||
if (information.equals(EncryptedPacket.getTheProtocol()) && cipherToUse != null) return new EncryptedPacket(factoryToUse, loaderToUse, cipherToUse);
|
if (information.equals(EncryptedPacket.getTheProtocol()) && cipherToUse != null) return new EncryptedPacket(factoryToUse, loaderToUse, cipherToUse);
|
||||||
if (information.equals(NetworkEncryptionUpgradePacket.getTheProtocol())) return new NetworkEncryptionUpgradePacket(null, false, false, cipherToUse);
|
if (information.equals(NetworkEncryptionUpgradePacket.getTheProtocol())) return new NetworkEncryptionUpgradePacket(null, false, false, cipherToUse);
|
||||||
|
Loading…
Reference in New Issue
Block a user