NodeJS实现Bitnami Sealed Secrets解密遇RSA-OAEP填充错误求助
解决Sealed Secret解密时的
Invalid RSAES-OAEP padding错误 以下是导致错误的关键问题及修正方案:
问题分析
- 数据拆分错误:截取AES加密数据时错误地减去了1字节,导致后续RSA解密的输入数据错位或不完整
- Label参数类型不兼容:node-forge的RSA-OAEP解密不接受Node.js原生Buffer作为
label参数,需要转换为forge兼容格式 - AES会话密钥处理错误:RSA解密得到的会话密钥是原始二进制字节,不需要额外转十六进制
- AES-GCM数据拆分遗漏标签:Bitnami的AES-256-GCM加密结果包含IV、密文和认证标签,未处理标签会导致解密失败
修正后的代码
import * as fs from 'fs'; import * as forge from 'node-forge'; // 加载私钥 const privateKeyPEM = fs.readFileSync('priv.key', 'utf8'); const privateKey = forge.pki.privateKeyFromPem(privateKeyPEM); // Sealed Secret原始数据 const sealedSecretData = Buffer.from( 'AgAdMSMYznQfAavqvsmqVnjnZYnaPHyrLoxsj6Qg5uoH0yWgkgea9ipMgl2CAXaatUxsz4Qx3ULM6GyRmOvTP47ETt0h3rALxK47lXdoDq3z9937/2rln2uMaGhCyyTQ0m7G3F0Rj3J5NRFnuuVhYZit/v6vrXHKqAHTuG0AxIA/nuN0o3nFN7+MmBs3RTXPII+6CYYmho3ldZwimyQKrBkbbZpRjFnmvv2ErGFQg9lz63QxzTqE5EPvrz0DIwGFUxJKKZ2fOucVcXavEkZJUflKFnK58d/ur90GPQp/N5Ivmqj+1Lf7L5ezqAP5WpmK0M2q69D6RG+OUoOgpYLNQJybL4nxqgv4lFu0eXHxBwqjmNUOqkFDAd5APS1CDaFNjcw5dJ009jqeUN+4AxM2WtfzjjQz6rf5M5UmGMDCc26mjx3fOvi8AAIvEJ6B/hJcRwnC0zqsK0apJ00VykRyHsOTK8G6/eFy8wFnvx4neBCNKgQAMMq0F8A5ekWVZg7sxdeUucc2KXHc53c/p+tOcf0eMBCwefM7ijcoc85x+0wr+wigJ71BakjCGZfQDlnnfOGf9ayp4EhpiPfUdNQ8k1A3G45dE8wJdrUtvn4Qoootevhb9acWM3rKjFstDj3FB8epCct85Fnu5y8QGqWPfUTiprSNWAc+1zejXtZULSWal2cf66kniG+hjjAeEU8l2unncQj+0mf/', 'base64' ); // 正确拆分Sealed Secret数据 const aesKeySize = sealedSecretData.readUIntBE(0, 2); const rsaEncryptedData = sealedSecretData.slice(2, 2 + aesKeySize); // 移除错误的length-1截断,取完整剩余数据作为AES加密结果 const aesEncryptedData = sealedSecretData.slice(2 + aesKeySize); // 转换Label为forge兼容的Buffer格式 const label = forge.util.createBuffer('kube-systemsealed-secrets-keyfc5ht', 'utf8'); // 解密RSA加密数据获取AES会话密钥 const rsaEncryptedBytes = forge.util.createBuffer(rsaEncryptedData.toString('binary')); const aesSessionKey = privateKey.decrypt(rsaEncryptedBytes.getBytes(), 'RSA-OAEP', { md: forge.md.sha256.create(), label, }); // 拆分AES-GCM的IV、密文和认证标签(GCM标准标签长度为16字节) const iv = aesEncryptedData.slice(0, 16); const ciphertext = aesEncryptedData.slice(16, -16); const tag = aesEncryptedData.slice(-16); // 解密AES-GCM数据 const aesDecipher = forge.cipher.createDecipher('AES-GCM', aesSessionKey); aesDecipher.start({ iv: forge.util.createBuffer(iv.toString('binary')), tag: forge.util.createBuffer(tag.toString('binary')), // 传入认证标签用于完整性验证 }); aesDecipher.update(forge.util.createBuffer(ciphertext.toString('binary'))); const decryptSuccess = aesDecipher.finish(); if (decryptSuccess) { const decryptedSecretData = aesDecipher.output.toString('utf8'); console.log('解密成功:', decryptedSecretData); } else { console.error('AES-GCM解密失败,可能是数据篡改或密钥不匹配'); }
关键改动说明
- 数据拆分修正:删除
sealedSecretData.length - 1的错误截断,确保AES加密数据完整 - Label格式修正:用forge的Buffer包装label字符串,符合RSA-OAEP解密的参数要求
- 会话密钥处理:直接使用RSA解密后的原始字节作为AES密钥,移除多余的
hexToBytes转换 - AES-GCM标签处理:明确拆分并传入认证标签,保证GCM解密的完整性验证通过
内容的提问来源于stack exchange,提问作者Saad Belkhou
相关产品推荐
相关产品推荐

