C# RSA加密与PHP解密互操作指南

霞舞
发布: 2025-12-04 13:50:23
原创
114人浏览过

c# rsa加密与php解密互操作指南

本文旨在提供一套完整的跨平台RSA加密解密方案,详细阐述如何在C#应用程序中生成RSA密钥对并进行数据加密,随后在PHP环境中利用私钥对密文进行解密。核心内容包括C#加密实现、XML格式私钥到PEM格式的转换方法,以及PHP解密过程中的Base64解码与OpenSSL函数应用,确保数据在不同语言环境间的安全传输与处理。

1. 引言

在现代软件开发中,跨语言、跨平台的数据安全传输是常见的需求。RSA作为一种非对称加密算法,广泛应用于数据加密、数字签名等场景。本文将聚焦于一个具体的实践问题:如何使用C#进行RSA数据加密,并随后在PHP环境中进行解密。这涉及到密钥格式的兼容性、数据编码以及不同语言的加密库使用细节。

2. C# RSA加密实现

在C#中,我们可以使用System.Security.Cryptography命名空间下的RSACryptoServiceProvider类来生成RSA密钥对并执行加密操作。

2.1 密钥生成与管理

首先,创建一个RSAEncrypter类来封装密钥的生成和加密逻辑。构造函数中,我们初始化一个2048位的RSA服务提供者,并导出公钥和私钥参数。

立即学习PHP免费学习笔记(深入)”;

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;

namespace TEST
{
    public class RSAEncrypter
    {
        private RSACryptoServiceProvider _rsa;
        private RSAParameters _privateKey;
        private RSAParameters _publicKey;

        public RSAEncrypter()
        {
            // 初始化2048位的RSA密钥对
            _rsa = new RSACryptoServiceProvider(2048);
            // 导出私钥参数(包含所有秘密信息)
            _privateKey = _rsa.ExportParameters(true);
            // 导出公钥参数(只包含公开信息)
            _publicKey = _rsa.ExportParameters(false);
        }

        // 获取私钥的XML字符串表示
        public string PrivateKeyString()
        {
            var sw = new StringWriter();
            var xs = new XmlSerializer(typeof(RSAParameters));
            xs.Serialize(sw, _privateKey);
            return sw.ToString();
        }

        // 获取公钥的XML字符串表示(如果需要外部提供公钥进行加密)
        public string PublicKeyString()
        {
            var sw = new StringWriter();
            var xs = new XmlSerializer(typeof(RSAParameters));
            xs.Serialize(sw, _publicKey);
            return sw.ToString();
        }
    }
}
登录后复制

注意: 在实际应用中,私钥应严格保密,不应随意通过字符串形式传输或存储在不安全的地方。这里为了演示方便,将其导出为字符串。

2.2 数据加密

加密方法接收明文和公钥字符串。在加密前,需要将传入的公钥字符串反序列化回RSAParameters对象,并导入到RSACryptoServiceProvider实例中。

// 续 RSAEncrypter 类
public string Encrypt(string plainText, string publicKeyXml)
{
    // 创建一个新的RSACryptoServiceProvider实例用于加密,避免与当前实例的私钥混淆
    using (var rsaEncryptor = new RSACryptoServiceProvider())
    {
        // 从XML字符串导入公钥
        rsaEncryptor.FromXmlString(publicKeyXml);

        // 将明文转换为字节数组,使用Unicode编码确保字符兼容性
        var data = Encoding.Unicode.GetBytes(plainText);

        // 执行RSA加密,第二个参数为false表示使用PKCS#1 v1.5填充(默认)
        var cypher = rsaEncryptor.Encrypt(data, false);

        // 将加密后的字节数组转换为Base64字符串,以便于传输和存储
        return Convert.ToBase64String(cypher);
    }
}
登录后复制

C#导出的RSAParameters XML格式私钥示例如下:

