Fix up Base64Packet.

Add non-cache support for EncryptedPacket.
This commit is contained in:
Captain ALM 2023-05-21 20:29:22 +01:00
parent f873983ffa
commit eb886b430d
Signed by: alfred
GPG Key ID: 4E4ADD02609997B1
2 changed files with 111 additions and 21 deletions

View File

@ -30,6 +30,7 @@ public class Base64Packet implements IStreamedPacket {
/**
* Constructs a new Base64Packet with the specified {@link IPacketFactory} and {@link PacketLoader}.
* The encrypted data will not be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
@ -54,6 +55,7 @@ public class Base64Packet implements IStreamedPacket {
/**
* Constructs a new Base64Packet with the specified {@link IPacketFactory}, {@link PacketLoader} and {@link IPacket}.
* The encrypted data will not be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
@ -149,23 +151,13 @@ public class Base64Packet implements IStreamedPacket {
public void loadPayload(byte[] packetData) throws PacketException {
if (packetData == null) throw new NullPointerException("packetData is null");
synchronized (slock) {
if (useCache) {
encryptedCache = packetData;
try {
byte[] payload = Base64.getDecoder().decode(encryptedCache);
held = loader.readPacketNoDigest(payload, factory, null);
} catch (IllegalArgumentException e) {
encryptedCache = null;
throw new PacketException(e);
}
} else {
try {
byte[] payload = Base64.getDecoder().decode(packetData);
held = loader.readPacketNoDigest(payload, factory, null);
} catch (IllegalArgumentException e) {
throw new PacketException(e);
}
try {
byte[] payload = Base64.getDecoder().decode(packetData);
held = loader.readPacketNoDigest(payload, factory, null);
} catch (IllegalArgumentException e) {
throw new PacketException(e);
}
if (useCache) encryptedCache = packetData;
}
}

View File

@ -24,6 +24,17 @@ import static com.captainalm.lib.calmnet.packet.PacketLoader.readByteFromInputSt
* @author Captain ALM
*/
public class EncryptedPacket implements IStreamedPacket {
/*
* Packet Format:
*
* Sections are seperated by spaces.
* {} is condition followed by () containing the sections caused by the condition.
* [] contains the length of the section.
*
* payload = trailerFlag[1] cypherSettingsLen[4] cypherSettings[cypherSettingsLen] {trailerFlag & 1}(trailerLength[4]) encrypted[*]
* encrypted = encrypt<toEncrypt>
* toEncrypt = data[*] {trailerFlag & 1}(trailer[trailerLength])
*/
private static final PacketProtocolInformation protocol = new PacketProtocolInformation((byte) 255, (byte) 252);
protected final Object slock = new Object();
@ -32,6 +43,7 @@ public class EncryptedPacket implements IStreamedPacket {
protected IPacket held;
protected byte[] encryptedCache;
protected int trailingArrayLengthCache;
protected boolean useCache;
protected Cipher cipher;
protected ICipherFactory cipherFactory;
@ -40,6 +52,7 @@ public class EncryptedPacket implements IStreamedPacket {
/**
* Constructs a new EncryptedPacket with the specified {@link IPacketFactory}, {@link PacketLoader} and {@link ICipherFactory}.
* The encrypted data will not be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
@ -47,11 +60,26 @@ public class EncryptedPacket implements IStreamedPacket {
* @throws NullPointerException factory, loader or cipherFactory is null.
*/
public EncryptedPacket(IPacketFactory factory, PacketLoader loader, ICipherFactory cipherFactory) {
this(factory, loader, cipherFactory, null);
this(factory, loader, cipherFactory, false);
}
/**
* Constructs a new EncryptedPacket with the specified {@link IPacketFactory}, {@link PacketLoader}, {@link ICipherFactory}
* and if the encrypted data should be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
* @param cipherFactory The cipher factory to use.
* @param useCache If the encrypted data should be cached.
* @throws NullPointerException factory, loader or cipherFactory is null.
*/
public EncryptedPacket(IPacketFactory factory, PacketLoader loader, ICipherFactory cipherFactory, boolean useCache) {
this(factory, loader, cipherFactory, null, useCache);
}
/**
* Constructs a new EncryptedPacket with the specified {@link IPacketFactory}, {@link PacketLoader}, {@link ICipherFactory} and {@link IPacket}.
* The encrypted data will not be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
@ -59,6 +87,20 @@ public class EncryptedPacket implements IStreamedPacket {
* @throws NullPointerException factory, loader or cipherFactory is null.
*/
public EncryptedPacket(IPacketFactory factory, PacketLoader loader, ICipherFactory cipherFactory, IPacket packet) {
this(factory, loader, cipherFactory, packet, false);
}
/**
* Constructs a new EncryptedPacket with the specified {@link IPacketFactory}, {@link PacketLoader}, {@link ICipherFactory},
* {@link IPacket} and if the encrypted data should be cached.
*
* @param factory The packet factory to use.
* @param loader The Packet Loader to use.
* @param cipherFactory The cipher factory to use.
* @param useCache If the encrypted data should be cached.
* @throws NullPointerException factory, loader or cipherFactory is null.
*/
public EncryptedPacket(IPacketFactory factory, PacketLoader loader, ICipherFactory cipherFactory, IPacket packet, boolean useCache) {
if (factory == null) throw new NullPointerException("factory is null");
if (loader == null) throw new NullPointerException("loader is null");
if (cipherFactory == null) throw new NullPointerException("cipherFactory is null");
@ -66,6 +108,7 @@ public class EncryptedPacket implements IStreamedPacket {
this.loader = loader;
this.cipher = null;
held = packet;
this.useCache = useCache;
}
protected void generateCipher(int opmode) throws PacketException {
@ -177,6 +220,8 @@ public class EncryptedPacket implements IStreamedPacket {
System.arraycopy(encryptedCache, 0, toret, index, encryptedCache.length);
if (!useCache) encryptedCache = null;
return toret;
}
}
@ -237,6 +282,8 @@ public class EncryptedPacket implements IStreamedPacket {
held = loader.readPacketNoDigest(thePacket, factory, null);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new PacketException(e);
} finally {
if (!useCache) encryptedCache = null;
}
}
}
@ -253,7 +300,16 @@ public class EncryptedPacket implements IStreamedPacket {
public void readData(OutputStream outputStream) throws IOException, PacketException {
if (outputStream == null) throw new NullPointerException("outputStream is null");
synchronized (slock) {
processEncryptedCache();
byte[] trailingArray;
if (useCache) {
processEncryptedCache();
trailingArray = null;
} else {
if (held == null) throw new PacketException("no data");
generateCipher(Cipher.ENCRYPT_MODE);
trailingArray = (trailingPassword == null || trailingPassword.length() < 1) ? new byte[0] : trailingPassword.getBytes(StandardCharsets.UTF_8);
trailingArrayLengthCache = trailingArray.length;
}
outputStream.write((trailingPassword != null && trailingPassword.length() > 0) ? 1 : 0);
@ -265,7 +321,19 @@ public class EncryptedPacket implements IStreamedPacket {
if (trailingArrayLengthCache > 0) PacketLoader.writeInteger(outputStream, trailingArrayLengthCache);
outputStream.write(encryptedCache);
if (useCache) {
outputStream.write(encryptedCache);
} else {
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher);
loader.writePacketNoDigest(cipherOutputStream, held, true);
if (trailingArrayLengthCache > 0)
cipherOutputStream.write(trailingArray);
try {
outputStream.write(cipher.doFinal());
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new PacketException(e);
}
}
}
}
@ -331,6 +399,7 @@ public class EncryptedPacket implements IStreamedPacket {
cipher.doFinal();
}
catch (BadPaddingException | IllegalBlockSizeException e) {
throw new PacketException(e);
}
}
}
@ -344,8 +413,15 @@ public class EncryptedPacket implements IStreamedPacket {
@Override
public int getSize() throws PacketException {
synchronized (slock) {
processEncryptedCache();
return encryptedCache.length + 5 + cipherFactory.getSettingsNoSecretsLength() + ((trailingArrayLengthCache == 0) ? 0 : 4);
if (useCache) {
processEncryptedCache();
return encryptedCache.length + 5 + cipherFactory.getSettingsNoSecretsLength() + ((trailingArrayLengthCache == 0) ? 0 : 4);
} else {
if (held == null) throw new PacketException("no data");
generateCipher(Cipher.ENCRYPT_MODE);
trailingArrayLengthCache = (trailingPassword == null || trailingPassword.length() < 1) ? 0 : trailingPassword.getBytes(StandardCharsets.UTF_8).length;
return 5 + cipherFactory.getSettingsNoSecretsLength() + ((trailingArrayLengthCache == 0) ? 0 : 4) + cipher.getOutputSize(loader.getPacketSize(held, true, true) + trailingArrayLengthCache);
}
}
}
@ -456,4 +532,26 @@ public class EncryptedPacket implements IStreamedPacket {
held = packet;
}
}
/**
* Gets if the encrypted data is cached.
*
* @return If the encrypted data is cached.
*/
public boolean isCacheUsed() {
return useCache;
}
/**
* Sets if the encrypted data is cached.
*
* @param used If the encrypted data should be cached.
*/
public void setCacheUsed(boolean used) {
synchronized (slock) {
useCache = used;
if (!useCache)
encryptedCache = null;
}
}
}