Skip to content
Advertisement

Function from C# to PHP

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.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement