From 084e7b22fa40ff17f9cc3ef805e386f553e4cf2b Mon Sep 17 00:00:00 2001 From: P0nk Date: Mon, 14 Feb 2022 19:05:50 +0100 Subject: [PATCH] Consolidate HexTool methods and add more tests --- src/main/java/client/Client.java | 2 +- src/main/java/net/encryption/MapleAESOFB.java | 2 +- .../net/packet/logging/InPacketLogger.java | 4 +- .../packet/logging/MonitoredChrLogger.java | 2 +- .../net/packet/logging/OutPacketLogger.java | 4 +- .../handlers/login/LoginPasswordHandler.java | 4 +- src/main/java/tools/HexTool.java | 52 +++++++++++-------- src/test/java/tools/HexToolTest.java | 32 ++++++++---- 8 files changed, 61 insertions(+), 41 deletions(-) diff --git a/src/main/java/client/Client.java b/src/main/java/client/Client.java index 12ca7278f9..5ed36fbcb7 100644 --- a/src/main/java/client/Client.java +++ b/src/main/java/client/Client.java @@ -1335,7 +1335,7 @@ public class Client extends ChannelInboundHandlerAdapter { try { MessageDigest digester = MessageDigest.getInstance(type); digester.update(password.getBytes(StandardCharsets.UTF_8), 0, password.length()); - return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase().equals(hash); + return HexTool.toHexString(digester.digest()).replace(" ", "").toLowerCase().equals(hash); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Encoding the string failed", e); } diff --git a/src/main/java/net/encryption/MapleAESOFB.java b/src/main/java/net/encryption/MapleAESOFB.java index f55b2a277f..4de36a078b 100644 --- a/src/main/java/net/encryption/MapleAESOFB.java +++ b/src/main/java/net/encryption/MapleAESOFB.java @@ -180,7 +180,7 @@ public class MapleAESOFB { @Override public String toString() { - return "IV: " + HexTool.toString(this.iv); + return "IV: " + HexTool.toHexString(this.iv); } private static byte[] funnyShit(byte inputByte, byte[] in) { diff --git a/src/main/java/net/packet/logging/InPacketLogger.java b/src/main/java/net/packet/logging/InPacketLogger.java index da9e8aa16d..adf48616a6 100644 --- a/src/main/java/net/packet/logging/InPacketLogger.java +++ b/src/main/java/net/packet/logging/InPacketLogger.java @@ -35,9 +35,9 @@ public class InPacketLogger extends ChannelInboundHandlerAdapter implements Pack final String opcodeName = getRecvOpcodeName(opcode); final String prefix = opcodeName == null ? " " : ""; log.debug("{}ClientSend:{} [{}] ({}) {} {}", prefix, opcodeName, opcodeHex, packetLength, - HexTool.toString(content), HexTool.toStringFromAscii(content)); + HexTool.toHexString(content), HexTool.toStringFromAscii(content)); } else { - log.debug(HexTool.toString(new byte[]{content[0], content[1]}) + "..."); + log.debug(HexTool.toHexString(new byte[]{content[0], content[1]}) + "..."); } } diff --git a/src/main/java/net/packet/logging/MonitoredChrLogger.java b/src/main/java/net/packet/logging/MonitoredChrLogger.java index dc3785e550..782e78c794 100644 --- a/src/main/java/net/packet/logging/MonitoredChrLogger.java +++ b/src/main/java/net/packet/logging/MonitoredChrLogger.java @@ -75,7 +75,7 @@ public class MonitoredChrLogger { return; } - String packet = packetContent.length > 0 ? HexTool.toString(packetContent) : ""; + String packet = packetContent.length > 0 ? HexTool.toHexString(packetContent) : ""; log.info("{}-{} {}-{}", c.getAccountName(), chr.getName(), packetId, packet); } diff --git a/src/main/java/net/packet/logging/OutPacketLogger.java b/src/main/java/net/packet/logging/OutPacketLogger.java index ea8a96356e..5de9307afd 100644 --- a/src/main/java/net/packet/logging/OutPacketLogger.java +++ b/src/main/java/net/packet/logging/OutPacketLogger.java @@ -36,9 +36,9 @@ public class OutPacketLogger extends ChannelOutboundHandlerAdapter implements Pa String opcodeName = getSendOpcodeName(opcode); String prefix = opcodeName == null ? " " : ""; log.debug("{}ServerSend:{} [{}] ({}) {} {}", prefix, opcodeName, opcodeHex, packetLength, - HexTool.toString(content), HexTool.toStringFromAscii(content)); + HexTool.toHexString(content), HexTool.toStringFromAscii(content)); } else { - log.debug(HexTool.toString(new byte[]{content[0], content[1]}) + " ..."); + log.debug(HexTool.toHexString(new byte[]{content[0], content[1]}) + " ..."); } } diff --git a/src/main/java/net/server/handlers/login/LoginPasswordHandler.java b/src/main/java/net/server/handlers/login/LoginPasswordHandler.java index 7d07dcc46d..4dbbae373b 100644 --- a/src/main/java/net/server/handlers/login/LoginPasswordHandler.java +++ b/src/main/java/net/server/handlers/login/LoginPasswordHandler.java @@ -50,7 +50,7 @@ public final class LoginPasswordHandler implements PacketHandler { private static String hashpwSHA512(String pwd) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest digester = MessageDigest.getInstance("SHA-512"); digester.update(pwd.getBytes(StandardCharsets.UTF_8), 0, pwd.length()); - return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase(); + return HexTool.toHexString(digester.digest()).replace(" ", "").toLowerCase(); } @Override @@ -67,7 +67,7 @@ public final class LoginPasswordHandler implements PacketHandler { p.skip(6); // localhost masked the initial part with zeroes... byte[] hwidNibbles = p.readBytes(4); - Hwid hwid = new Hwid(HexTool.bytesToHex(hwidNibbles)); + Hwid hwid = new Hwid(HexTool.toCompactHexString(hwidNibbles)); int loginok = c.login(login, pwd, hwid); diff --git a/src/main/java/tools/HexTool.java b/src/main/java/tools/HexTool.java index 5b83fd30f6..64b7959a0a 100644 --- a/src/main/java/tools/HexTool.java +++ b/src/main/java/tools/HexTool.java @@ -22,30 +22,44 @@ package tools; import constants.string.CharsetConstants; -import io.netty.buffer.ByteBufUtil; import java.util.HexFormat; -// TODO: use HexFormat from Java 17 +/** + * Handles converting back and forth from byte arrays to hex strings. + */ public class HexTool { /** - * Convert a byte array to its hex string representation. - * Each byte value is equivalent to two hex characters delimited by a space. + * Convert a byte array to its hex string representation (upper case). + * Each byte value is converted to two hex characters delimited by a space. * * @param bytes Byte array to convert to a hex string. * Example: {1, 16, 127, -1} is converted to "01 F0 7F FF" * @return The hex string */ - public static String toString(byte[] bytes) { + public static String toHexString(byte[] bytes) { return HexFormat.ofDelimiter(" ").withUpperCase().formatHex(bytes); } /** - * Convert a hex string to its byte array representation. Two consecutive hex characters are equivalent to one byte. + * Convert a byte array to its hex string representation (upper case). + * Like {@link #toHexString(byte[]) HexTool.toString}, but with no space delimiter. * - * @param hexString Hex string to convert to bytes. Hex character pairs may be delimited by a space or not (compact) + * @return The compact hex string + */ + public static String toCompactHexString(byte[] bytes) { + return HexFormat.of().withUpperCase().formatHex(bytes); + } + + /** + * Convert a hex string to its byte array representation. Two consecutive hex characters are converted to one byte. + * + * @param hexString Hex string to convert to bytes. May be lower or upper case, and hex character pairs may be + * delimited by a space or not. * Example: "01 10 7F FF" is converted to {1, 16, 127, -1}. + * The following hex strings are considered identical and are converted to the same byte array: + * "01 10 7F FF", "01107FFF", "01 10 7f ff", "01107fff" * @return The byte array */ public static byte[] toBytes(String hexString) { @@ -57,27 +71,19 @@ public class HexTool { } public static String toStringFromAscii(final byte[] bytes) { - byte[] ret = new byte[bytes.length]; - for (int x = 0; x < bytes.length; x++) { - if (bytes[x] < 32 && bytes[x] >= 0) { - ret[x] = '.'; + byte[] filteredBytes = new byte[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + if (isSpecialCharacter(bytes[i])) { + filteredBytes[i] = '.'; } else { - int chr = ((short) bytes[x]) & 0xFF; - ret[x] = (byte) chr; + filteredBytes[i] = (byte) (bytes[i] & 0xFF); } } - return new String(ret, CharsetConstants.CHARSET); + return new String(filteredBytes, CharsetConstants.CHARSET); } - /** - * Get upper case hex dump - */ - public static String bytesToHex(byte[] bytes) { - return ByteBufUtil.hexDump(bytes).toUpperCase(); - } - - public static byte[] hexToBytes(String hex) { - return ByteBufUtil.decodeHexDump(hex); + private static boolean isSpecialCharacter(byte asciiCode) { + return asciiCode >= 0 && asciiCode <= 31; } } diff --git a/src/test/java/tools/HexToolTest.java b/src/test/java/tools/HexToolTest.java index 1a8a864080..0354ca9a97 100644 --- a/src/test/java/tools/HexToolTest.java +++ b/src/test/java/tools/HexToolTest.java @@ -11,7 +11,14 @@ class HexToolTest { void bytesToHexString() { byte[] bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 127, -1}; String expectedHexString = "01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 7F FF"; - assertEquals(expectedHexString, HexTool.toString(bytes)); + assertEquals(expectedHexString, HexTool.toHexString(bytes)); + } + + @Test + void bytesToCompactHexString() { + byte[] bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 127, -1}; + String expectedHexString = "0102030405060708090A0B0C0D0E0F10117FFF"; + assertEquals(expectedHexString, HexTool.toCompactHexString(bytes)); } @Test @@ -29,16 +36,23 @@ class HexToolTest { } @Test - void upperCaseHexToBytesAndBack() { - String hex = "A1B2C3"; - byte[] bytes = HexTool.hexToBytes(hex); - assertEquals(hex, HexTool.bytesToHex(bytes)); + void lowerCaseHexStringToBytes() { + String lowerCaseHexString = "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 7f ff"; + byte[] expectedBytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 127, -1}; + assertArrayEquals(expectedBytes, HexTool.toBytes(lowerCaseHexString)); } @Test - void mixedCaseHexToBytesAndBack() { - String hex = "aB5DaA"; - byte[] bytes = HexTool.hexToBytes(hex); - assertEquals(hex.toUpperCase(), HexTool.bytesToHex(bytes)); + void lowerCaseCompactHexStringToBytes() { + String hexString = "0102030405060708090a0b0c0d0e0f10117fff"; + byte[] expectedBytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 127, -1}; + assertArrayEquals(expectedBytes, HexTool.toBytes(hexString)); + } + + @Test + void toStringFromAscii() { + byte[] asciiBytes = new byte[]{1, 10, 20, 30, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 0, 31}; + String expectedString = "....0123456789.."; + assertEquals(expectedString, HexTool.toStringFromAscii(asciiBytes)); } } \ No newline at end of file