简体   繁体   English

PHP 加密不兼容 .NET/C# 解密 (AES-256/CBC)

[英]PHP encryption not compatible with .NET/C# decryption (AES-256/CBC)

when I try to encrypt using openssl_encrypt PHP I get square spaces at the end decrypted data which is shown in attached image当我尝试使用 openssl_encrypt PHP 进行加密时,我在最后得到方形空格,解密数据显示在附图中

My API response is getting failure due to getting extra characters during decryption done by .NET side..由于 .NET 端在解密期间获得额外字符,我的 API 响应失败。

How can i resolve this issue please help我该如何解决这个问题请帮忙

C# C#

public static string Decrypt(String encryptedText, String VendorKey, String Token)
{
    var encryptedBytes = Convert.FromBase64String(encryptedText);
    return Encoding.UTF8.GetString(Decrypt(encryptedBytes, GetRijndaelManaged(VendorKey,Token)));
}

private static byte[] Decrypt(byte[] encryptedData, RijndaelManaged rijndaelManaged)
{
    return rijndaelManaged.CreateDecryptor()
                .TransformFinalBlock(encryptedData, 0, encryptedData.Length);
}

public static RijndaelManaged GetRijndaelManaged(String VendorKey, String Token)
{
    var keyBytes = new byte[32];
    var ivBytes = new byte[16];
            
    var secretKeyBytes = Encoding.UTF8.GetBytes(VendorKey + Token);
    Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));

    var ivKeyBytes = Encoding.UTF8.GetBytes(VendorKey);
    Array.Copy(ivKeyBytes, ivBytes, Math.Min(ivBytes.Length, ivKeyBytes.Length));

    return new RijndaelManaged
    {
       Mode = CipherMode.CBC,
       Padding = PaddingMode.Zeros,
       KeySize = 256, 
       BlockSize = 128, 
       Key = keyBytes,
       IV = ivKeyBytes
    };
}

public static string Encrypt(String plainText, String VendorKey, String Token)
{
    var plainBytes = Encoding.UTF8.GetBytes(plainText);
    return Convert.ToBase64String(Encrypt(plainBytes, GetRijndaelManaged(VendorKey, Token)));
}

private static byte[] Encrypt(byte[] plainBytes, RijndaelManaged rijndaelManaged)
{
    return rijndaelManaged.CreateEncryptor()
                .TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}

public static RijndaelManaged GetRijndaelManaged(String VendorKey, String Token)
{
    var keyBytes = new byte[32];
    var ivBytes = new byte[16];
            
    var secretKeyBytes = Encoding.UTF8.GetBytes(VendorKey + Token);
    Array.Copy(secretKeyBytes, keyBytes, Math.Min(keyBytes.Length, secretKeyBytes.Length));

    var ivKeyBytes = Encoding.UTF8.GetBytes(VendorKey);
    Array.Copy(ivKeyBytes, ivBytes, Math.Min(ivBytes.Length, ivKeyBytes.Length));

    return new RijndaelManaged
    {
       Mode = CipherMode.CBC,
       Padding = PaddingMode.Zeros,
       KeySize = 256, 
       BlockSize = 128, 
       Key = keyBytes,
       IV = ivKeyBytes
    };
}

So can help me to resolve this issue所以可以帮我解决这个问题

在此处输入图像描述

When using the sample data you provided, encryption with the .NET code:使用您提供的示例数据时,使用 .NET 代码进行加密:

string vendorKey = "0123456789012345";
string token = "012345";
string pt = @"{""prospectNo"":""SL1000000"",""paymentRequestDateFrom"":""2020-05-28"",""paymentRequestDateTo"":""2020-06-02"",""merchantTransactionId"":""7"",""callerReferenceNo"":""3""}";
string ct = Encrypt(pt, vendorKey, token);
Console.WriteLine(ct);

returns the following ciphertext:返回以下密文:

g163a7jXmZKjH1J3RjC7xkPn5+PJWY6wTX9BgxiTY8hkYjsqImlCuvXOtZgUrrfLnwLy1QGUk6iylc/sInV/XJ9sypJ93tCvjRoj4s4RWGKTqUk3bY31JTM6QuYVclw4zNvyq2WUBCc+EMGGYtn5dBAvqiYdTqrJJTae67EZfgc4Fw5ormmf0rCYXQ2mn7mc1Jdg8v2r3LK9FYiwLEbhOA==

