Hướng dẫn decode hex javascript

It seems to be XOR'ed with number 5

const data = "64 67 66 61 60 63 62 6D 6C 6F 6E 69 68 6B 6A 75 74 77 76 71 70 73 72 7D 7C 7F";

console.log[data.split[" "].map[n => String.fromCharCode[parseInt[n, 16] ^ 5]].join[""]];

Knowing the expected result, we can compare existing number with expected to see the difference and find a pattern.

Let's compare first number 64 with letter a [61] in binary:

0x64 = 01100100
0x61 = 01100001

now the second number 67 with letter b [62]:

0x67 = 01100111
0x62 = 01100010

and third number 66 with letter c [63]:

0x66 = 01100110
0x63 = 01100011

If you look closely, you can see that there is a pattern, bit 0 and 2 [bits count from right side] are not matching. So, if we convert binary 00000101 into decimal we'll get number 5

const data = "64 67 66 61 60 63 62 6D 6C 6F 6E 69 68 6B 6A 75 74 77 76 71 70 73 72 7D 7C 7F";

data.split[" "].forEach[[n,i] =>
{
  const number = parseInt[n, 16],
        numberExpected = "a".charCodeAt[0] + i,
        char = String.fromCharCode[number],
        charExpected = String.fromCharCode[numberExpected],
        xor = number ^ numberExpected,
        result = number ^ xor,
        charResult = String.fromCharCode[result];

  console.log[`${char} [${n}] | expected: ${charExpected} [${numberExpected.toString[16]}] | XOR difference: ${xor} | result: ${charResult}`];
}];
.as-console-wrapper{top:0;max-height:unset!important;overflow:auto!important;}

Một giải pháp cập nhật hơn, để mã hóa:

// This is the same for all of the below, and
// you probably won't need it except for debugging
// in most cases.
function bytesToHex[bytes] {
  return Array.from[
    bytes,
    byte => byte.toString[16].padStart[2, "0"]
  ].join[""];
}

// You almost certainly want UTF-8, which is
// now natively supported:
function stringToUTF8Bytes[string] {
  return new TextEncoder[].encode[string];
}

// But you might want UTF-16 for some reason.
// .charCodeAt[index] will return the underlying
// UTF-16 code-units [not code-points!], so you
// just need to format them in whichever endian order you want.
function stringToUTF16Bytes[string, littleEndian] {
  const bytes = new Uint8Array[string.length * 2];
  // Using DataView is the only way to get a specific
  // endianness.
  const view = new DataView[bytes.buffer];
  for [let i = 0; i != string.length; i++] {
    view.setUint16[i, string.charCodeAt[i], littleEndian];
  }
  return bytes;
}

// And you might want UTF-32 in even weirder cases.
// Fortunately, iterating a string gives the code
// points, which are identical to the UTF-32 encoding,
// though you still have the endianess issue.
function stringToUTF32Bytes[string, littleEndian] {
  const codepoints = Array.from[string, c => c.codePointAt[0]];
  const bytes = new Uint8Array[codepoints.length * 4];
  // Using DataView is the only way to get a specific
  // endianness.
  const view = new DataView[bytes.buffer];
  for [let i = 0; i != codepoints.length; i++] {
    view.setUint32[i, codepoints[i], littleEndian];
  }
  return bytes;
}

Ví dụ:

bytesToHex[stringToUTF8Bytes["hello 漢字 👍"]]
// "68656c6c6f20e6bca2e5ad9720f09f918d"
bytesToHex[stringToUTF16Bytes["hello 漢字 👍", false]]
// "00680065006c006c006f00206f225b570020d83ddc4d"
bytesToHex[stringToUTF16Bytes["hello 漢字 👍", true]]
// "680065006c006c006f002000226f575b20003dd84ddc"
bytesToHex[stringToUTF32Bytes["hello 漢字 👍", false]]
// "00000068000000650000006c0000006c0000006f0000002000006f2200005b57000000200001f44d"
bytesToHex[stringToUTF32Bytes["hello 漢字 👍", true]]
// "68000000650000006c0000006c0000006f00000020000000226f0000575b0000200000004df40100"

Để giải mã, nó thường đơn giản hơn rất nhiều, bạn chỉ cần:

function hexToBytes[hex] {
    const bytes = new Uint8Array[hex.length / 2];
    for [let i = 0; i !== bytes.length; i++] {
        bytes[i] = parseInt[hex.substr[i * 2, 2], 16];
    }
    return bytes;
}

sau đó sử dụng tham số mã hóa của TextDecoder:

// UTF-8 is default
new TextDecoder[].decode[hexToBytes["68656c6c6f20e6bca2e5ad9720f09f918d"]];
// but you can also use:
new TextDecoder["UTF-16LE"].decode[hexToBytes["680065006c006c006f002000226f575b20003dd84ddc"]]
new TextDecoder["UTF-16BE"].decode[hexToBytes["00680065006c006c006f00206f225b570020d83ddc4d"]];
// "hello 漢字 👍"

Đây là danh sách các tên mã hóa được phép: //www.w3.org/TR/encoding/#names-and-labels

Bạn có thể nhận thấy UTF-32 không có trong danh sách đó, đó là một điều khó khăn, vì vậy:

function bytesToStringUTF32[bytes, littleEndian] {
  const view = new DataView[bytes.buffer];
  const codepoints = new Uint32Array[view.byteLength / 4];
  for [let i = 0; i !== codepoints.length; i++] {
    codepoints[i] = view.getUint32[i * 4, littleEndian];
  }
  return String.fromCodePoint[...codepoints];
}

Sau đó:

bytesToStringUTF32[hexToBytes["00000068000000650000006c0000006c0000006f0000002000006f2200005b57000000200001f44d"], false]
bytesToStringUTF32[hexToBytes["68000000650000006c0000006c0000006f00000020000000226f0000575b0000200000004df40100"], true]
// "hello 漢字 👍"

10 hữu ích 0 bình luận chia sẻ

Chủ Đề