<?xml version="1.0" encoding="utf-16"?>
<RSAParameters xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Exponent>AQAB</Exponent>
  <Modulus>38Z4+7H1ADzMPO8z5+QdxXS21YBEaq9Xacf7dHFXUpK72SUAIYnfijc5RDSgGFismTNlrrOa7m/6+iIWS/yB7+esvIjgfSFm+QU2aeC16NisMuw+KvPeEr8CVMjh8F5YW1ST4qKXHXG6qIe/FM2LPVGV92O9WO1ATIDcATO8UU2rJgrxKMdmE9fawqmy/j7fwI1+FL6LCNgdvgZ3OOLLwHVcyOyj7ibiIUQAcw10qW0I4MBnQL5V8udKrhKXKoVE6rsfLZoBC9rBD62ckB7CJfMsGcAVffBvnd7SRJiTFEEPVZFqzyGk0BOeqbJkHbzKNytNkUjnFQlDX9tSLCtufQ==</Modulus>
  <!-- ... 其他私钥参数 P, Q, DP, DQ, InverseQ, D ... -->
</RSAParameters>
登录后复制

3. PHP RSA解密实现

PHP的openssl扩展提供了强大的加密功能,但它通常期望PEM(Privacy-Enhanced Mail)格式的密钥。C#导出的XML格式密钥不能直接被PHP识别,因此需要进行转换。

3.1 密钥格式转换:XML到PEM

这是C#与PHP互操作的关键一步。C#的RSAParameters XML格式包含了RSA私钥的所有组成部分(模数、指数、素数因子等)。PEM格式的私钥通常是PKCS#1或PKCS#8标准,它们将这些参数编码为ASN.1结构,然后进行Base64编码,并用-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----(或-----BEGIN PRIVATE KEY-----)等头尾标记包裹。

由于C#没有直接导出PEM格式私钥的功能,我们需要一个外部工具或脚本来完成这个转换。通常,这个过程涉及:

  1. 解析C#导出的XML字符串,提取Modulus、Exponent、P、Q、DP、DQ、InverseQ、D等Base64编码的参数。
  2. 将这些Base64编码的参数解码为原始字节
  3. 按照PKCS#1 RSA私钥的ASN.1结构(SEQUENCE of INTEGERs)重新组装这些字节。
  4. 对组装后的ASN.1结构进行Base64编码。
  5. 在Base64编码的字符串前后添加PEM格式的头尾标记。

有许多开源库或脚本可以实现此功能,例如GitHub上的一些Gist或专用的密钥转换工具。一旦转换完成,你的私钥将看起来像这样:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAwGbWRx8kEz5+BHt5f8/R4ka7AOBGbP1YjfhY33eUQzsh6Ygl
jAvPYXmopaSEOLWAjq/TTCGXGmSfZi0DRPGeSnNXzU6nUu1qQBC5sQYIPSph/lEV
S7jv8isVO9/vH+TGCwE0CeGiQt1QP/m72Vaux3U6nt6ddVat3rpHy4FVuuDHKF58
9HQakf5cMCz4wei4y71U/tLIj1F7P5TRqSdKMB4ZLYLDbX+32OEPMEP6DJEysAiC
oRdpBR/KCOlH3QHEF0RDuTbdgL6f8oAuN2Wvr+p+f1lnkld08+gyKma9cEBpeIB7
cjBeNNcImyhXfp8VBjjZNd//ikt7jnDle30MWQIDAQABAoIBADuxbDfCrKGf2N8x
I+AIrTiD807xRkhYTdo2O/SRGBnHxdy7ldKec2fto+pIYZFqlokueeL75PKWV3IO
8x23zQGSSaJ0DavH5xgbWFFY6sN3W9HYfD/zD9bVkQ/ziTAe/Wa6p9eM/pe6LES9
CZADudQ+RcK2lKmsC+O3bcDwzpVczzuZ1s29F6Jc2L0Q7e1ce9FfBmhl/faei7ro
5DWV30+AqhdwPppMhOWFS/walro8Sq90Kz0chaU6N1vVBEdo4dSLKYapyxJwAHhm
HfNkA+wMrsMXGd9eKpi4u8AupnJYypFdBaEEgrKIbg21LLRTyx1fFKXWdE0puG7H
0GVfoNUCgYEAxoaCzv7LslAOa8bZwGVxcvnE0tIafPwXyOldH/jqeXf53I1gOmFM
dI143wawKQES8CvrbedzP/5tNVZhdrOOekTRM61yw3xSUYY5e8Ngt/gn4KyQ0nA5
X75QjtC6VxNM6ssFpyUxQT95lvTo13avrVjhnGt3raNxwTgiqJjvTfsCgYEA+Bp5
FElve0NnfvkpYeffuF6E3mTRS44IH7qRTFrpXh31zwMxE6K3cltbRtHtuf5/7DmR
XpbeogxG4Bzzw/Y7DodV3V82ApIzyhFkN5PPfg5mR/W8cia82Q3QsRMpjYTo9TBZ
aiAsTbUz8E6KaFrS64V6KbRl84EE8XBaG7tvYrsCgYBZ4TZBzvub7EDLLMkTIRpe
6pPgurzBT0TZckX2HrTRb68Q2nTxmXGK5y4NEzMYLWNMlyXMqVf1ZhQ9bLFNk3dz
BcsNMX7e4F9Ih5No5Aja4Z/0SUx76dEf9sL0Fa33lEZjmq0hgmYtWzaKULFGM3bP
7YifT8xsMa5jwy111V+qlwKBgQCjtHwN+cKYd8pTir5WfrQsqBlN0QIUs3wCy4zR
7+6qDmTCGl4IkcYvq74Xha8xmY745KdZ3Xy7OhSODix+MfuXw47RieBOY//OJhmV
Xm97wq6Ubr3QKGVVZvs7y+QQIBHCrwtgriftglHqDzjeUId5plIMMJ9Qw+HqGXMr
d0qwvwKBgQCjNuhKMHGqG6DuYiLQjJVHA6aG87K5tfNNC8yQPOIbkIJTlSzGQIkm
66wA2PSCI+yRixm+gZWGdVcYuVvcfTHLsledLocTWBRf/2VAGlqZg1ewybGrrixF
05KXg9DcAK9HFyZryFZAXtLyAoRaS1ElcSVBtLggQreGsr8fIM5Fvw==
-----END RSA PRIVATE KEY-----
登录后复制

