JS `Web Cryptography API`:浏览器端加密与哈希操作

嘿,大家好!咱们今天聊聊浏览器里的“密码箱”—— Web Cryptography API,看看它怎么帮我们安全地玩转加密和哈希。准备好了吗?Let’s go!

Web Cryptography API 是个啥?

简单来说,Web Cryptography API (简称 Web Crypto API) 是浏览器提供的一套 JavaScript 接口,让开发者可以在客户端(也就是用户的浏览器里)执行各种加密操作,比如生成密钥、加密解密数据、计算哈希值等等。听起来是不是很酷?

为什么要用它?

  • 安全第一: 相比于把敏感数据直接明文传输,或者依赖服务器端加密,Web Crypto API 允许我们在浏览器端进行加密,这样即使数据在传输过程中被截获,攻击者看到的也是一堆乱码。
  • 减轻服务器压力: 某些加密解密操作可以在客户端完成,可以有效降低服务器的计算负担。
  • 离线也能用: 某些情况下,如果需要离线进行数据加密,Web Crypto API 也能派上用场。

Web Crypto API 核心概念

在使用 Web Crypto API 之前,我们需要了解几个关键的概念:

  • crypto 对象: 这是 Web Crypto API 的入口点,通过 window.crypto 可以访问。
  • SubtleCrypto 接口: crypto.subtle 返回一个 SubtleCrypto 对象,它提供了加密、解密、签名、验证等各种底层加密操作的方法。
  • CryptoKey 接口: 代表一个加密密钥,可以是公钥、私钥或对称密钥。
  • 算法 (Algorithms): Web Crypto API 支持多种加密算法,比如 AES, RSA, SHA 等等。每种算法都有自己的参数和用法。

Web Crypto API 支持的算法

Web Crypto API 支持多种对称和非对称加密算法,以及哈希算法。 常见的算法包括:

算法类型 算法名称 描述
对称加密 AES-CBC 高级加密标准,使用密码块链接模式。
AES-CTR 高级加密标准,使用计数器模式。
AES-GCM 高级加密标准,使用伽罗瓦/计数器模式。 这是最常用的对称加密方式,通常也是最安全的。
AES-KW AES 密钥封装,用于安全地封装(加密)密钥。
非对称加密 RSA-OAEP RSA 加密算法,使用最优非对称加密填充 (OAEP) 模式。
RSA-PSS RSA 签名算法,使用概率签名方案 (PSS)。
RSA-PKCS1-v1_5 RSA 加密和签名算法,使用 PKCS#1 v1.5 填充模式。 现在已经很少使用了,安全性有待考量。
ECDSA 椭圆曲线数字签名算法。
ECDH 椭圆曲线 Diffie-Hellman 密钥交换算法。
哈希算法 SHA-1 安全哈希算法 1。 已经被认为是不安全的,不推荐使用。
SHA-256 安全哈希算法 256 位。 推荐使用。
SHA-384 安全哈希算法 384 位。 推荐使用。
SHA-512 安全哈希算法 512 位。 推荐使用。
HMAC 密钥哈希消息认证码。

Web Crypto API 实战:AES-GCM 加密解密

咱们来一个实际的例子,用 AES-GCM 算法来加密和解密数据。AES-GCM 是一种常用的对称加密算法,安全性较高。

1. 生成密钥 (generateKey)

首先,我们需要生成一个 AES 密钥。

async function generateAESKey() {
  return await window.crypto.subtle.generateKey(
    {
      name: "AES-GCM",
      length: 256, // 可以是 128, 192, 或 256
    },
    true, // 是否可提取密钥
    ["encrypt", "decrypt"] // 密钥的用途
  );
}

这段代码会生成一个 256 位的 AES 密钥,并且允许我们用它来加密和解密数据。

2. 加密 (encrypt)

async function encrypt(key, data) {
  const iv = window.crypto.getRandomValues(new Uint8Array(12)); // 初始化向量,长度必须是 12 字节
  const encodedData = new TextEncoder().encode(data); // 将字符串转换为 Uint8Array

  const ciphertext = await window.crypto.subtle.encrypt(
    {
      name: "AES-GCM",
      iv: iv,
    },
    key,
    encodedData
  );

  return {
    iv: iv,
    ciphertext: new Uint8Array(ciphertext),
  };
}

这里我们做了几件事:

  • 生成一个随机的初始化向量 (IV)。IV 用于增加加密的随机性,防止同样的明文被加密成同样的密文。对于 AES-GCM 来说,IV 的长度必须是 12 字节。
  • 将要加密的数据(字符串)转换成 Uint8Array
  • 使用 crypto.subtle.encrypt() 方法进行加密。
  • 返回 IV 和密文。

3. 解密 (decrypt)

async function decrypt(key, iv, ciphertext) {
  const decryptedData = await window.crypto.subtle.decrypt(
    {
      name: "AES-GCM",
      iv: iv,
    },
    key,
    ciphertext
  );

  const decodedData = new TextDecoder().decode(decryptedData); // 将 Uint8Array 转换为字符串
  return decodedData;
}

解密过程与加密类似,需要提供密钥、IV 和密文。解密后,我们需要将 Uint8Array 转换回字符串。

4. 完整示例

