Pergunta

Hi i have c# sample of code but i can't turn it to php. İ tried to rewrite code but i can't do it. In my project other server encrypts data with c# and i have to decrypt it using PHP.

I have password and salt value.

Here is C# code includes encrypt and decrypt function.

using System;

using System.Collections.Generic;

using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace EncryptionSample
{
    public static class CipherUtility
    {
        public static string Encrypt(string plainText, string password, string salt)
        {
            if (plainText == null || plainText.Length <= 0)
            {
                throw new ArgumentNullException("plainText");
            }

            if (String.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException("password");
            }

            if (String.IsNullOrEmpty(salt))
            {
                throw new ArgumentNullException("salt");
            }

            byte[] encrypted;
            byte[] saltBytes = Encoding.UTF8.GetBytes(salt);

            using (Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, saltBytes))
            {
                using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
                {
                    aesAlg.Key = derivedBytes.GetBytes(32);
                    aesAlg.IV = derivedBytes.GetBytes(16);

                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                    using (MemoryStream msEncrypt = new MemoryStream())
                    {
                        using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                            {
                                swEncrypt.Write(plainText);
                            }

                            encrypted = msEncrypt.ToArray();
                        }
                    }
                }
            }

            return Convert.ToBase64String(encrypted);
        }

        public static string Decrypt(string cipherValue, string password, string salt)
        {
            byte[] cipherText = Convert.FromBase64String(cipherValue);

            if (cipherText == null 
                || cipherText.Length <= 0)
            {
                throw new ArgumentNullException("cipherValue");
            }

            if (String.IsNullOrWhiteSpace(password))
            {
                throw new ArgumentNullException("password");
            }

            if (String.IsNullOrWhiteSpace(password))
            {
                throw new ArgumentNullException("salt");
            }

            string plaintext = null;
            byte[] saltBytes = Encoding.UTF8.GetBytes(salt);

            using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(password, saltBytes))
            {
                using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
                {
                    aesAlg.Key = deriveBytes.GetBytes(32);
                    aesAlg.IV = deriveBytes.GetBytes(16);

                    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }
            }

            return plaintext;
        }
    }
}

My php code is here but i think i am totally wrong.

function decrypt($encrypted, $password, $salt) {
 // Build a 256-bit $key which is a SHA256 hash of $salt and $password.
 $key = hash('SHA256', $salt . $password, true);
 // Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
 $iv = base64_decode(substr($encrypted, 0, 22) . '==');
// print_r($iv);die();
 // Remove $iv from $encrypted.
 $encrypted = substr($encrypted, 22);
 //print_r($encrypted);die();
 // Decrypt the data.  rtrim won't corrupt the data because the last 32 characters are the md5 hash; thus any \0 character has to be padding.

 $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, base64_decode($encrypted), MCRYPT_MODE_CBC, $iv), "\0\4");

 // Retrieve $hash which is the last 32 characters of $decrypted.
 $hash = substr($decrypted, -32);
 // Remove the last 32 characters from $decrypted.
 $decrypted = substr($decrypted, 0, -32);
 // Integrity check.  If this fails, either the data is corrupted, or the password/salt was incorrect.
 if (md5($decrypted) != $hash) return false;

 return $decrypted;
 }
Foi útil?

Solução 2

I'm no crypto expert, but I think you might find phpseclib useful.

Outras dicas

On first glance, I can see that your keys are going to be different. Your C# code generates your key using Rfc2898DeriveBytes, which is a key generator based on PBKDF2. Your php code, on the other hand, is using SHA256 to generate the key. These are going to return different values. With different keys, you are done before you even start.

Also, I don't know that CryptoStream is going to append the IV on the beginning of the ciphertext, nor a MAC value at the end of the ciphertext. Stripping out that text will make your plaintext garbled if it will decrypt at all. Note in the C# decryption method you derive the IV based on the key derivation object (which is not smart, since the same key will generate the same IV for every message, which reduces the security of the first block of your ciphertext, but that's an entirely separate issue).

Do you know for a fact that the C# server is generating the ciphertext exactly the same as your code sample? You need to know the exact parameters of the cryptography being used on the server side

I would suggest that you actually try to research and understand the format of the ciphertext that C# is going to emit, then figure out how to consume that in PHP. Cryptography can be very tricky to work with, especially when trying to integrate heterogenous systems.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top