对象嵌套 Uint8Array(32) 到 String 到 btoa 到 localStorage 到 atob 到 Uint8Array(32)
Object Nested Uint8Array(32) to String to btoa to localStorage to atob to Uint8Array(32)
我在 javascript 方面的技能很少,我不确定在将原始 Uint8Array(32) 发送到 localStorage、解码并转换回 Uint8Array(32) 后如何获取它。下面您将看到我尝试将私钥字符串化,然后对其进行 base64 编码,以便将其发送到 localStorage 供以后使用:
window.genSKey = function()
{
var secretKey = eccrypto.generatePrivate();
console.log(secretKey);
var skey = JSON.stringify(secretKey);
var SKey = window.btoa(skey);
localStorage.setItem("skey", SKey);
console.log(SKey);
alert(`your private key is ${SKey}`);
return;
}
在这里你会注意到我正在尝试获取私钥,以便我可以通过从 localStorage 中获取 base64 编码的字符串并从中创建一个新的 Uint8Array 来生成相应的 public 密钥:
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;
}
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, 228, 72, 92, 221, 139, 235, 147, 244, 10, 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
我认为问题可能在于使用 JSON.stringify 将嵌套的 Uint8Array 转换为字符串,但我不确定是否有其他方法可以很好地实现此功能。
为什么输入的对象和输出的对象不一样?我想学习如何做到这一点,帮助对我来说意味着整个世界。
一些问题:
虽然你用了JSON.stringify
,但你从来没有用过反向操作,即JSON.parse
你用了charCodeAt
,但你从来没有用过反向操作,即String.fromCharCode
。 charCodeAt
与您制作字符串的方式无关,因此应将其删除。
调试此类问题时,应消除步骤。例如,您会发现以下步骤与您的问题无关:
- 在本地存储中存储和检索;
- 与 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%。你可以没有这个。
- 本地存储
- 加密模块
在继续下一步之前,请继续检查操作是否可以反转,让您返回类型化数组的原始值,就像我在上面的代码片段中所做的那样。
我在 javascript 方面的技能很少,我不确定在将原始 Uint8Array(32) 发送到 localStorage、解码并转换回 Uint8Array(32) 后如何获取它。下面您将看到我尝试将私钥字符串化,然后对其进行 base64 编码,以便将其发送到 localStorage 供以后使用:
window.genSKey = function()
{
var secretKey = eccrypto.generatePrivate();
console.log(secretKey);
var skey = JSON.stringify(secretKey);
var SKey = window.btoa(skey);
localStorage.setItem("skey", SKey);
console.log(SKey);
alert(`your private key is ${SKey}`);
return;
}
在这里你会注意到我正在尝试获取私钥,以便我可以通过从 localStorage 中获取 base64 编码的字符串并从中创建一个新的 Uint8Array 来生成相应的 public 密钥:
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;
}
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, 228, 72, 92, 221, 139, 235, 147, 244, 10, 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
我认为问题可能在于使用 JSON.stringify 将嵌套的 Uint8Array 转换为字符串,但我不确定是否有其他方法可以很好地实现此功能。
为什么输入的对象和输出的对象不一样?我想学习如何做到这一点,帮助对我来说意味着整个世界。
一些问题:
虽然你用了
JSON.stringify
,但你从来没有用过反向操作,即JSON.parse
你用了
charCodeAt
,但你从来没有用过反向操作,即String.fromCharCode
。charCodeAt
与您制作字符串的方式无关,因此应将其删除。调试此类问题时,应消除步骤。例如,您会发现以下步骤与您的问题无关:
- 在本地存储中存储和检索;
- 与 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%。你可以没有这个。
- 本地存储
- 加密模块
在继续下一步之前,请继续检查操作是否可以反转,让您返回类型化数组的原始值,就像我在上面的代码片段中所做的那样。