3.2 数据解密

在PHP中,使用openssl_private_decrypt函数进行解密。需要注意的是,C#加密后输出的是Base64编码的字符串,因此在PHP解密前必须先使用base64_decode将其转换回原始的二进制密文。

<?php

// 从C#加密端接收到的Base64编码密文
$encryptedData = '
b9+nktWSdlYQWiuswcT49JJdt1mmZj87Gwwydkpiu2Xbf3n1Nc+xE5whSzgfTIIthQEVssCUk/UfNsyN2iC37nkxcQe4Xu6KsiWFYvCRZmxww24p/qi43isd1ijCS6wajrJbrpq2tvLzBZ7KhrYkEt3qPbanRRslJauzaCW8MT42HotFl7mVKJjj5p+U6p5dklkm0Uxn36a9eB8+Nt8kSum1YcUbkrS0TRhmorQxifNY99yEju3KeISq5+946tKpW+Efau0CvUF/V5mKn203T5MdO8x5z7VFejHW6dB6oDxTh9EeEyEAPPRBz734wtZxCOVODd39Ttnk6FfnnWat8w==
';

// 经过转换后的PEM格式RSA私钥
$private_key = '
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAwGbWRx8kEz5+BHt5f8/R4ka7AOBGbP1YjfhY33eUQzsh6Ygl
jAvPYXmopaSEOLWAjq/TTCGXGmSfZi0DRPGeSnNXzU6nUu1qQBC5sQYIPSph/lEV
S7jv8isVO9/vH+TGCwE0CeGiQt1QP/m72Vaux3U6nt6ddVat3rpHy4FVuuDHKF58
9HQakf5cMCz4wei4y71U/tLIj1F7P5TRqSdKMB4ZLYLDbX+32OEPMEP6DJEysAiC
oRdpBR/KCOlH3QHEF0RDuTbdgL6f8oAuN2Wvr+p+f1lnkld08+gyKma9cEBpeIB7
cjBeNNcImyhXfp8VBjjZNd//ikt7jnDle30MWQIDAQABAoIBADuxbDfCrKGf2N8x
I+AIrTiD807xRkhYTdo2O/SRGBnHxdy7ldKec2fto+pIYZFqlokueeL75PKWV3IO
8x23zQGSSaJ0DavH5xgbWFFY6sN3W9HYfD/zD9bVkQ/ziTAe/Wa6p9eM/pe6LES9
CZADudQ+RcK2lKmsC+O3bcDwzpVczzuZ1s29F6Jc2L0Q7e1ce9FfBmhl/faei7ro
5DWV30+AqhdwPppMhOWFS/walro8Sq90Kz0chaU6N1vVBEdo4dSLKYapyxJwAHhm
HfNkA+wMrsMXGd9eKpi4u8AupnJYypFdBaEEgrKIbg21LLRTyx1fFKXWdE0puG7H
0GVfoNUCgYEAxoaCzv7LslAOa8bZwGVxcvnE0tIafPwXyOldH/jqeXf53I1gOmFM
dI143wawKQES8CvrbedzP/5tNVZhdrOOekTRM61yw3xSUYY5e8Ngt/gn4KyQ0nA5
X75QjtC6VxNM6ssFpyUxQT95lvTo13avrVjhnGt3raNxwTgiqJjvTfsCgYEA+Bp5
FElve0NnfvkpYeffuF6E3mTRS44IH7qRTFrpXh31zwMxE6K3cltbRtHtuf5/7DmR
XpbeogxG4Bzzw/Y7DodV3V82ApIzyhFkN5PPfg5mR/W8cia82Q3QsRMpjYTo9TBZ
aiAsTbUz8E6KaFrS64V6KbRl84EE8XBaG7tvYrsCgYBZ4TZBzvub7EDLLMkTIRpe
6pPgurzBT0TZckX2HrTRb68Q2nTxmXGK5y4NEzMYLWNMlyXMqVf1ZhQ9bLFNk3dz
BcsNMX7e4F9Ih5No5Aja4Z/0SUx76dEf9sL0Fa33lEZjmq0hgmYtWzaKULFGM3bP
7YifT8xsMa5jwy111V+qlwKBgQCjtHwN+cKYd8pTir5WfrQsqBlN0QIUs3wCy4zR
7+6qDmTCGl4IkcYvq74Xha8xmY745KdZ3Xy7OhSODix+MfuXw47RieBOY//OJhmV
Xm97wq6Ubr3QKGVVZvs7y+QQIBHCrwtgriftglHqDzjeUId5plIMMJ9Qw+HqGXMr
d0qwvwKBgQCjNuhKMHGqG6DuYiLQjJVHA6aG87K5tfNNC8yQPOIbkIJTlSzGQIkm
66wA2PSCI+yRixm+gZWGdVcYuVvcfTHLsledLocTWBRf/2VAGlqZg1ewybGrrixF
05KXg9DcAK9HFyZryFZAXtLyAoRaS1ElcSVBtLggQreGsr8fIM5Fvw==
-----END RSA PRIVATE KEY-----
';

