allow keeping the same trypt instance for a while, massively improving security of chatcrypt

This commit is contained in:
Daniella / Tove 2024-05-25 01:04:48 +02:00
parent d3a7346ece
commit c8ea8ae662
3 changed files with 68 additions and 14 deletions

View file

@ -2,8 +2,10 @@ package com.baseband.client.module.chat;
import com.baseband.client.configuration.annotation.Config;
import com.baseband.client.configuration.annotation.Gate;
import com.baseband.client.configuration.annotation.MultiGate;
import com.baseband.client.configuration.annotation.Range;
import com.baseband.client.event.events.PacketEvent;
import com.baseband.client.gui.lib.component.Button;
import com.baseband.client.mixins.ICPacketChat;
import com.baseband.client.module.Feature;
import com.baseband.client.module.category.Chat;
@ -49,10 +51,12 @@ public class ChatCrypt extends Feature {
@Config("Use SBE algorithm (preferred)")
@Marker(1)
public boolean useSBE = true;
@Marker(2)
public boolean useTrypt = false;
@Config("(But Trypt looks more random)")
@Marker(2)
@Gate(2)
@Marker(-1)
@Gate(-1)
public boolean _trypt_info = true;
@Config("Seed")
@ -64,13 +68,29 @@ public class ChatCrypt extends Feature {
@Gate(1)
public int boxSize = 256;
@Config("Keep Trypt instance")
@Gate(2)
@Marker(3)
public boolean keepTrypt = false;
@Config("Warning! More secure, worse QOL")
@MultiGate(and = {3, -2})
@Marker(-2)
public boolean _keep_info = true;
@Config("Reset Trypt")
@Gate(3)
public Button.ClickEvent resetTrypt = btn -> {
trypt = null;
};
private Trypt trypt;
private final Pattern CHAT_PATTERN = Pattern.compile("(<.*?> )|(.*?: )");
@Config("Password")
public String password = "CLICK HERE";
public void onEnable() {
if(password.isEmpty() || password.equalsIgnoreCase("CLICK HERE")) {
toggle();
@ -78,6 +98,12 @@ public class ChatCrypt extends Feature {
}
}
@Override
public void onEveryTick() {
useTrypt = !useSBE;
}
String sentSomething = null;
public void onPacketRead(PacketEvent.Read e) {
if (e.getPacket() instanceof SPacketChat) {
@ -97,8 +123,23 @@ public class ChatCrypt extends Feature {
message = message.substring(0, message.length() - getTerminator().length());
}
boolean isOurs = message.equals(sentSomething);
sentSomething = null;
GlobalUtil.LOGGER.info("decrypt: {}", message);
message = decrypt(message);
byte[] original = recoverBytes(message);
message = decrypt(original);
if(!useSBE && keepTrypt && !isOurs) {
// we must re-encrypt anything we get, unless it is from ourselves, to make sure our key stays up-to-date
if(Arrays.equals(trypt.encryptChunk(message.getBytes(StandardCharsets.UTF_8), original[0]), original)) {
GlobalUtil.LOGGER.debug("Successfully kept Trypt key up-to-date.");
}
else {
HUD.notifyAndPrint("§c§lChat>§c Unable to keep Trypt key up-to-date. You must reset it.");
}
}
try {
FieldFinder.findUnmarked(SPacketChat.class, ITextComponent.class, 0).set(e.getPacket(), new TextComponentString("§dChatCrypt> §r" + username + ": " + message));
} catch (IllegalAccessException ex) {
@ -127,10 +168,13 @@ public class ChatCrypt extends Feature {
if(s.startsWith("/"))
return;
s = encrypt(s) + getTerminator();
s = encrypt(s);
sentSomething = s;
s += getTerminator();
if (s.length() > 256) {
ChatUtil.print("Encrypted message length was too long, couldn't send!");
e.setCancelled(true);
sentSomething = null;
}
((ICPacketChat)e.getPacket()).setMessage(s);
}
@ -142,20 +186,22 @@ public class ChatCrypt extends Feature {
return armorBytes(sbe.transform(value.getBytes(StandardCharsets.UTF_8)));
}
else {
Trypt trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8));
if(!keepTrypt || trypt == null)
trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8));
return armorBytes(trypt.encryptChunk(value.getBytes(StandardCharsets.UTF_8)));
}
}
public String decrypt(String encrypted) {
public String decrypt(byte[] encrypted) {
if(useSBE) {
SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, seed);
return new String(sbe.transform(recoverBytes(encrypted)), StandardCharsets.US_ASCII);
return new String(sbe.transform(encrypted), StandardCharsets.US_ASCII);
}
else {
Trypt trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8));
return new String(trypt.decryptChunk(recoverBytes(encrypted)), StandardCharsets.UTF_8);
if(!keepTrypt || trypt == null)
trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8));
return new String(trypt.decryptChunk(encrypted), StandardCharsets.UTF_8);
}
}

View file

@ -7,6 +7,7 @@ import com.baseband.client.module.Category;
import com.baseband.client.module.Feature;
import com.baseband.client.module.category.Render;
import com.baseband.client.module.client.Client;
import com.baseband.client.util.ingame.ChatUtil;
import com.baseband.client.util.misc.Marker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@ -50,6 +51,11 @@ public class HUD extends Feature {
}
}
public static void notifyAndPrint(String text) {
notifs.add(new Notification(text));
ChatUtil.print(text);
}
public static void notify(String text) {
notifs.add(new Notification(text));
}

View file

@ -18,15 +18,18 @@ public class Trypt {
cRandD = new Random(seed);
this.key = key;
}
public byte[] encryptChunk(byte[] input) {
return encryptChunk(input, (byte) sRand.nextInt());
}
public byte[] encryptChunk(byte[] input, byte salt) {
ArrayList<Byte> data = new ArrayList<>(input.length);
for (byte b : input) {
data.add(b);
}
ArrayList<Integer> forbidden = new ArrayList<>(input.length);
byte[] output = new byte[input.length + 1];
byte salt = (byte) sRand.nextInt();
output[0] = salt;
for(int i = 0; i < input.length;) {
@ -36,7 +39,6 @@ public class Trypt {
forbidden.add(newLocation);
byte old = data.remove(0);
output[newLocation + 1] = (byte) (old ^ salt ^ key[(i++ ^ cRandE.nextInt(0x7fffffff)) % key.length]);
//input[(newLocation + 1) % input.length] -= (byte) (old ^ cRandE.nextInt(0x7fffffff));
salt = (byte) (salt ^ (newLocation << cRandE.nextInt(8)));
}