furioushercules
furioushercules

Reputation: 31

Equivalent Perl pack ("H*") in Java with non-hexadecimal characters

I'm trying to rewrite Perl script to Java. There is a line in this script with pack function:

my $key = '0rdR-0PrdK';
$key = pack("H*", $key);

The method i use in java is:

private static byte[] hexToBytes(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i + 1), 16));
    }
    return data;
}

it works correctly on hex strings, but it doesnt on non-hex strings

on the left bytes received in java, on the right from perl '0rdR-0PrdK'

-1      11
-49     -37
-16     -48
-17     -101
-49     -44

Have any of you had such a problem? How to solve it?

Upvotes: 2

Views: 202

Answers (2)

furioushercules
furioushercules

Reputation: 31

pack("H*", '0rdR-0PrdK') produces garbage.

Thats true, but this garbage were used as secret key in encryption algorithm. It was possible to decrypt when you used the same garbage.

I was really pressed on time so i did it this way:

  • I found packed(H*...) value of every character in Perl
  • encode them with Base64
  • decode hardcoded values in Java

    private static final String[] possibleChars = {"0`", "`0", "0~", "~0", "0!", "!0", "0@", "@0", "0#", "#0", "0$", "$0", "0%", "%0", "0^", "^0",
                "0&", "&0", "0*", "*0", "0(", "(0", "0)", ")0", "0-", "-0", "0_", "_0", "0=", "=0", "0+", "+0", "0[", "[0", "0{", "{0",
                "0]", "]0", "0}", "}0", "0\\", "\\0", "0|", "|0", "0;", ";0", "0:", ":0", "0'", "'0", "0\"", "\"0", "0,", ",0", "0<",
                "<0", "0.", ".0", "0>", ">0", "0/", "/0", "0?", "?0", "0a", "a0", "0b", "b0", "0c", "c0", "0d", "d0", "0e", "e0", "0f",
                "f0", "0g", "g0", "0h", "h0", "0i", "i0", "0j", "j0", "0k", "k0", "0l", "l0", "0m", "m0", "0n", "n0", "0o", "o0", "0p",
                "p0", "0q", "q0", "0r", "r0", "0s", "s0", "0t", "t0", "0u", "u0", "0v", "v0", "0w", "w0", "0x", "x0", "0y", "y0", "0z",
                "z0", "00", "00", "01", "10", "02", "20", "03", "30", "04", "40", "05", "50", "06", "60", "07", "70", "08", "80", "09", "90"};
    private static final String[] base64codes = {"AA==", "AA==", "Dg==", "4A==", "AQ==", "EA==", "AA==", "AA==", "Aw==", "MA==", "BA==",
                "QA==", "BQ==", "UA==", "Dg==", "4A==", "Bg==", "YA==", "Cg==", "oA==", "CA==", "gA==", "CQ==", "kA==", "DQ==", "0A==",
                "Dw==", "8A==", "DQ==", "0A==", "Cw==", "sA==", "Cw==", "sA==", "Cw==", "sA==", "DQ==", "0A==", "DQ==", "0A==", "DA==",
                "wA==", "DA==", "wA==", "Cw==", "sA==", "Cg==", "oA==", "Bw==", "cA==", "Ag==", "IA==", "DA==", "wA==", "DA==", "wA==",
                "Dg==", "4A==", "Dg==", "4A==", "Dw==", "8A==", "Dw==", "8A==", "Cg==", "oA==", "Cw==", "sA==", "DA==", "wA==", "DQ==",
                "0A==", "Dg==", "4A==", "Dw==", "8A==", "AA==", "AA==", "AQ==", "EA==", "Ag==", "IA==", "Aw==", "MA==", "BA==", "QA==",
                "BQ==", "UA==", "Bg==", "YA==", "Bw==", "cA==", "CA==", "gA==", "CQ==", "kA==", "Cg==", "oA==", "Cw==", "sA==", "DA==",
                "wA==", "DQ==", "0A==", "Dg==", "4A==", "Dw==", "8A==", "AA==", "AA==", "AQ==", "EA==", "Ag==", "IA==", "Aw==", "MA==",
                "AA==", "AA==", "AQ==", "EA==", "Ag==", "IA==", "Aw==", "MA==", "BA==", "QA==", "BQ==", "UA==", "Bg==", "YA==", "Bw==",
                "cA==", "CA==", "gA==", "CQ==", "kA=="};

    private static void initializeHashMap() {
            for (int i = 0; i < possibleChars.length; i++) {
                hashMap.put(possibleChars[i], base64codes[i]);
            }
    }
    
    public static byte[] h16pack(String s) {
            String str = s.toLowerCase();
            int len = s.length();
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) (Base64.decode(hashMap.get(str.charAt(i) + "0"))[0]
                        + Base64.decode(hashMap.get("0" + str.charAt(i + 1)))[0]);
            }
            return data;
    }

not elegant, but it works

Upvotes: 1

ikegami
ikegami

Reputation: 386331

pack("H*", '0rdR-0PrdK') produces garbage.

$ perl -M5.014 -e'
   my $encoded = pack "H*", $ARGV[0];
   my $decoded = unpack "H*", $encoded;
   say $decoded;
   say $decoded eq $ARGV[0] ? "ok" : "ERROR";
' 0rdR-0PrdK
0bdbd09bd4
ERROR

It's impossible to get 0rdR-0PrdK from the the output of pack("H*", 0rdR-0PrdK").

Someone meant to use unpack "H*" but accidentally used pack "H*".

# bytes -> hex
$ perl -M5.014 -e'say unpack "H*", $ARGV[0]' 0rdR-0PrdK
307264522d305072644b

# hex -> bytes
$ perl -M5.014 -e'say pack "H*", $ARGV[0]' \
   "$( perl -M5.014 -e'say unpack "H*", $ARGV[0]' 0rdR-0PrdK )"
0rdR-0PrdK

You should fix that instead of trying to work around the bug.


The bytes you want can be obtained using the following:

$ perl -M5.014 -e'say for unpack "c*", pack "H*", $ARGV[0]' 0rdR-0PrdK
11
-37
-48
-101
-44

The following will provide a string you can pass to hexToBytes to obtain the same result:

$ perl -M5.014 -e'say for unpack "H*", pack "H*", $ARGV[0]' 0rdR-0PrdK
0bdbd09bd4

Upvotes: 2

Related Questions