C# RSA Encrpytion -> Laravel phpseclib 解密()

问题描述

我正在使用由 PHPseclib 生成的密钥对,然后我用它在 C# 中加密一条消息并在 PHP 中解密。

公钥是:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvh4OvlS5+7Skk5Nij296
rDAKQsxZrz+gV/MInvWqe/SAOlOf8vqs6xJsn7sd523X8m+b0Kd751UbeeDQRGjC
mbQc9iwQHUFrNa0bSVnpyoc27K+cuxNdtoPG1XXRCFLKKqVJKSyB5ZPu+oQr+OIo
6zYhU5jfCEYbpzPdyYqfDGJPpJv/r8F11MCBrdbvD5Z42ysTDqSxFGIfROWtDOP5
ShSNcVGRQYfX3E/v8j+qy0yu2PD/W1UqNd3m6TTkUj/u1XukUMWp+tfXEdEp7IEU
askvGnBfHgJcsBp2c6kT9WxIU0ai4G8mo/2OsHprw42PBWLcJwfUeUgY3itSczni
WQIDAQAB
-----END PUBLIC KEY-----

到 XML 的转换是通过 https://superdry.apphb.com/tools/online-rsa-key-converter

完成的

以下是消息在 C# 中的加密方式:

public void Synch()
    {
        string messagetoSend = "123";
        
        var encryptedData = EncryptString(messagetoSend);
        
        var request = new HTTPRequest(new Uri(APIUrl),HTTPMethods.Post,OnRequestFinished);

        request.AddField("message",encryptedData);
        request.FormUsage = BestHTTP.Forms.HTTPFormUsage.Multipart;

        request.Send();
    }

public byte[] EncryptBytes(string message)
    {
        // https://superdry.apphb.com/tools/online-rsa-key-converter
        string XML = "<RSAkeyvalue><Modulus>vh4OvlS5+7Skk5Nij296rDAKQsxZrz+gV/MInvWqe/SAOlOf8vqs6xJsn7sd523X8m+b0Kd751UbeeDQRGjCmbQc9iwQHUFrNa0bSVnpyoc27K+cuxNdtoPG1XXRCFLKKqVJKSyB5ZPu+oQr+OIo6zYhU5jfCEYbpzPdyYqfDGJPpJv/r8F11MCBrdbvD5Z42ysTDqSxFGIfROWtDOP5ShSNcVGRQYfX3E/v8j+qy0yu2PD/W1UqNd3m6TTkUj/u1XukUMWp+tfXEdEp7IEUaskvGnBfHgJcsBp2c6kT9WxIU0ai4G8mo/2OsHprw42PBWLcJwfUeUgY3itSczniWQ==</Modulus><Exponent>AQAB</Exponent></RSAkeyvalue>";
        

        //get the object back from the stream
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.FromXmlString(XML);
        
        byte[] bytesMessage = Encoding.UTF8.GetBytes(message);
        var bytesCipherText = rsa.Encrypt(bytesMessage,false);

        return bytesCipherText;
    }

public string EncryptString(string message)
    {
        string encryptedText = Convert.ToBase64String(EncryptBytes(message));
        return encryptedText;
    }

C# 向 PHP 发送的内容(加密消息)(每次都更改):

DE9e82l/lP211YQ0gDhvIcwU1dIXaN7re9+VpUYEB62yRYYnmzZfHxv+WeMHtvg5Yq15Lr4rhvQpTiMGyktxkR5wPQRQhDX74gonPIKgYYIfoqF0mswkulaiLReagcroVyd4ZFEfPxKScLXqjo3yIFLaGWVMGoh81ZwRoOUEGLCPkhsRMp1CiHecGZEmZm7VNoiOEeA5xRdO3asl5/jrbnpXeNXcU4OFV4n1hfdw8W04VHyzDU3AmkDnpfO3AHnZluGPOYpl3OYVn9bsmuqL9d02gBr0UP72vp5GxNoDZAy3tzymhdNZArN9sfBXX+QPOlK2eaFwSypGIa/SUn+erg==

PHP 中的解密端:

Route::post('/decrypt',function (Request $request) {
    $encoded_message = $request->input('message');
    if (!empty($encoded_message)) {
        $private = RSA::loadFormat('PKCS8',file_get_contents(resource_path() . '/rsa/key.pem'),$password = false);

        try {
            $message = $private->decrypt(base64_decode($encoded_message));
            echo $message;
            }
        } catch (Exception $e) {
            return response()->json([
                'message' => 'Failed to process: '.$e->getMessage().$e->getTraceAsstring(),]);
        }

输出是这样的:

Response: {"message":"Failed to process: Decryption error#0 C:\\www\\laravel\\vendor\\PHPseclib\\PHPseclib\\PHPseclib\\Crypt\\RSA\\PrivateKey.PHP(469):

在这里遗漏了什么?

解决方法

在 C# 代码中应用了 PKCS#1 v1.5 填充(Encrypt() 的第二个参数是 false),phpseclib 默认使用 OAEPadding({{3} }).

如果在 PHP 代码中明确指定了 PKCS#1 v1.5 填充,则解密工作:

$message = $private->withPadding(RSA::ENCRYPTION_PKCS1)->decrypt(base64_decode($encoded_message));

或者,可以在 C# 代码中使用 OAEPadding。但请注意,如果在 Encrypt() 中将第二个参数设置为 true,默认情况下 .NET 对两个摘要都使用 SHA-1。但是,phpseclib 默认情况下对两个摘要都应用 SHA-256。因此,在 C# 代码中,为了与 PHP 代码兼容,两个摘要都必须显式设置为 SHA256(这对于 RSACryptoServiceProvider 是不可能的,但对于 RSACng 是不可能的;也,需要 here 的重载,使用它可以显式设置摘要)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...