如何将十六进制字符串转换为字节数组,以及将字节数组转换为十六进制字符串?

34
下面的代码过程bytes = parseHexString (createHexString (bytes))导致了字节的更新,我想避免这种情况。结果,计算不正确。
<html>
<head>
<SCRIPT SRC="http://eu.static.mega.co.nz/sjcl_1.js"></SCRIPT>
<SCRIPT SRC="http://eu.static.mega.co.nz/crypto_1.js"></SCRIPT>
<SCRIPT SRC="http://eu.static.mega.co.nz/rsa_1.js"></SCRIPT>
<SCRIPT SRC="http://eu.static.mega.co.nz/hex_1.js"></SCRIPT>
<SCRIPT>
function parseHexString(str) { 
    var result = [];
    while (str.length >= 2) { 
        result.push(parseInt(str.substring(0, 2), 16));
        str = str.substring(2, str.length);
    }

    return result;
}

function createHexString(arr) {
    var result = "";
    for (i in arr) {
        var str = arr[i].toString(16);
        str = str.length == 0 ? "00" :
              str.length == 1 ? "0" + str : 
              str.length == 2 ? str :
              str.substring(str.length-2, str.length);
        result += str;
    }
    return result;
}

function t()
{
    var json_k     = 'aOrP5yLtNQT53WMQfufSlA';
    var json_csid  = 'CABD6JUMldvI_eqP0537xl9P8x7kgk2OjOq99Fy7kosphj6AFUtlbwRRDpg4EIifXRLO6FNpdD22WwtUlJ_1Mgye2Y87trEqLCbhahuEFJVQNMDtNbIem7xY2ER9uF-cdgBXZWuzp7XIBybSh7W8MSUlv_eGS6LcLGJ81Q49dSzVhcswHTJ_IJl04p3c0axR6ZIJ8dH5bJ_vXvgQsypUVVtdfMacKhB9cXdEtRZ6iWLKCKqscXdo6CNXlbIdzRhro0gxfmhfB_miysFAiSQrbtuYnIgYBU3i9p3jRlPD4ti3CUcnj0SomV61w1aEYNvo56HPMUZlVkVHA7BFzvHGHo0J';
    var json_privk = 'K7LDtk2M2QhjJx_v_Hqf0LKUBaZx76U_vBDjQty9HpFDy2MntF5HxxuyHQ9-1HmXeYzbL1pZnAxsZ7LRUbDnkR6qtJVaGdWuQhrytkuq0l5zBp-O--gZxoQPRGTsVgVRdAvpsRTkQI_q8fxADLCe0womFxtvvnD_FJgjaMsm7vkYchXkoq33WWyHijb3JMkymjl0_GtiSamT0qEL6sm_l5Z1lehqBGUEHfYAa0ub8IDx_yqy2R9Nh8Lwzmz4s24sShVxjaNsMBlSE-sEvTziOsnNWK1Zl_XUYadlENkweuIoxYx_lt8XIV71TzjEFuVTd-pXhzVlqePmIu3SM3bO1Kzq_DnGfB62RmzlmbtHU4iyw4Hd1wQFRhTeSRrvMjsMPFKN-SIIQU7CRNaMuaDxZbNZcOKhMg_h9mApM0rRS3VZaGZzFTL9rSaDMYHw4pL3aOkSFPMY3w785Tss7Zqwuo9HFUWUVbnYAb97JkgCohlMotORrMMtual1dQ4sG1sIYXyWTckAGGL0ZAGurhtSKiyz1m8Lb39pXPacqFh_nCHqqb2_RdrKTj0PdGZESKkU8YedeqC1I9nR4v38DuQc-pBBR5DOwgNjJMvzvsUehs_PxIL8THjgIcr7ONc4hWV9o2v_l81Vo2cCW2I99Iz84IFN2fV1dTqHIG_tnLzz8ljBVygETUqrFdZ0JlQJkurZ7RBku5krm-k9CZmDezCIzPPil-RcYzVIk00gNYAxfiZE48Or4WEiGjgKLnHCYVtSlvlMF4bPGB4SVCZ-68j49EjfSWaMK0OoMkpGhqf7KchgxYBZq6o3AhLgp4t0BClvsdee6VTz1SFqc3m2A-TMG6fNdbCT_Q9nYCYdZIROdOc';

    var aes = new sjcl.cipher.aes( prepare_key_pw("oEyoo9cQcw") );
    k = decrypt_key(aes, base64_to_a32(json_k) );

    aes = new sjcl.cipher.aes(k);

    var t = mpi2b(base64urldecode(json_csid));

    var privk = a32_to_str(decrypt_key(aes,base64_to_a32(json_privk)));

    var rsa_privk = Array(4);
    for (var i = 0; i < 4; i++)
    {
        var l = ((privk.charCodeAt(0)*256+privk.charCodeAt(1)+7)>>3)+2;

        rsa_privk[i] = mpi2b(privk.substr(0,l));
        if (typeof rsa_privk[i] == 'number') break;
        privk = privk.substr(l);    
    }

    var p = parseHexString(createHexString(rsa_privk[0]));  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    var q = parseHexString(createHexString(rsa_privk[1]));  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    var d = parseHexString(createHexString(rsa_privk[2]));  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    var u = parseHexString(createHexString(rsa_privk[3]));  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!
    sid = base64urlencode(b2s(RSAdecrypt(t,d,p,q,u)).substr(0,43));
    if (sid!=='tajetAbW0qTQGFlwp8iD5lQ0TFV1QUZJZFVvjRX7Xx-bPzYBoau7qog09w')
        console.log("ERROR");

    p = rsa_privk[0];
    q = rsa_privk[1];
    d = rsa_privk[2];
    u = rsa_privk[3];
    sid = base64urlencode(b2s(RSAdecrypt(t,d,p,q,u)).substr(0,43));
    if (sid=='tajetAbW0qTQGFlwp8iD5lQ0TFV1QUZJZFVvjRX7Xx-bPzYBoau7qog09w')
        console.log("OK");
}
</script>

