Object Nested Uint8Array(32) to String to btoa to localStorage to atob to Uint8Array(32)

问题描述

我在 javascript 方面的技能很少,我不确定如何在将原始 Uint8Array(32) 发送到 localStorage、解码并转换回 Uint8Array(32) 后获取它。下面您将看到我尝试将私钥字符串化,然后对其进行 base64 编码,以便将其发送到 localStorage 以供以后使用:

window.base642Array = function(base64) {
    var binStr = window.atob(base64);
    console.log("binStr"+ binStr);
    var l = binStr.length;
    var bytes = new Uint8Array(l);
    for (var i = 0; i < l; i++) {
        bytes[i] = binStr.charCodeAt(i);
    }
    return bytes.buffer;
}

在这里你会注意到我正在尝试获取私钥,以便我可以通过从 localStorage 中获取 base64 编码的字符串并从中创建一个新的 Uint8Array 来生成相应的公钥:

window.genPKey = function()
{
    console.log("getSKey flag: 0");

    var SKey = getSKey();

    console.log("getSKey flag: 1");

    var publicKey;
    if(SKey != null || undefined)
    {
        console.log(SKey);

        console.log("getSKey flag: 2");

        publicKey = eccrypto.getPublic(SKey);

        console.log("getSKey flag: 3");

        localStorage.setItem("pkey",window.btoa(JSON.stringify(publicKey)));

        return;

    }

    console.log("getSKey flag: alt");

    genSKey();
    genPKey();

    return;
window.getSKey = function()
{
    console.log("getSKey flag: 0");

    var SKey = localStorage.getItem("skey");

    var skey = base642Array(SKey);

    console.log("getSKey flag: 1");

    console.log("getSKey flag: 2");

    console.log(skey);

    return skey;
}
Uint8Array(32) [247,145,236,54,52,10,202,187,35,79,42,141,230,76,228,2,109,72,92,221,139,235,147,244,149,220,196,175,11,128]
0: 247
1: 145
2: 236
3: 54
4: 52
5: 10
6: 202
7: 187
8: 35
9: 79
10: 42
11: 141
12: 230
13: 76
14: 228
15: 2
16: 109
17: 228
18: 72
19: 92
20: 221
21: 139
22: 235
23: 147
24: 244
25: 10
26: 149
27: 220
28: 196
29: 175
30: 11
31: 128
offset: (...)
parent: (...)
buffer: (...)
byteLength: (...)
byteOffset: (...)
length: (...)
Symbol(Symbol.toStringTag): (...)
__proto__: Uint8Array

在这里您会看到输入的结果与输出的结果不同:

ArrayBuffer(141) {}
[[Int8Array]]: Int8Array(141)
[0 … 99]
[100 … 140]
__proto__: TypedArray
[[Uint8Array]]: Uint8Array(141)
[0 … 99]
[100 … 140]
__proto__: TypedArray
byteLength: (...)
__proto__: ArrayBuffer
byteLength: (...)
constructor: ƒ ArrayBuffer()
slice: ƒ slice()
Symbol(Symbol.toStringTag): "ArrayBuffer"
get byteLength: ƒ byteLength()
__proto__: Object
[[IsDetached]]: false

{{1}}

我认为问题可能在于使用 JSON.stringify 将嵌套的 Uint8Array 转换为字符串,但我不确定其他方法可以使此功能正常运行。

为什么对象输入和对象输出不一样?我想学习如何做到这一点,帮助对我来说意味着整个世界。

解决方法

一些问题:

  • 尽管您使用了 JSON.stringify,但您从未使用过相反的操作,即 JSON.parse

  • 您使用了 charCodeAt,但您从未使用过相反的操作,即 String.fromCharCodecharCodeAt 与您制作字符串的操作无关,因此应该删除它。

  • 在调试此类问题时,您应该消除步骤。例如,您会发现以下步骤与您的问题无关:

    • 从本地存储中存储和检索;
    • 与base64编码相互转换;
    • 使用加密库

    问题在于将类型化数组转换为字符串并返回。

转换为字符串和转换回类型数组根本不是彼此的颠倒。

要解决此问题,我建议将您必须调用的调用更改为 JSON.stringify,以便将字符串化为数组表示法(以 [ 开头)而不是普通对象表示法(以{)。所以改变:

JSON.stringify(secretKey);

到:

JSON.stringify(Array.from(secretKey));

然后将该字符串转回类型化数组,使用 JSON.parse:

new Uint8Array(JSON.parse(str))

这是一个没有不相关步骤的小演示:

function fromTypedArrayToString(arr) {
    return JSON.stringify([...arr]);
}

function fromStringToTypedArray(str) {
    return new Uint8Array(JSON.parse(str));
}

function compareTypedArrays(arr1,arr2) {
    if (arr1.length !== arr2.length) return false;
    for (let i = 0; i < arr1.length; i++) {
        if (arr1[i] !== arr2[i]) return false;
    }
    return true;
}  

// Demo: make a typed array with all possible values
let arr = new Uint8Array([...Array(256).keys()]);
let str = fromTypedArrayToString(arr);
let arr2 = fromStringToTypedArray(str);
let consistent = compareTypedArrays(arr,arr2);
console.log("Is the result consistent:",consistent);

您应该能够将其应用到您的代码中,并逐步添加:

  • base64 编码,虽然我看不到它的好处:字符串的大小会增长 30%。你可以没有这个。
  • 本地存储
  • 加密模块

在继续下一步之前,请继续检查操作是否可以反转,返回类型化数组的原始值,就像我在上面的代码片段中所做的那样。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...