如何用PowerShell生成与OpenSSL兼容的加密RSA私钥?
问题:PowerShell生成OpenSSL兼容加密私钥遇ASN1错误,无ExportRSAPrivateKey()可用,能否实现转换?
我尝试使用Stack Overflow用户Topaco提供的代码,在PowerShell中生成与OpenSSL格式一致的加密私钥,但运行时出现以下ASN1编码错误:
6788:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:./crypto/asn1/tasn_dec.c:1294: 6788:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:./crypto/asn1/tasn_dec.c:830: 6788:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:./crypto/asn1/tasn_dec.c:749:Field=n, Type=RSA 6788:error:0D09A00D:asn1 encoding routines:d2i_PrivateKey:ASN1 lib:./crypto/asn1/d2i_pr.c:99: 6788:error:0907B00D:PEM routines:PEM_READ_BIO_PRIVATEKEY:ASN1 lib:./crypto/pem/pem_pkey.c:125:
同时我无法使用ExportRSAPrivateKey()函数。我已从PFX格式证书中导出非加密RSA私钥(格式为-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----),希望将其转换为-----BEGIN ENCRYPTED PRIVATE KEY-----...-----END ENCRYPTED PRIVATE KEY-----格式的加密私钥。服务器未安装且不打算安装OpenSSL,请问能否通过PowerShell实现该需求?
解决方案
可以通过PowerShell实现,核心是利用.NET类库手动处理PKCS#8标准的ASN.1编码和加密逻辑,避开ExportRSAPrivateKey()的限制,步骤如下:
1. 加载未加密RSA私钥
先将PEM格式的私钥转换为可操作的RSA对象:
# 读取本地PEM私钥文件 $rsaPrivateKeyPem = Get-Content -Path "path/to/your/rsa_private_key.pem" -Raw # 清理PEM头部、尾部和空白字符 $cleanedPem = $rsaPrivateKeyPem -replace "-----BEGIN RSA PRIVATE KEY-----", "" ` -replace "-----END RSA PRIVATE KEY-----", "" ` -replace "\s", "" # 转换为字节数组并导入到RSA对象 $keyBytes = [Convert]::FromBase64String($cleanedPem) $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider $rsa.ImportPkcs8PrivateKey($keyBytes, [ref]$null)
2. 生成OpenSSL兼容的加密私钥
严格遵循PKCS#8加密私钥标准,用PBKDF2生成密钥、AES-256-CBC加密私钥,再组装符合OpenSSL要求的ASN.1结构:
# 设置加密参数 $password = "your_secure_password" $salt = [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes(16) $iterations = 10000 # OpenSSL默认迭代次数 # 用PBKDF2生成AES密钥和IV $keyDerivation = New-Object System.Security.Cryptography.Rfc2898DeriveBytes($password, $salt, $iterations) $aesKey = $keyDerivation.GetBytes(32) # AES-256密钥长度 $iv = $keyDerivation.GetBytes(16) # 导出PKCS#8格式的未加密私钥 $pkcs8RawBytes = $rsa.ExportPkcs8PrivateKey() # AES-256-CBC加密私钥 $aes = New-Object System.Security.Cryptography.AesManaged $aes.Key = $aesKey $aes.IV = $iv $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7 $encryptor = $aes.CreateEncryptor() $encryptedKeyBytes = $encryptor.TransformFinalBlock($pkcs8RawBytes, 0, $pkcs8RawBytes.Length) # 组装完整的PKCS#8加密私钥ASN.1结构 $asnWriter = New-Object System.Security.Cryptography.AsnWriter([System.Security.Cryptography.AsnEncodingRules]::BER) $asnWriter.PushSequence() # EncryptedPrivateKeyInfo版本 $asnWriter.WriteInteger(0) # 加密算法标识符(包含PBKDF2参数) $asnWriter.PushSequence() $asnWriter.WriteObjectIdentifier("1.2.840.113549.1.5.12") # PBKDF2 OID $asnWriter.PushSequence() $asnWriter.WriteOctetString($salt) $asnWriter.WriteInteger($iterations) $asnWriter.WriteInteger(32) # 导出密钥长度 # 嵌套AES-256-CBC算法参数 $asnWriter.PushSequence() $asnWriter.WriteObjectIdentifier("2.16.840.1.101.3.4.1.42") # AES-256-CBC OID $asnWriter.PushSequence() $asnWriter.WriteOctetString($iv) $asnWriter.PopSequence() $asnWriter.PopSequence() $asnWriter.PopSequence() $asnWriter.PopSequence() # 加密后的私钥数据 $asnWriter.WriteOctetString($encryptedKeyBytes) $asnWriter.PopSequence() # 转换为PEM格式 $encryptedPkcs8Bytes = $asnWriter.Encode() $encryptedPem = "-----BEGIN ENCRYPTED PRIVATE KEY-----`n" + ` [Convert]::ToBase64String($encryptedPkcs8Bytes, [System.Base64FormattingOptions]::InsertLineBreaks) + ` "`n-----END ENCRYPTED PRIVATE KEY-----" # 保存到本地文件 $encryptedPem | Out-File -Path "path/to/encrypted_private_key.pem" -Encoding ASCII
3. 原ASN1错误说明
你之前遇到的错误,是因为生成的PKCS#8结构不符合OpenSSL的预期——要么缺少PBKDF2参数的嵌套封装,要么ASN.1标签类型错误。上面的代码严格遵循PKCS#8标准和OpenSSL的加密私钥格式,可避免此类问题。
内容的提问来源于stack exchange,提问作者Ekta
相关产品推荐
相关产品推荐

