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

使用C#实现AES-RSA加解密对接FastSpring遇错求助

关于FastSpring加密载荷的RSA加密解密问题

问题背景

项目向FastSpring发送加密载荷的流程如下:

  • 生成2048位RSA公私证书对,将公证书上传至FastSpring;
  • 使用OpenSSL生成密钥对的命令:
    openssl genrsa -out privatekey.pem 2048
    openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem
  • 随机生成16字节AES密钥,用该密钥加密载荷,再用私钥加密AES密钥,将加密后的载荷和AES密钥发送给FastSpring;
  • FastSpring用已上传的公证书解密AES密钥,再解密载荷。

我的AES密钥加密代码(C#)

string privateKeyText = File.ReadAllText(PathToPrivateKey);    
using RSA privateRsa = RSA.Create();    
privateRsa.ImportFromPem(privateKeyText.ToCharArray());
 
byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt); //AES Key
byte[] encryptedAesKey = rsa.Encrypt(bytesToEncrypt, RSAEncryptionPadding.OaepSHA256);

本地测试解密代码及错误

测试代码:

using var publicX509 = new X509Certificate2(PathToCertificate); 
RSA publicRsa = publicX509.GetRSAPublicKey();
byte[] decryptedBytes = rsa.Decrypt(encryptedAesKey, RSAEncryptionPadding.OaepSHA256); 
string decryptedAesKey = Encoding.UTF8.GetString(decryptedBytes);

错误信息:

WindowsCryptographicException: Key does not exist. 
   at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, Boolean encrypt)
   at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, Boolean encrypt)
   at System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)
   at UserQuery.DecryptData(Byte[] dataToDecrypt, RSA rsa), line 37
   at UserQuery.Main(), line 20

疑问

常规RSA是公钥加密、私钥解密,但FastSpring文档显示私钥加密后用公钥解密可行,请问该方式是否有效?若有效,错误原因是什么?

FastSpring支持团队提供的实现代码(C#)

public static string CreateSecureLoad(string clearText, ref byte[] generatedAesKey)
{
    RijndaelManaged cryptoAlgo = new RijndaelManaged
    {
        Padding = PaddingMode.PKCS7,
        Mode = CipherMode.ECB,
        KeySize = 128,
        BlockSize = 128
    };

    generatedAesKey = cryptoAlgo.Key;
    var clearTextArrary = Encoding.UTF8.GetBytes(clearText);
    var encryptor = cryptoAlgo.CreateEncryptor();

    using (MemoryStream msEncryprt = new MemoryStream())
    {
        using (CryptoStream csEncrypt = new CryptoStream(msEncryprt, encryptor, CryptoStreamMode.Write))
        {
            csEncrypt.Write(clearTextArrary);
            csEncrypt.FlushFinalBlock();
            var cipher = msEncryprt.ToArray();
            return Convert.ToBase64String(cipher);
        }
    }

    return "";
}

public static string CreateSecureKey(byte[] aesKey, string privateKeyPEM)
{
    var encryptEngine = new Pkcs1Encoding(new RsaEngine());

    using (var textReader = new StreamReader(privateKeyPEM))
    {
        var pemReader = new PemReader(textReader);
        var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
        encryptEngine.Init(true, keyPair.Private);
    }

    var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(aesKey, 0, aesKey.Length));

    return encrypted;
}

public static string CreateSecureKeyFromPEM(byte[] aesKey, string privateKeyPEM)
{
    var encryptEngine = new Pkcs1Encoding(new RsaEngine());

    using (TextReader textReader = new StringReader(privateKeyPEM))
    {
        var pemReader = new PemReader(textReader);
        var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
        encryptEngine.Init(true, keyPair.Private);
    }

    var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(aesKey, 0, aesKey.Length));

    return encrypted;
}

解答

1. 私钥加密、公钥解密的有效性

这种方式是有效的,本质是利用RSA非对称性实现身份验证:只有持有私钥的一方能生成加密内容,持有公钥的一方可以验证并解密,确认内容来自私钥持有者,符合FastSpring的安全校验需求。

2. 错误原因分析

你的代码存在两个核心问题:

  • API使用逻辑错误:.NET内置的RSA.Encrypt方法仅用于公钥加密,即便传入私钥实例,该方法依然会按公钥加密逻辑执行,生成的密文无法用公钥解密;而RSA.Decrypt仅用于私钥解密,用公钥实例调用会直接抛出密钥不存在的错误。
  • 填充方式不匹配:FastSpring提供的代码使用PKCS#1 v1.5填充(通过Pkcs1Encoding实现),而你使用的是OAEP-SHA256填充,两者不兼容,这是FastSpring无法解密的直接原因。

3. 修复方案

  • 直接采用FastSpring提供的代码:该代码依赖BouncyCastle库,使用其API实现私钥加密、公钥解密的逻辑,且填充方式与FastSpring端完全匹配。
  • 若不想引入第三方库,可通过RSA签名逻辑模拟:用私钥对AES密钥生成签名(本质是带PKCS#1填充的加密),用公钥验证签名并确认内容有效性,但.NET没有直接提取原始内容的API,如需还原AES密钥仍建议使用BouncyCastle。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:03:12