JS如何实现密码的哈希转换

136 阅读3分钟

一 window.crypto来实现密码的哈希转换

在浏览器环境中,使用window.crypto对象结合SubtleCrypto接口来实现密码的哈希转换,通常会使用PBKDF2(Password-Based Key Derivation Function 2)算法,它是一种通过多次迭代来增加破解难度的密码哈希方法。以下是一个示例代码


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Password Hashing</title>
</head>

<body>
  <script>
    // 待哈希的密码
    const password = "mysecretpassword";
    // 生成盐值,这里使用16字节的随机值
    const salt = new Uint8Array(crypto.getRandomValues(new Uint8Array(16)));
    // 迭代次数,一般设置较大的值增加安全性
    const iterations = 100000;
    // 期望生成的密钥长度(以比特为单位),这里设置为256比特即32字节
    const keyLength = 256;

    async function hashPassword() {
      try {
        // 将密码字符串转换为Uint8Array
        const encoder = new TextEncoder();
        const passwordData = encoder.encode(password);

        // 导入密码密钥
        const passwordKey = await window.crypto.subtle.importKey(
          "raw",
          passwordData,
          { name: "PBKDF2" },
          false,
          ["deriveBits"]
        );

        // 派生密钥
        const derivedKey = await window.crypto.subtle.deriveBits(
          {
            name: "PBKDF2",
            salt: salt,
            iterations: iterations,
            hash: { name: "SHA-256" }
          },
          passwordKey,
          keyLength
        );

        // 将派生的密钥转换为十六进制字符串
        const hashArray = Array.from(new Uint8Array(derivedKey));
        const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');

        console.log("Salt:", Array.from(salt).map(b => b.toString(16).padStart(2, '0')).join(''));
        console.log("Hashed Password:", hashHex);
      } catch (error) {
        console.error("Error hashing password:", error);
      }
    }

    hashPassword();
  </script>
</body>

</html>

在上述代码中:

  1. 首先定义了密码、盐值、迭代次数和密钥长度等参数。

  2. hashPassword函数将密码转换为Uint8Array,并使用subtle.importKey导入密码密钥。

  3. 然后通过subtle.deriveBits方法基于PBKDF2算法和设置的参数派生密钥。

  4. 最后将派生的密钥转换为十六进制字符串进行展示,同时也展示了生成的盐值。

二 使用crypto模块实现密码的哈希转换

在Node.js环境中,crypto模块提供了丰富的加密功能,使用它实现密码哈希转换,常见的是采用pbkdf2算法,这是一种基于密码的密钥派生函数,通过多次迭代来增加安全性。以下是示例代码:

const crypto = require('crypto');

// 待哈希的密码
const password = 'your_password_here';
// 生成随机盐值,建议盐值长度足够长以增强安全性
const salt = crypto.randomBytes(16).toString('hex');
// 迭代次数,通常设置较大的值来增加破解难度,这里设置为100000次
const iterations = 100000;
// 生成密钥的长度(以字节为单位),这里设置为64字节
const keylen = 64;
// 哈希算法,这里使用SHA256
const digest ='sha256';

// 使用pbkdf2Sync方法进行同步哈希计算
const hashedPassword = crypto.pbkdf2Sync(password, salt, iterations, keylen, digest).toString('hex');

console.log('盐值(Salt):', salt);
console.log('哈希后的密码(Hashed Password):', hashedPassword);

上述代码中:

  1. 首先引入crypto模块。

  2. 定义了要哈希的密码,生成随机盐值,设置迭代次数、生成密钥长度和哈希算法。

  3. 然后调用crypto.pbkdf2Sync方法,传入密码、盐值、迭代次数、密钥长度和哈希算法,得到哈希后的密码。

  4. 最后打印出盐值和哈希后的密码。

在实际应用中,将盐值和哈希后的密码存储起来,当用户登录验证时,使用相同的盐值和算法对用户输入的密码进行哈希,再对比哈希值是否一致。