Web中的文件sha256校验

Web中的文件sha256校验

SHA-256(Secure Hash Algorithm 256-bit)验证文件完整性有多个优点

  • 数据完整性验证: SHA-256 是一种加密哈希函数,它生成一个 256 位(32 字节)的哈希值,该值在理论上是唯一的。通过比较文件的 SHA-256 哈希值,用户可以验证文件是否在传输或存储过程中发生了任何更改。如果文件的 SHA-256 哈希值匹配预期的哈希值,那么文件的完整性就可以被确认。

  • 不可逆性: 哈希函数是不可逆的,这意味着从哈希值无法推导出原始数据。因此,即使哈希值是公开可见的,也无法通过哈希值还原出原始文件内容。这提供了额外的安全性,因为攻击者无法通过逆向工程哈希值来生成伪造的文件。

  • 唯一性: SHA-256 的输出是一个 256 位的哈希值,这个值的空间极其庞大,几乎可以保证不同的文件将生成不同的哈希值。这增加了哈希冲突的难度,使得两个不同的文件生成相同的 SHA-256 哈希值的可能性非常低。

  • 广泛的应用: SHA-256 是许多安全协议和算法的基础,包括 TLS/SSL、PGP、SSH 等。

  • 快速计算: SHA-256 是一种相对快速的哈希算法,它可以在短时间内计算出大文件的哈希值。

  • 标准化: SHA-256 是由 National Institute of Standards and Technology(NIST)标准化的哈希算法之一,这意味着它已经被广泛接受,并且是许多安全协议和应用程序中的标准。

如何在 Web 中使用 SHA-256

通过 Web Crypto API,我们可以在浏览器中使用 SHA-256 算法。Web Crypto API 是一个 JavaScript API,它提供了加密和解密数据的功能。它提供了一组用于执行加密操作的接口,包括哈希函数、对称加密、非对称加密、消息认证码、数字签名等。

Web Crypto API 的 SubtleCrypto 接口提供了许多底层加密函数。

方法 描述
decrypt() 用于解密加密数据。
deriveBits() 用于从一个基本密钥派生比特序列(数组)。
deriveKey() 用于从主密钥派生密钥。
digest() 生成给定数据的摘要。摘要是从一些可变长的输入生成的短且具有固定长度的值。密码摘要应表现出抗冲突性,这意味着很难构造出具有相同摘要值的两个不同的输入。
encrypt() 用于加密数据。
exportKey() 用于导出密钥。
generateKey() 用于生成新的密钥(用于对称加密算法)或密钥对(用于非对称加密算法)。
importKey() 用于导入密钥:也就是说,它以外部可移植格式的密钥作为输入,并给出对应的、可用于 Web Crypto API 的 CryptoKey 对象。
sign() 用于生成数字签名。
unwrapKey() “解开密钥的包装”。这意味着它将一个已导出且加密(也被称为“包装”)的密钥作为输入。它会解密这个密钥然后导入它,返回一个可用于 Web Crypto API 的 CryptoKey 对象。
verify() 用于验证数字签名。
wrapKey() 用于“包装”(wrap)密钥。这一味着它以外部可移植的格式导出密钥,然后对其进行加密。包装密钥有助于在不受信任的环境中保护它,例如在未受保护的数据存储,或在未受保护的网络上进行传输。

使用 Web Crypto API 计算文件的 SHA-256 哈希值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
async function calculateSHA256ByChunks(file: File, chunkSize: number = 1024 * 1024): Promise<string> {
const hashArray = new Uint8Array(await crypto.subtle.digest("SHA-256", new Uint8Array(0)));

return new Promise<string>((resolve, reject) => {
const fileReader = new FileReader();
let offset = 0;

fileReader.onload = async function () {
const chunkBuffer = fileReader.result as ArrayBuffer;

// 指定算法为 SHA-256
await crypto.subtle.digest("SHA-256", chunkBuffer).then(async function (chunkHashBuffer) {
// 将每个块的哈希更新到总的哈希中
const newHashArray = new Uint8Array(hashArray.length + chunkHashBuffer.byteLength);
newHashArray.set(hashArray, 0);
newHashArray.set(new Uint8Array(chunkHashBuffer), hashArray.length);

// 使用 subarray 确保不越界
hashArray.set(newHashArray.subarray(0, hashArray.length));

// 继续读取下一个块
offset += chunkSize;
if (offset < file.size) {
readChunk();
} else {
// 完成后将总的哈希值返回
const hashHex = Array.from(hashArray)
.map((byte) => byte.toString(16).padStart(2, "0"))
.join("");
resolve(hashHex);
}
});
};

fileReader.onerror = function (event) {
reject(event.target?.error);
};

function readChunk() {
const chunk = file.slice(offset, offset + chunkSize);
fileReader.readAsArrayBuffer(chunk);
}

readChunk();
});
}

目前遇到的使用场景

  1. Web 中大文件分片上传通常与秒传、断点续传搭配使用,秒传和断点续传都需要校验文件的完整性,而 sha256 可以很好的完成这个任务。

作者

1uciuszzz

发布于

2023-12-06

更新于

2023-12-06

许可协议

评论