// 确保PHP能够正确解析PEM密钥
// openssl_pkey_get_private() 函数用于从字符串或文件获取私钥资源
$privateKeyResource = openssl_pkey_get_private($private_key);
if (!$privateKeyResource) {
    die("无法加载私钥: " . openssl_error_string());
}

// 先将Base64编码的密文解码为二进制数据
$decodedEncryptedData = base64_decode($encryptedData);

$decryptedData = '';
// 使用私钥解密数据
// OPENSSL_PKCS1_PADDING 与 C# 的 RSA.Encrypt(data, false) 默认填充方式一致
$success = openssl_private_decrypt($decodedEncryptedData, $decryptedData, $privateKeyResource, OPENSSL_PKCS1_PADDING);

if ($success) {
    // C#加密时使用了Unicode编码,PHP解密后可能需要进一步处理编码
    // 通常,如果原始数据是UTF-8,C#加密前应转为UTF-8字节,或PHP解密后转回UTF-8
    // 这里假设原始数据是可直接显示的ASCII或ISO-8859-1,如果包含中文等,可能需要编码转换
    echo "解密成功:\n";
    echo $decryptedData; // 输出解密后的明文
    // 如果C#加密前是特定编码(如UTF-8),则PHP解密后可能需要 iconv 或 mb_convert_encoding
    // 例如:echo iconv('UCS-2LE', 'UTF-8
登录后复制

以上就是C# RSA加密与PHP解密互操作指南的详细内容,更多请关注php中文网其它相关文章!

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号