I need to transform these encryption system developed in C# to PHP. These are the input data. Customer ID, JSON object transformed to string and a private key.
codigoCliente: 1002
datos: {“codigoCliente”:1002,”codigoArticulo”:”30-07483″,”cantidad”:1}
claveSecretaServicio: RFlTfDIwMjBXZWJQYWdlX0V4dGVybmF
I need to get this HASH as result: WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=
This is the call in C#: GetHash(modelo.CodigoCliente.ToString(), JsonSerializer.Serialize(modelo), “WGHGEY830J3WeadO1o4NGNLYZ9lY7xvquol5igE+hLU=”);
The C# functions to transform to PHP are these.
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;
}
}
I don’t know C# so I don’t really understand the detailed workings of the functions to change them to PHP.
I have tried this but my HASH result is different.
/********************
* 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);
}
I’ve gotten a valid 3DES PHP function (thanks to 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);
}
but I still need the other two to achieve the valid HASH. Perhaps if I you read this Michael Fehr.
Your function is correct and I get the same intermediate 3DES value that is achieved with C#: PD8fSM4gz3s=
Thank you in advance.
Advertisement
Answer
The posted Base64 encoded key RFlTfDIwMjBXZWJQYWdlX0V4dGVybmF
results Base64 decoded in DYS|2020WebPage_Externa
and thus has a length of 23 bytes. This is too short for TripleDES, which requires a 24 bytes key. A plausible key that additionally has the required length of 24 bytes is DYS|2020WebPage_External
, which is Base64 encoded RFlTfDIwMjBXZWJQYWdlX0V4dGVybmFs
. This is probably a copy/paste issue.
Since the passed data corresponds to a JSON string, a corresponding class, in the following called Modelo
, has to be defined, initialized according to the posted sample data and passed as JSON string.
Then the following C# code returns the expected hash:
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=
In the PHP code, in the encrypt_3DES
method, the result must not be returned Base64 encoded, but as raw binary data. In addition, a class corresponding to the Modelo
class of the C# code must be implemented, initialized according to the posted sample data, and passed as JSON string.
The following PHP code returns the expected hash value corresponding to that of the C# code:
<?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=
?>
A further note: Apparently the data (datos
) are to be hashed with a HMAC and the key used for this (claveOperacion
) is derived from a client ID (CodigoCliente
) in combination with a password (claveSecretaServicio
). To derive the key for the HMAC, an encryption with TripleDES is applied. More contemporary seems to me a derivation with a reliable key derivation function, such as PBKDF2.