From c98ab6de76928845b9a5076d72a21679b9801d86 Mon Sep 17 00:00:00 2001 From: TudbuT Date: Sun, 2 Jun 2024 04:14:15 +0200 Subject: [PATCH] make Trypt cryptographically secure (i believe) --- .../client/feature/chat/ChatCrypt.java | 27 ++++---- .../client/util/misc/SecurePRandom.java | 66 +++++++++++++++++++ .../com/baseband/client/util/misc/Trypt.java | 21 +++--- 3 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 Client/src/main/java/com/baseband/client/util/misc/SecurePRandom.java diff --git a/Client/src/main/java/com/baseband/client/feature/chat/ChatCrypt.java b/Client/src/main/java/com/baseband/client/feature/chat/ChatCrypt.java index 11facfc..f70e9da 100644 --- a/Client/src/main/java/com/baseband/client/feature/chat/ChatCrypt.java +++ b/Client/src/main/java/com/baseband/client/feature/chat/ChatCrypt.java @@ -61,11 +61,10 @@ public class ChatCrypt extends Feature { public boolean useTrypt = false; @Config("Seed") - @Description("(Must be a number or will be hashed into one.)\n" + - "PRNG seed to make results less predictable.\n" + + @Description("PRNG seed to make results less predictable.\n" + "On SBE: Necessary for decreasing the likelihood of undigested bytes.\n" + "On Trypt: Necessary for scrambling byte order and decreasing the likelihood of undigested bytes.") - public String sSeed = "94278"; + public String sSeed = "this is a bad seed"; @Config("Box Size") @Description("The size of the SBE random data box.") @@ -116,15 +115,15 @@ public class ChatCrypt extends Feature { } } - int seed = -1; + int iSeed = -1; @Override public void onEveryTick() { useTrypt = !useSBE; try { - seed = Integer.parseInt(sSeed); + iSeed = Integer.parseInt(sSeed); } catch (NumberFormatException e) { - seed = sSeed.hashCode(); + iSeed = sSeed.hashCode(); } } @@ -223,12 +222,12 @@ public class ChatCrypt extends Feature { public String encrypt(String value) { if(useSBE) { - SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, seed); + SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, iSeed); return armorBytes(sbe.transform(value.getBytes(StandardCharsets.UTF_8))); } else { if(!keepTrypt || trypt == null) - trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), scramble); + trypt = new Trypt(sSeed.getBytes(StandardCharsets.UTF_8), Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), scramble); return armorBytes(trypt.encryptChunk(value.getBytes(StandardCharsets.UTF_8))); } } @@ -236,32 +235,32 @@ public class ChatCrypt extends Feature { public String decrypt(byte[] encrypted) { if(useSBE) { - SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, seed); + SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, iSeed); return new String(sbe.transform(encrypted), StandardCharsets.US_ASCII); } else { if(!keepTrypt || trypt == null) - trypt = new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), scramble); + trypt = new Trypt(sSeed.getBytes(StandardCharsets.UTF_8), Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), scramble); return new String(trypt.decryptChunk(encrypted), StandardCharsets.UTF_8); } } public String encryptNoKeep(String value) { if (useSBE) { - SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, seed); + SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, iSeed); return armorBytes(sbe.transform(value.getBytes(StandardCharsets.UTF_8))); } else { - return armorBytes(new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), 0).encryptChunk(value.getBytes(StandardCharsets.UTF_8))); + return armorBytes(new Trypt(sSeed.getBytes(StandardCharsets.UTF_8), Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), 0).encryptChunk(value.getBytes(StandardCharsets.UTF_8))); } } public String decryptNoKeep(byte[] encrypted) { if(useSBE) { - SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, seed); + SBE sbe = new SBE(Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), boxSize, iSeed); return new String(sbe.transform(encrypted), StandardCharsets.US_ASCII); } else { - return new String(new Trypt(seed, Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), 0).decryptChunk(encrypted), StandardCharsets.UTF_8); + return new String(new Trypt(sSeed.getBytes(StandardCharsets.UTF_8), Hasher.sha512hex(password).getBytes(StandardCharsets.UTF_8), 0).decryptChunk(encrypted), StandardCharsets.UTF_8); } } diff --git a/Client/src/main/java/com/baseband/client/util/misc/SecurePRandom.java b/Client/src/main/java/com/baseband/client/util/misc/SecurePRandom.java new file mode 100644 index 0000000..200527a --- /dev/null +++ b/Client/src/main/java/com/baseband/client/util/misc/SecurePRandom.java @@ -0,0 +1,66 @@ +package com.baseband.client.util.misc; + +import de.tudbut.obj.NotSupportedException; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Random; + +public class SecurePRandom extends Random { + + private final MessageDigest sha256; + private final byte[] seed; + private long index = 0; + + public SecurePRandom(byte[] seed) { + super(0); + this.seed = seed; + try { + sha256 = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new NotSupportedException("SecurePRandom is not supported on this JVM"); + } + } + + @Override + public synchronized void setSeed(long seed) { + throw new NotSupportedException(); + } + + public synchronized byte[] nextBytes() { + sha256.reset(); + sha256.update(seed); + byte[] bytes = new byte[8]; + bytes[0] = (byte) (index >> 56 & 0xff); + bytes[1] = (byte) (index >> 48 & 0xff); + bytes[2] = (byte) (index >> 40 & 0xff); + bytes[3] = (byte) (index >> 32 & 0xff); + bytes[4] = (byte) (index >> 24 & 0xff); + bytes[5] = (byte) (index >> 16 & 0xff); + bytes[6] = (byte) (index >> 8 & 0xff); + bytes[7] = (byte) (index >> 0 & 0xff); + index++; + return sha256.digest(bytes); + } + + @Override + public synchronized void nextBytes(byte[] bytes) { + for(int i = 0; i < bytes.length; i += 32) { + System.arraycopy(nextBytes(), 0, bytes, i, Math.min(32, bytes.length)); + } + } + + @Override + final protected int next(int numBits) { + int numBytes = (numBits+7)/8; + byte[] b = new byte[numBytes]; + int next = 0; + + nextBytes(b); + for (int i = 0; i < numBytes; i++) { + next = (next << 8) + (b[i] & 0xFF); + } + + return next >>> (numBytes*8 - numBits); + } +} diff --git a/Client/src/main/java/com/baseband/client/util/misc/Trypt.java b/Client/src/main/java/com/baseband/client/util/misc/Trypt.java index 56ad598..eaa4d29 100644 --- a/Client/src/main/java/com/baseband/client/util/misc/Trypt.java +++ b/Client/src/main/java/com/baseband/client/util/misc/Trypt.java @@ -2,20 +2,17 @@ package com.baseband.client.util.misc; import java.security.SecureRandom; import java.util.ArrayList; -import java.util.Random; public class Trypt { private final SecureRandom sRand = new SecureRandom(); - private final Random cRandE; - private final Random cRandD; - private final long seed; + private final SecurePRandom cRandE; + private final SecurePRandom cRandD; private final byte[] key; private final int scramble; - public Trypt(long seed, byte[] key, int scramble) { - cRandE = new Random(seed); - cRandD = new Random(seed); - this.seed = seed; + public Trypt(byte[] seed, byte[] key, int scramble) { + cRandE = new SecurePRandom(seed); + cRandD = new SecurePRandom(seed); this.key = key; this.scramble = scramble; } @@ -29,18 +26,17 @@ public class Trypt { for (byte b : input) { data.add(b); } - ArrayList forbidden = new ArrayList<>(input.length); + ArrayList finished = new ArrayList<>(input.length); byte[] output = new byte[input.length + 1]; output[0] = salt; for(int i = 0; i < input.length;) { int newLocation = cRandE.nextInt(input.length); - if(forbidden.contains(newLocation)) + if(finished.contains(newLocation)) continue; - forbidden.add(newLocation); + finished.add(newLocation); byte old = data.remove(0); output[newLocation + 1] = (byte) (old ^ salt ^ key[(i++ ^ cRandE.nextInt(0x7fffffff)) % key.length]); - salt = (byte) (salt ^ (newLocation << cRandE.nextInt(8))); } for (byte b = 0; b < input[cRandE.nextInt(input.length)]; b++) { @@ -62,7 +58,6 @@ public class Trypt { forbidden.add(newLocation); byte encrypted = input[newLocation + 1]; output[i] = (byte) (encrypted ^ salt ^ key[(i++ ^ cRandD.nextInt(0x7fffffff)) % key.length]); - salt = (byte) (salt ^ (newLocation << cRandD.nextInt(8))); } for (byte b = 0; b < output[cRandD.nextInt(output.length)]; b++) {