如何在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
相关产品推荐
相关产品推荐

