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

PowerShell加密后用node-forge解密报错:Encrypted message length is invalid

PowerShell RSA-OAEP加密后用node-forge解密报“Encrypted message length is invalid”的解决办法

问题重现

用PowerShell执行非对称加密后,通过Node.js的node-forge库解密时触发错误:

Error: Encrypted message length is invalid.

PowerShell加密代码

function Encrypt-Asymmetric {
    [CmdletBinding()]
    [OutputType([System.String])]
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $ClearText,

        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-Path $_ -PathType Leaf })]
        [System.String]
        $PublicKeyFilePath,

        [Parameter(Position=2)]
        [System.String]
        $OutputFilePath
    )

    $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider
    $rsa.ImportSubjectPublicKeyInfo((Get-Content $PublicKeyFilePath -Raw))

    $encryptedBytes = $rsa.Encrypt([System.Text.Encoding]::UTF8.GetBytes($ClearText), $true)
    $encryptedBase64String = [System.Convert]::ToBase64String($encryptedBytes)

    if ($OutputFilePath) {
        $encryptedBase64String | Set-Content -Path $OutputFilePath
    }

    return $encryptedBase64String
}

$clearText = "thisisasecret"
$publicKeyFilePath = "public1.pem"
$outputFilePath = "encrypted.txt"

$encryptedString = Encrypt-Asymmetric -ClearText $clearText -PublicKeyFilePath $publicKeyFilePath -OutputFilePath $outputFilePath
Write-Output "Encrypted: $encryptedString"

Node.js解密代码

const forge = require('node-forge');
const fs = require('fs');

function decryptAsymmetric(encryptedString, privateKeyFilePath) {
    const privateKeyPem = fs.readFileSync(privateKeyFilePath, 'utf8');
    const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);

    const encryptedBytes = forge.util.decode64(encryptedString);
    const decryptedBytes = privateKey.decrypt(encryptedBytes, 'RSA-OAEP', {
        md: forge.md.sha256.create(),
        mgf1: {
            md: forge.md.sha256.create()
        }
    });

    return decryptedBytes.toString();
}

const encryptedString =
    "IdnKfQ3tPZH/5AdYbqhsMzvRbW6/VQgGjvmJYtuQz/VT5nxlfVIDVTXKayIMDhnCtLvprODAOFg5GBhPUwEUtzuO4H7T6wzPu84Pnev4UyNC/w0cmnPBixwRggyVQpOvso1rKeTfD5wNcSTtQ4KIaQScSUC/+U5oAldhbjI5S1Y="
    //fs.readFileSync('encrypted.txt', 'utf8')

const privateKeyFilePath = 'private1.key';

const decryptedText = decryptAsymmetric(encryptedString, privateKeyFilePath);
console.log('Decrypted:', decryptedText);

问题原因

核心问题是加密和解密使用的OAEP哈希算法不匹配:

  • PowerShell中使用RSACryptoServiceProvider.Encrypt(..., $true)时,默认采用SHA-1作为OAEP的哈希算法和MGF1的哈希算法
  • Node.js代码中明确指定了SHA-256作为哈希,两边算法不一致导致解密时无法正确解析密文,触发长度错误

另外,手动复制密文时若引入换行、空格或截断,也可能导致密文长度异常,但从提供的代码来看,主要问题还是算法不匹配。

解决方案

方案1:Node.js端改用SHA-1(快速验证,不推荐生产环境)

修改node-forge的解密代码,将哈希算法改为SHA-1,与PowerShell端默认值匹配:

const decryptedBytes = privateKey.decrypt(encryptedBytes, 'RSA-OAEP', {
    md: forge.md.sha1.create(),
    mgf1: {
        md: forge.md.sha1.create()
    }
});

方案2:PowerShell端改用SHA-256(推荐,更安全)

由于RSACryptoServiceProvider不支持自定义OAEP哈希算法,需改用RSACng类实现SHA-256的OAEP加密:

function Encrypt-Asymmetric {
    [CmdletBinding()]
    [OutputType([System.String])]
    param(
        [Parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [System.String]
        $ClearText,

        [Parameter(Position=1, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-Path $_ -PathType Leaf })]
        [System.String]
        $PublicKeyFilePath,

        [Parameter(Position=2)]
        [System.String]
        $OutputFilePath
    )

    # 使用RSACng替代RSACryptoServiceProvider,支持自定义OAEP哈希
    $rsa = New-Object System.Security.Cryptography.RSACng
    $rsa.ImportSubjectPublicKeyInfo((Get-Content $PublicKeyFilePath -Raw))

    # 指定OAEP填充,哈希算法用SHA-256
    $encryptedBytes = $rsa.Encrypt([System.Text.Encoding]::UTF8.GetBytes($ClearText), [System.Security.Cryptography.RSAEncryptionPadding]::OaepSHA256)
    $encryptedBase64String = [System.Convert]::ToBase64String($encryptedBytes)

    if ($OutputFilePath) {
        $encryptedBase64String | Set-Content -Path $OutputFilePath
    }

    return $encryptedBase64String
}

$clearText = "thisisasecret"
$publicKeyFilePath = "public1.pem"
$outputFilePath = "encrypted.txt"

$encryptedString = Encrypt-Asymmetric -ClearText $clearText -PublicKeyFilePath $publicKeyFilePath -OutputFilePath $outputFilePath
Write-Output "Encrypted: $encryptedString"

修改后,Node.js端原有使用SHA-256的代码即可正常解密。

额外注意事项

  1. 确保公私钥对匹配:加密用公钥必须和解密用私钥属于同一密钥对
  2. 避免手动复制密文:建议直接读取文件内容,防止引入多余格式字符
  3. 生产环境优先使用SHA-256及以上哈希算法,规避SHA-1的安全风险

内容的提问来源于stack exchange,提问作者AVS Kasturi Karthik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:53:14