You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求纯JavaScript环境下的密码学安全DRNG方案

原生JavaScript实现密码学安全确定性随机数生成器(HMAC_DRBG)

核心方案:基于Web Crypto的HMAC_DRBG

HMAC_DRBG是NIST标准化的密码学安全确定性随机数生成器,完全可以通过Web Crypto API原生实现,不需要额外依赖。它能满足你的需求:只要共享种子一致,多客户端就能生成完全相同的输出,且具备密码学安全性。

实现思路

利用Web Crypto提供的HMAC算法实现HMAC_DRBG的核心逻辑,遵循NIST SP 800-90A规范的基本流程:

  1. 初始化:用安全共享的种子初始化HMAC_DRBG的状态。
  2. 生成:通过HMAC迭代生成所需长度的随机字节序列。
  3. 结合Web Crypto的deriveKey:将生成的随机字节作为密钥材料,导入为AES密钥,或直接作为deriveKey的输入派生密钥。

原生实现代码

class HMACDRBG {
  /**
   * 初始化HMAC_DRBG
   * @param {ArrayBuffer} seed 共享种子(至少32字节,推荐对应SHA-256长度)
   * @param {string} hashAlgorithm 哈希算法,默认SHA-256
   */
  constructor(seed, hashAlgorithm = 'SHA-256') {
    this.hashAlgorithm = hashAlgorithm;
    this.seed = seed;
    this.state = null;
    this.reseedCounter = 1;
    this._initialize();
  }

  async _initialize() {
    // 初始化HMAC密钥
    const hmacKey = await crypto.subtle.importKey(
      'raw',
      this.seed,
      { name: 'HMAC', hash: this.hashAlgorithm },
      false,
      ['sign']
    );

    // 生成初始状态:V = 0x01重复哈希长度次,K = HMAC(K, V || 0x00 || seed)
    const hashLength = this.hashAlgorithm === 'SHA-256' ? 32 : 64; // SHA-512对应64字节
    const V = new Uint8Array(hashLength).fill(0x01);
    const temp = new Uint8Array([...V, 0x00, ...new Uint8Array(this.seed)]);
    
    const K = await crypto.subtle.sign('HMAC', hmacKey, temp);
    this.state = { K, V };
  }

  /**
   * 生成指定长度的随机字节
   * @param {number} length 需要生成的字节数(单次最大1024,超过自动分批次)
   * @returns {Promise<ArrayBuffer>} 生成的随机字节
   */
  async generate(length) {
    if (length > 1024) {
      const chunks = [];
      let remaining = length;
      while (remaining > 0) {
        const chunkSize = Math.min(remaining, 1024);
        chunks.push(await this._generateChunk(chunkSize));
        remaining -= chunkSize;
      }
      return this._concatArrayBuffers(chunks);
    }
    return this._generateChunk(length);
  }

  async _generateChunk(length) {
    const { K, V } = this.state;
    const hashLength = this.hashAlgorithm === 'SHA-256' ? 32 : 64;
    const outputChunks = [];
    let totalBytes = 0;

    // 生成足够的输出字节
    while (totalBytes < length) {
      // V = HMAC(K, V)
      const newV = await crypto.subtle.sign('HMAC', await this._getHMACKey(K), V);
      outputChunks.push(newV);
      totalBytes += hashLength;
      this.state.V = newV;
    }

    // 截取需要的长度
    const fullOutput = this._concatArrayBuffers(outputChunks);
    const truncatedOutput = fullOutput.slice(0, length);

    // 更新状态:K = HMAC(K, V || 0x01)
    const temp = new Uint8Array([...new Uint8Array(this.state.V), 0x01]);
    const newK = await crypto.subtle.sign('HMAC', await this._getHMACKey(K), temp);
    this.state.K = newK;
    this.reseedCounter += 1;

    return truncatedOutput;
  }

  async _getHMACKey(keyData) {
    return crypto.subtle.importKey(
      'raw',
      keyData,
      { name: 'HMAC', hash: this.hashAlgorithm },
      false,
      ['sign']
    );
  }

  _concatArrayBuffers(buffers) {
    const totalLength = buffers.reduce((sum, buf) => sum + buf.byteLength, 0);
    const result = new Uint8Array(totalLength);
    let offset = 0;
    for (const buf of buffers) {
      result.set(new Uint8Array(buf), offset);
      offset += buf.byteLength;
    }
    return result.buffer;
  }
}

// 使用示例1:直接生成共享AES密钥
async function generateSharedAESKey(sharedSeed) {
  // 初始化DRBG(种子需安全共享,至少32字节)
  const drbg = new HMACDRBG(sharedSeed);
  // 生成AES-256所需的32字节密钥材料
  const keyMaterial = await drbg.generate(32);
  // 导入为可用于加密解密的AES密钥
  const aesKey = await crypto.subtle.importKey(
    'raw',
    keyMaterial,
    { name: 'AES-GCM' },
    true,
    ['encrypt', 'decrypt']
  );
  return aesKey;
}

// 使用示例2:结合deriveKey派生AES密钥
async function deriveAESKeyFromDRBG(sharedSeed, salt) {
  const drbg = new HMACDRBG(sharedSeed);
  const derivedInput = await drbg.generate(32);
  const aesKey = await crypto.subtle.deriveKey(
    {
      name: 'PBKDF2',
      salt: salt,
      iterations: 100000,
      hash: 'SHA-256'
    },
    await crypto.subtle.importKey('raw', derivedInput, { name: 'PBKDF2' }, false, ['deriveKey']),
    { name: 'AES-GCM', length: 256 },
    true,
    ['encrypt', 'decrypt']
  );
  return aesKey;
}

关键注意事项

  • 种子安全性:必须通过安全信道(如TLS加密API、端到端加密)传输共享种子,种子长度至少32字节,避免使用弱种子。
  • 算法选择:示例中使用SHA-256,若需更高安全性可改用SHA-512,只需调整代码中的哈希长度参数。
  • 兼容性:所有主流浏览器(Chrome、Firefox、Safari)和Node.js(需启用Web Crypto)都支持该实现,无需额外依赖。
  • 合规性:HMAC_DRBG符合NIST SP 800-90A标准,满足密码学安全要求,适合生成密钥材料。

内容的提问来源于stack exchange,提问作者Randusr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 07:55:19