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

如何在TypeScript中实现RSA-OAEP稳定加密(固定密文)

如何在TypeScript的RSA-OAEP加密中生成稳定密文?

问题背景

我需要实现同一明文每次加密生成固定密文的效果(比如加密“sai”始终得到相同结果),已经在Go语言中通过自定义随机读取器实现了该功能:

randomFunc := func(b []byte) (n int, err error) {
    // 如果提供seed,用它生成固定的伪随机数
    if seed != "" {
        h := hmac.New(sha256.New, []byte(seed))
        if _, err := h.Write(b); err != nil {
            return 0, err
        }
        copy(b, h.Sum(nil))
        return len(b), nil
    }
    // 无seed时使用标准随机源
    return rand.Read(b)
}

ciphertext, err := rsa.EncryptOAEP(
    sha256.New(),
    SecureRandomReader{randomFunc},
    publicKey,
    plaintext,
    labelBytes,
)

当明文为“sai”、labelBytes为“label”、seed为“seed”时,每次生成的密文完全一致。

但在TypeScript中使用node-forge库实现时,每次加密结果都不同:

const sha256 = forge.md.sha256.create()
sha256.update(seed)
if (seed) {
    const ciphertextBuffer = publicKey.encrypt(forge.util.encodeUtf8(toBeEncrypted), 'RSA-OAEP', {
        md: sha256,
        mgf1: {
          md: sha256,
        },
        label: labelBytes,
    })
    ciphertextBase64 = forge.util.encode64(ciphertextBuffer)
}

我不在意安全性,只想实现稳定密文的生成,请问如何控制TypeScript中的随机化?


解决方案:替换forge的随机数生成器

RSA-OAEP加密的随机性来自于填充过程中生成的随机掩码,要生成固定密文,需要将随机源替换为基于固定seed的伪随机生成器,和Go端逻辑对齐。

步骤1:实现固定伪随机字节生成函数

import * as forge from 'node-forge';

// 生成与seed绑定的固定伪随机字节函数,逻辑对齐Go端的HMAC-SHA256实现
function createFixedRandomGenerator(seed: string) {
  let counter = 0;
  return function(bytesNeeded: number): forge.util.ByteStringBuffer {
    const hmac = forge.hmac.create();
    hmac.start('sha256', forge.util.encodeUtf8(seed));
    // 用计数器递增确保每次生成的字节序列连续且固定
    hmac.update(forge.util.encodeUtf8(counter.toString()));
    counter++;
    const hash = hmac.digest().getBytes();
    
    // 若需要的字节数超过哈希长度,重复拼接哈希值(按需扩展)
    let result = '';
    while (result.length < bytesNeeded) {
      result += hash;
    }
    return forge.util.createBuffer(result.slice(0, bytesNeeded));
  };
}

步骤2:加密时替换随机生成器

function encryptFixed(
  publicKey: forge.pki.PublicKey,
  plaintext: string,
  label: string,
  seed: string
): string {
  const sha256 = forge.md.sha256.create();
  // 保存原随机生成器,避免影响其他逻辑
  const originalRandom = forge.random.getBytes;
  
  try {
    // 替换为自定义固定随机生成器
    forge.random.getBytes = createFixedRandomGenerator(seed);
    
    const ciphertextBuffer = publicKey.encrypt(
      forge.util.encodeUtf8(plaintext),
      'RSA-OAEP',
      {
        md: sha256,
        mgf1: { md: sha256 },
        label: forge.util.encodeUtf8(label), // 确保label编码与Go端一致
      }
    );
    return forge.util.encode64(ciphertextBuffer);
  } finally {
    // 恢复原随机生成器
    forge.random.getBytes = originalRandom;
  }
}

关键注意事项

  • 确保所有参数与Go端完全对齐:明文编码(UTF-8)、label编码、哈希算法(SHA256)、MGF1参数,否则即使随机源固定,密文也可能不一致。
  • 仅在需要固定密文的加密场景中临时替换随机生成器,加密完成后立即恢复,避免影响其他需要真随机的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:57:04