如何使用ES6代理(Proxy)处理ArrayBuffer或Uint8Array?

4

以下内容可行:

crypto.subtle.digest('SHA-512', new Uint8Array([0]))
crypto.subtle.digest('SHA-512', new Uint8Array([0]).buffer)

这些不行:

crypto.subtle.digest('SHA-512', new Proxy(new Uint8Array([0]),{}))
crypto.subtle.digest('SHA-512', new Proxy(new Uint8Array([0]).buffer,{})

错误:

'SubtleCrypto'上的 'digest' 执行失败:提供的值不是 '(ArrayBuffer 或 ArrayBufferView)'类型

instanceof Uint8Arrayinstanceof ArrayBuffer 在两种情况下都返回 true。


1
看起来本地的 crypto.subtle.digest 函数需要一个真正的类型化数组,而不是代理。即使它们在 JavaScript 中是无法区分的。 - Bergi
1
你想做什么?为什么要在这里使用代理? - Bergi
1
你可以完美地切割文件(Blob或ArrayBuffer)而不使用代理吗?虽然我不确定你打算如何使用代理来降低内存使用率。 - Bergi
本地加密不支持用于哈希的.update(data)。您只需提供一个ArrayBuffer,它将返回一个ArrayBuffer的承诺。故事结束。 - Mihail Malostanidis
我原本计划先给它第一片,然后在到达结尾时处理掉它并开始喂下一片,如此循环。目前来看,我已经基本接受这是不可能的了,显然它需要缓冲区作为其后端实现,而不是作为其JavaScript API。 - Mihail Malostanidis
显示剩余4条评论
1个回答

2

digest是由它的IDL接口指定仅接受BufferSource,该接口可以是ArrayBufferViewArrayBuffer。这个IDL级别的类型说明,正确的实现将明确拒绝任何没有正确内部类型的输入。

你可能想使用Proxy的任何技巧都无法在digest上起作用。相反,你可以使用代理技巧,在将数据传递给digest之前立即获得所需的确切ArrayBuffer

例如,下面是一个伪造与其内部对象上的buffer不同的buffer的代理。该buffer是真实的,因此可以传递给digest,但它是通过Proxy魔法创建的:

var proxy = new Proxy(new Uint8Array([0]), {
                          get:function(obj, prop) {
                              if(prop=="buffer"){ return new Uint8Array([42]).buffer }
                              else { return obj[prop]; }
                          }
            });
crypto.subtle.digest('SHA-512', proxy.buffer)

如果无法生成缓冲区(例如,如果它太大而无法放入RAM中),您目前必须依赖于SubtleCrypto以外的其他内容。
这似乎是向W3C提出的一个很好的观点,例如支持一个“更新”机制,以迭代地收集输入。

我想要的ArrayBuffer是非法的,因为它太大了。 - Mihail Malostanidis
@MihailMalostanidis 那你可能就没那么幸运了。你可能需要看看是否可以使用支持增量更新的非本地实现。这似乎是与W3C提出的一个很好的观点。此外,对于某些哈希函数,可能可以进行增量更新(例如,此Crypto.SE帖子暗示您可以编写一些组合函数F,使得F(Hash(s1), s2) == Hash(s1 + s2)适用于SHA-1、-2和-3),但如果存在给定哈希算法的这样的函数,您需要咨询哈希专家来创建它。 - apsillers
@MihailMalostanidis 看起来对于SHA-1和SHA-2系列函数(包括512),这样的函数F(oldHash, newInput)是可能的,但是对于SHA-3系列函数则不可能。请参考https://en.wikipedia.org/wiki/Length_extension_attack以了解如何开始实现此类功能。 - apsillers
在尝试纯JS解决方案之前,我考虑过用H(F(H(s1),s2)的方式来实现。然而,即使它可以打败一次迭代的填充,但需要将状态加载到SHA-512机器中意味着原生函数再次无法工作。 - Mihail Malostanidis
也许我应该考虑使用wasm来实现,因为它现在已经支持移动端了(这是纯JS最受伤的地方)。 - Mihail Malostanidis

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