</head>
<body onload="t();"></body>
</html>

我不是JavaScript开发人员,而且在谷歌代码中也没有找到适用于这些数据的方法。

更新1

console.log(createHexString(rsa_privk[0])); = e5d109c673d8ef03df564beb9e36e9983a23842b0a724efa45ff76bbe5ad72ed62d2757968 

但是如果这样做

parseHexString('e5d109c673d8ef03df564beb9e36e9983a23842b0a724efa45ff76bbe5ad72ed‌​62d2757968'); 

然后代码 if (sid!== ... 出现错误

更新2

console.log(rsa_privk[0].toString(16));

输出结果:123676133、198914513、129998601、245147334、11918451、206998232、96766191、75984899、177840095、106709334、10180427、208237547、119814814、127003446、189062377、84099480、220452154、250519075、267883908、115471915、165124106、238628722、169382478、42320122、95982405、80725759、89608310、85166267、200925925、254033325、86971506、191278317、127411298、180195794、142776693、188738169、39016

更新 3

console.log(parseHexString(createHexString(rsa_privk[0])));
console.log(rsa_privk[0]);

输出:

[229, 209, 9, 198, 115, 216, 239, 3, 223, 86, 75, 235, 158, 54, 233, 152, 58, 35, 132, 43, 10, 114, 78, 250, 69, 255, 118, 187, 229, 173, 114, 237, 98, 210, 117, 121, 104]

[123676133, 198914513, 129998601, 245147334, 11918451, 206998232, 96766191, 75984899, 177840095, 106709334, 10180427, 208237547, 119814814, 127003446, 189062377, 84099480, 220452154, 250519075, 267883908, 115471915, 165124106, 238628722, 169382478, 42320122, 95982405, 80725759, 89608310, 85166267, 200925925, 254033325, 86971506, 191278317, 127411298, 180195794, 142776693, 188738169, 39016]

你期望获取什么数据?你实际获取到了什么数据? - ATOzTOA
我期望转换数据 = parseHexString (createHexString (data)) 不会改变数据。 - SkyN
复制粘贴您的输入到 createHexString(rsa_privk[0]),即 console.log(rsa_privk[0]); - ATOzTOA
好的,如果我理解正确,您只想以十六进制形式显示数据,对吗?那您为什么需要将其转换回来呢? - ATOzTOA
更新了带有解决方案的答案... 请享用... - ATOzTOA
显示剩余2条评论
6个回答

80

将十六进制字符串转换为字节数组及其反向操作

注意:此实现来自 crypto-js,尽管现在已过时并略有变化

// Convert a hex string to a byte array
function hexToBytes(hex) {
    let bytes = [];
    for (let c = 0; c < hex.length; c += 2)
        bytes.push(parseInt(hex.substr(c, 2), 16));
    return bytes;
}

// Convert a byte array to a hex string
function bytesToHex(bytes) {
    let hex = [];
    for (let i = 0; i < bytes.length; i++) {
        let current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
        hex.push((current >>> 4).toString(16));
        hex.push((current & 0xF).toString(16));
    }
    return hex.join("");
}

1
这个有效。其他的都没对我起作用。非常感谢你。 - darkheartfelt
1
提醒一下,crypto-js API 已经更改为 CryptoJS.enc.Hex.parse(),不再使用 hexToBytes。 - Qiulang
bytesToHex在某些情况下计算结果很奇怪。例如[159,15]被计算为'9f0f',但应该是'9ff'。[25,255]又可以正确计算。这是一个大小端问题吗?问题从第一个数组元素的第9位开始。接受答案中的createHexString函数对我有效。 - TefoD
@TefoD 我无法重现你的问题。这段代码对我来说运行良好。 - Roman Podlinov
仅使用 Buffer.toString("hex")Buffer.from(str, "hex") 有什么问题吗? - kravitz
显示剩余3条评论

14

更新:解决方案请往下滚动... 实时演示

问题:您正在使用一种无法逆转的有损十六进制转换。

var p = parseHexString(createHexString(rsa_privk[0]));

这将永远不会与rsa_privk [0]相同。

因为createHexString()仅使用每个数组元素的最后2个字节

例如:

rsa_privk[0] : [123676133, 198914513, 129998601, 245147334, 11918451, 206998232, 96766191, 75984899, 177840095, 106709334, 10180427, 208237547, 119814814, 127003446, 189062377, 84099480, 220452154, 250519075, 267883908, 115471915, 165124106, 238628722, 169382478, 42320122, 95982405, 80725759, 89608310, 85166267, 200925925, 254033325, 86971506, 191278317, 127411298, 180195794, 142776693, 188738169, 39016]

createHexString(rsa_privk[0]) : e5d109c673d8ef03df564beb9e36e9983a23842b0a724efa45ff76bbe5ad72ed62d2757968

parseHexString(createHexString(rsa_privk[0])) : [229, 209, 9, 198, 115, 216, 239, 3, 223, 86, 75, 235, 158, 54, 233, 152, 58, 35, 132, 43, 10, 114, 78, 250, 69, 255, 118, 187, 229, 173, 114, 237, 98, 210, 117, 121, 104] 

更新:工作解决方案...

这两个函数...十六进制始终包含8字节块,每个元素对应一个块...

function parseHexString(str) { 
    var result = [];
    while (str.length >= 8) { 
        result.push(parseInt(str.substring(0, 8), 16));

        str = str.substring(8, str.length);
    }

    return result;
}

function createHexString(arr) {
    var result = "";
    var z;

    for (var i = 0; i < arr.length; i++) {
        var str = arr[i].toString(16);

        z = 8 - str.length + 1;
        str = Array(z).join("0") + str;

        result += str;
    }

    return result;
}

测试代码...

function test() {   
    a = [123676133, 198914513, 129998601, 245147334, 11918451, 206998232, 96766191, 75984899, 177840095, 106709334, 10180427, 208237547, 119814814, 127003446, 189062377, 84099480, 220452154, 250519075, 267883908, 115471915, 165124106, 238628722, 169382478, 42320122, 95982405, 80725759, 89608310, 85166267, 200925925, 254033325, 86971506, 191278317, 127411298, 180195794, 142776693, 188738169, 39016];

    console.log("Input");
    console.log(a);

    b = createHexString(a);

    console.log("Hex");
    console.log(b);

    c = parseHexString(b); 

    console.log("Output");
    console.log(c);

    if(checkIfEqual(a, c)) {
        alert("Same");
    }
}

function checkIfEqual(arr1, arr2) {
    if (arr1.length != arr2.length) {
        return false;
    }
    //sort them first, then join them and just compare the strings
    return arr1.sort().join() == arr2.sort().join();
}

你的输入和输出是什么? - ATOzTOA
以上代码中的数据以二进制形式表示。问题是如何以十六进制格式显示它们。但我确定没有得到正确的结果,因为通过反向转换数据不正确。 - SkyN
创建了不美观的全局变量 z。 - Pointer Null
@PointerNull 只需将 z 的实例替换为其值即可。 - ATOzTOA
当然,我只是指出你的示例代码污染了全局命名空间。你少写了一个“var”。 - Pointer Null
显示剩余5条评论

9
我想说的是,在https://github.com/dcodeIO/bytebuffer.js上有一个库可以轻松帮助进行类似转换的操作,因此您不需要编写自己的函数(这可能不是最优解,或者如果您的解决方案在GitHub的开源社区中得到审查后可能会更加优秀)。
var ByteBuffer = require("bytebuffer");

var bb = ByteBuffer.fromHex(yourHexString);

// need to convert it to base 64?
// bb.toBase64();

请查看https://github.com/dcodeIO/bytebuffer.js/wiki/API#bytebufferfromhexstr-littleendian-noassert获取API文档及更多有关我上面使用的方法的信息。

3

仅做澄清,如果您只想对简单的字符串进行十六进制解码,例如48656C6C6F20576F726C6421Hello World!),则可以使用OP函数,但是不要使用长度为8,而应该使用长度为2。

