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.