从C#到PHP的函数
c#
我需要将这些用 C# 开发的加密系统转换为 PHP。这些是输入数据。客户 ID、转换为字符串的 JSON 对象和私钥。
codigoCliente: 1002
数据:{"codigoCliente":1002,"codigoArticulo":"30-07483","cantidad":1}
claveSecretaServicio:RFlTfDIwMjBXZWJQYWdlX0V4dGVybmF
我需要得到这个哈希结果:WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=
这是 C# 中的调用:GetHash(modelo.CodigoCliente.ToString(), JsonSerializer.Serialize(modelo), “WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=”);
转换为 PHP 的 C# 函数是这些。
public static string GetHash(string codigoCliente, string datos, string claveSecretaServicio)
{
var claveSecretaBytes = System.Convert.FromBase64String(claveSecretaServicio);
var claveOperacion = Encrypt3DES(codigoCliente, claveSecretaBytes);
var firmaBytes = GetHMACSHA256(datos, claveOperacion);
return System.Convert.ToBase64String(firmaBytes);
}
private static byte[] Encrypt3DES(string codigoCliente, byte[] key)
{
var codigoClienteBytes = System.Text.Encoding.UTF8.GetBytes(codigoCliente);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
byte[] SALT = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 };
tdes.BlockSize = 64;
tdes.KeySize = 192;
tdes.Mode = CipherMode.CBC;
tdes.Padding = PaddingMode.Zeros;
tdes.IV = SALT;
tdes.Key = key;
var cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(codigoClienteBytes, 0, codigoClienteBytes.Length);
tdes.Clear();
return resultArray;
}
private static byte[] GetHMACSHA256(string data, byte[] key)
{
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
using (HMACSHA256 hmac = new HMACSHA256(key))
{
byte[] hashValue = hmac.ComputeHash(dataBytes, 0, dataBytes.Length);
return hashValue;
}
}
我不知道 C#,所以我不太了解将它们更改为 PHP 的函数的详细工作原理。
我试过这个,但我的 HASH 结果是不同的。
/********************
* 3DES
********************/
function encrypt_3DES($message, $key)
{
$method = 'des-ede3-cbc';
if (strlen($message) % 8) {
$message = str_pad($message, strlen($message) + 8 - strlen($message) % 8, " ");
}
$iv = " ";
$encrypted = openssl_encrypt($message, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
return base64_encode($encrypted);
}
/********************
* SHA 256
********************/
function mac256($ent, $key)
{
$res = hash_hmac('sha256', $ent, $key, true); // TRUE (PHP 5 >= 5.1.2)
return $res;
}
/********************
* BASE 64
********************/
function encodeBase64($data)
{
$data = base64_encode($data);
return $data;
}
function decodeBase64($data)
{
$data = base64_decode($data);
return $data;
}
/********************
* HASH
********************/
function createHash($codigoCliente, $data, $key)
{
$key = decodeBase64($key);
$keyOperacion = encrypt_3DES($codigoCliente, $key);
$res = mac256($data, $keyOperacion);
return encodeBase64($res);
}
我得到了一个有效的 3DES PHP 函数(感谢 Michael Fehr)
function encrypt_3DES($message, $key)
{
$method = 'des-ede3-cbc';
if (strlen($message) % 8) {
$message = str_pad($message, strlen($message) + 8 - strlen($message) % 8, " ");
}
$iv = " ";
$encrypted = openssl_encrypt($message, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
return base64_encode($encrypted);
}
但我仍然需要另外两个来实现有效的 HASH。也许如果你读了这篇迈克尔·费尔。
你的函数是正确的,我得到了与 C# 相同的中间 3DES 值:PD8fSM4gz3s=
先感谢您。
回答
发布的 Base64 编码密钥RFlTfDIwMjBXZWJQYWdlX0V4dGVybmF结果 Base64 解码DYS|2020WebPage_Externa,因此长度为 23 个字节。这对于需要 24 字节密钥的 TripleDES 来说太短了。另外具有所需长度 24 字节的似是而非的密钥DYS|2020WebPage_External是 Base64 编码的RFlTfDIwMjBXZWJQYWdlX0V4dGVybmFs。这可能是复制/粘贴问题。
由于传入的数据对应一个 JSON 字符串,Modelo因此必须定义一个相应的类,在下面称为,根据发布的示例数据进行初始化并作为 JSON 字符串传递。
然后以下 C# 代码返回预期的哈希值:
class Modelo
{
public int CodigoCliente { get; set; }
public string CodigoArticulo { get; set; }
public int Cantidad { get; set; }
}
...
Modelo modelo = new Modelo
{
CodigoCliente = 1002,
CodigoArticulo = "30-07483",
Cantidad = 1
};
string hash = GetHash(modelo.CodigoCliente.ToString(), JsonSerializer.Serialize(modelo), "RFlTfDIwMjBXZWJQYWdlX0V4dGVybmFs");
Console.WriteLine(hash); // WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=
在 PHP 代码中,在encrypt_3DES方法中,返回的结果不能是 Base64 编码的,而是作为原始二进制数据返回的。此外,还Modelo必须实现一个与C#代码的类对应的类,根据贴出的示例数据进行初始化,并以JSON字符串的形式传递。
以下 PHP 代码返回与 C# 代码对应的预期哈希值:
<?php
/********************
* 3DES
********************/
function encrypt_3DES($message, $key)
{
$method = 'des-ede3-cbc';
if (strlen($message) % 8) {
$message = str_pad($message, strlen($message) + 8 - strlen($message) % 8, " ");
}
$iv = " ";
$encrypted = openssl_encrypt($message, $method, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv); //Force zero padding.
return $encrypted; // base64_encode($encrypted); // Fix: Return the raw data and not the Base64 encoded data
}
/********************
* SHA 256
********************/
function mac256($ent, $key)
{
$res = hash_hmac('sha256', $ent, $key, true); // TRUE (PHP 5 >= 5.1.2)
return $res;
}
/********************
* BASE 64
********************/
function encodeBase64($data)
{
$data = base64_encode($data);
return $data;
}
function decodeBase64($data)
{
$data = base64_decode($data);
return $data;
}
/********************
* HASH
********************/
function createHash($codigoCliente, $data, $key)
{
$key = decodeBase64($key);
$keyOperacion = encrypt_3DES($codigoCliente, $key);
$res = mac256($data, $keyOperacion);
return encodeBase64($res);
}
// Define a Modelo class as in the C# code
class Modelo
{
var $CodigoCliente;
var $CodigoArticulo;
var $Cantidad;
function __construct( $CodigoCliente, $CodigoArticulo, $Cantidad)
{
$this->CodigoCliente = $CodigoCliente;
$this->CodigoArticulo = $CodigoArticulo;
$this->Cantidad = $Cantidad;
}
}
$modelo = new Modelo(1002, '30-07483', 1);
$hash = createHash($modelo->CodigoCliente, json_encode($modelo), "RFlTfDIwMjBXZWJQYWdlX0V4dGVybmFs");
print($hash); // WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=
?>
进一步说明:显然数据 ( datos) 将使用 HMAC 进行散列,用于此 ( claveOperacion)的密钥来自客户端 ID ( CodigoCliente) 和密码 ( claveSecretaServicio)。为了导出 HMAC 的密钥,应用了 TripleDES 加密。在我看来,更现代的推导具有可靠的密钥推导函数,例如 PBKDF2。