代码:

var DecodeHexStringToByteArray = function (hexString) {
   var result = [];
   while (hexString.length >= 2) { 
       result.push(parseInt(hexString.substring(0, 2), 16));
       hexString = hexString.substring(2, hexString.length);
   }
   return result;
}

输出将是 [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]

我知道这段代码已经在问题中了,但它并不在被接受的答案中。我的目的只是给出对正在询问的问题的第一部分(如何将十六进制字符串转换为字节数组)直截了当的答案。


3

我在这里找到了解决方案 点击链接查看

function hexStringToByteArray(hexString) {
    if (hexString.length % 2 !== 0) {
        throw "Must have an even number of hex digits to convert to bytes";
    }
    var numBytes = hexString.length / 2;
    var byteArray = new Uint8Array(numBytes);
    for (var i=0; i<numBytes; i++) {
        byteArray[i] = parseInt(hexString.substr(i*2, 2), 16);
    }
    return byteArray;
}

再次感谢http://www.java2s.com


0
这是一个针对此测试的实时示例。

http://jsfiddle.net/vincentwang2020/eks1z4g2/

function testcreateHexString()
{
    alert('test function createHexString');
    var key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];
    var result = createHexString(key);
    alert ('Hex value:' + result);

    alert('test function parseHexString');

    var key2 = parseHexString(result);

    if (key.sort().join() == key2.sort().join())
        alert ('Matched');

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接