async function aesGcmExample(data) {
  const key = await generateAESKey();
  const { iv, ciphertext } = await encrypt(key, data);
  const decryptedData = await decrypt(key, iv, ciphertext);

  console.log("原始数据:", data);
  console.log("密文:", ciphertext);
  console.log("解密后的数据:", decryptedData);

  if (data === decryptedData) {
    console.log("加密解密成功!");
  } else {
    console.error("加密解密失败!");
  }
}

// 调用示例
aesGcmExample("Hello, Web Crypto API!");

运行这段代码,你会在控制台看到原始数据、密文和解密后的数据。如果一切顺利,你会看到“加密解密成功!”的消息。

Web Crypto API 实战:RSA-OAEP 加密解密

接下来,我们来看一个非对称加密的例子,使用 RSA-OAEP 算法。RSA 是一种常用的非对称加密算法,它使用公钥加密,私钥解密。

1. 生成密钥对 (generateKey)

async function generateRSAKeyPair() {
  return await window.crypto.subtle.generateKey(
    {
      name: "RSA-OAEP",
      modulusLength: 2048, // 密钥长度,通常是 2048 或 4096
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 固定值
      hash: "SHA-256", // 使用 SHA-256 哈希算法
    },
    true, // 是否可提取密钥
    ["encrypt", "decrypt"] // 密钥的用途
  );
}

这段代码会生成一个 RSA 密钥对,包括一个公钥和一个私钥。modulusLength 指定密钥的长度,通常是 2048 或 4096 位。

2. 加密 (encrypt)

async function rsaEncrypt(publicKey, data) {
  const encodedData = new TextEncoder().encode(data);

  const ciphertext = await window.crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
    },
    publicKey,
    encodedData
  );

  return new Uint8Array(ciphertext);
}

使用公钥加密数据。

3. 解密 (decrypt)

async function rsaDecrypt(privateKey, ciphertext) {
  const decryptedData = await window.crypto.subtle.decrypt(
    {
      name: "RSA-OAEP",
    },
    privateKey,
    ciphertext
  );

  const decodedData = new TextDecoder().decode(decryptedData);
  return decodedData;
}

使用私钥解密数据。

4. 完整示例

async function rsaOaepExample(data) {
  const { publicKey, privateKey } = await generateRSAKeyPair();
  const ciphertext = await rsaEncrypt(publicKey, data);
  const decryptedData = await rsaDecrypt(privateKey, ciphertext);

  console.log("原始数据:", data);
  console.log("密文:", ciphertext);
  console.log("解密后的数据:", decryptedData);

  if (data === decryptedData) {
    console.log("加密解密成功!");
  } else {
    console.error("加密解密失败!");
  }
}

// 调用示例
rsaOaepExample("Hello, RSA-OAEP!");

运行这段代码,你会看到 RSA 加密解密的结果。

Web Crypto API 实战:哈希 (Hashing)

除了加密解密,Web Crypto API 还可以用来计算哈希值。哈希是一种单向函数,可以将任意长度的数据转换成固定长度的哈希值。哈希值通常用于验证数据的完整性。

async function calculateHash(algorithm, data) {
  const encodedData = new TextEncoder().encode(data);
  const hashBuffer = await window.crypto.subtle.digest(algorithm, encodedData);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const hashHex = hashArray
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
  return hashHex;
}

async function hashExample(data) {
  const sha256Hash = await calculateHash("SHA-256", data);
  const sha512Hash = await calculateHash("SHA-512", data);

  console.log("原始数据:", data);
  console.log("SHA-256 哈希值:", sha256Hash);
  console.log("SHA-512 哈希值:", sha512Hash);
}

// 调用示例
hashExample("Hello, Hashing!");

这段代码会计算数据的 SHA-256 和 SHA-512 哈希值,并将结果以十六进制字符串的形式输出。

密钥的存储

密钥的存储是个大问题!直接把密钥写在代码里肯定是不行的。Web Crypto API 提供了 exportKeyimportKey 方法,可以将密钥导出成不同的格式(比如 jwkraw),然后存储在安全的地方(比如浏览器的 IndexedDB),或者传输到服务器端。

注意事项

  • 不要自己发明轮子: Web Crypto API 提供了标准的加密算法,尽量使用这些算法,不要试图自己设计加密算法。
  • 随机数很重要: 加密过程中需要使用随机数,Web Crypto API 提供了 window.crypto.getRandomValues() 方法来生成高质量的随机数。
  • 密钥管理是关键: 密钥的存储和管理非常重要,一定要采取安全措施,防止密钥泄露。
  • HTTPS 是基础: 使用 Web Crypto API 的网站必须使用 HTTPS 协议,否则可能会受到中间人攻击。
  • 算法选择: 根据实际需求选择合适的加密算法。AES-GCM 通常用于对称加密,RSA-OAEP 用于非对称加密。SHA-256 和 SHA-512 是常用的哈希算法。
  • 错误处理: 加密解密过程中可能会出现错误,比如密钥无效、数据损坏等等。一定要做好错误处理,防止程序崩溃。
  • 不要存储用户的密码 使用bcrypt之类的专门hash密码的方案,web crypto api提供的加密方案不适合直接加密密码。

总结

Web Cryptography API 为我们提供了一套强大的工具,可以在浏览器端进行各种加密和哈希操作。但同时也要注意安全问题,正确地使用这些 API,才能真正保护用户的数据安全。

希望今天的讲解对大家有所帮助!如果有什么问题,欢迎随时提问。下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注