The PHP code below:下面的PHP代码:

<?php
$cipher = "AES-256-CBC"; 

$array =  json_encode(array(
    "prospectNo"=> "SL1000000",
    "paymentRequestDateFrom"=>"2020-05-28",
    "paymentRequestDateTo"=>"2020-06-02",
    "merchantTransactionId"=> "7",
    "callerReferenceNo"=>"3"
    )
);

$token = "012345";
$vendorKey = "0123456789012345";
$key = substr(str_pad($vendorKey . $token, 32, "\0"), 0, 32);
$iv = substr(str_pad($vendorKey, 16, "\0"), 0, 16);

$encrypted_data = openssl_encrypt(zeroPad($array, 16), $cipher, $key, OPENSSL_ZERO_PADDING, $iv); 
print($encrypted_data . "\n");

function zeroPad($text, $bs) { 
    $pad = ($bs - strlen($text) % $bs) % $bs; 
    return ($pad > 0) ? $text . str_repeat("\0", $pad) : $text; 
}
?>

gives the same ciphertext and is thus the PHP counterpart you are looking for, ie under the premise that the API can process the data encrypted by the .NET code, it must also process the data encrypted by the PHP code.给出相同的密文,因此是您正在寻找的 PHP 对应物,即在 API 可以处理 .NET 代码加密的数据的前提下,它还必须处理 PHP 代码加密的数据。


As expected, this ciphertext is decrypted into the correct plaintext by the .NET code.正如预期的那样,这个密文被 .NET 代码解密为正确的明文。 The hex encoded plaintext also reveals that the .NET code does not remove the padding bytes (note the 8 0x00 bytes at the end):十六进制编码的明文还显示 .NET 代码不会删除填充字节(注意末尾的 8 个 0x00 字节):

string vendorKey = "0123456789012345";
string token = "012345";
string ct = "g163a7jXmZKjH1J3RjC7xkPn5+PJWY6wTX9BgxiTY8hkYjsqImlCuvXOtZgUrrfLnwLy1QGUk6iylc/sInV/XJ9sypJ93tCvjRoj4s4RWGKTqUk3bY31JTM6QuYVclw4zNvyq2WUBCc+EMGGYtn5dBAvqiYdTqrJJTae67EZfgc4Fw5ormmf0rCYXQ2mn7mc1Jdg8v2r3LK9FYiwLEbhOA==";
string dt = Decrypt(ct, vendorKey, token);
Console.WriteLine("Plaintext:      " + dt);
Console.WriteLine("Plaintext, hex: " + Convert.ToHexString(Encoding.UTF8.GetBytes(dt)));

with the output:输出:

Plaintext:      {"prospectNo":"SL1000000","paymentRequestDateFrom":"2020-05-28","paymentRequestDateTo":"2020-06-02","merchantTransactionId":"7","callerReferenceNo":"3"}
Plaintext, hex: 7B2270726F73706563744E6F223A22534C31303030303030222C227061796D656E74526571756573744461746546726F6D223A22323032302D30352D3238222C227061796D656E745265717565737444617465546F223A22323032302D30362D3032222C226D65726368616E745472616E73616374696F6E4964223A2237222C2263616C6C65725265666572656E63654E6F223A2233227D0000000000000000

The PHP code posted in this answer differs from your original PHP code essentially only in a more general derivation of $key and $iv (but this makes no difference for the vendorKey used here) and the padding.此答案中发布的 PHP 代码与您的原始 PHP 代码的不同之处主要在于$key$iv的更一般派生(但这对于此处使用的vendorKey没有区别)和填充。 The original PHP code applied the default PKCS#7 padding used by openssl_encrypt() , while the current PHP code applies Zero padding.原始 PHP 代码应用了openssl_encrypt()使用的默认 PKCS#7 填充,而当前 PHP 代码应用了零填充。

Specifically, for the current plaintext, this means that the original PHP code padded with 0x0808080808080808, while the current PHP code pads with 0x0000000000000000.具体来说,对于当前的明文,这意味着原始的PHP代码填充了0x0808080808080808,而当前的PHP代码填充了0x0000000000000000。 Since the .NET code does not remove the padding, the padding bytes are still present even when using the current PHP code (just with different values).由于 .NET 代码不会删除填充,因此即使使用当前的 PHP 代码(只是使用不同的值),填充字节仍然存在。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM