0

I'm trying to reproduce the same encryption algorithm used by a 3rd party on his C# based API. I need to pass a password in the URL encrypted with the same algorithm they use. Here it is the C# code:

public static class EncryptionHelper
{
    // This constant string is used as a "salt" value for the PasswordDeriveBytes function calls.
    // This size of the IV (in bytes) must = (keysize / 8).  Default keysize is 256, so the IV must be
    // 32 bytes long.  Using a 16 character string here gives us 32 bytes when converted to a byte array.
    private const string initVector = "tu89geji340t89u2";

    // This constant is used to determine the keysize of the encryption algorithm.
    private const int keysize = 256;

    /// <summary>
    /// Encrypts a text using a passPhrase
    /// </summary>
    /// <param name="plainText">string that contains the text to encrypt</param>
    /// <param name="passPhrase">string that contains the passPhrase for encryption</param>
    /// <returns></returns>
    public static string Encrypt(string plainText, string passPhrase)
    {
        byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
        byte[] keyBytes = password.GetBytes(keysize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream();
        CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
        cryptoStream.FlushFinalBlock();
        byte[] cipherTextBytes = memoryStream.ToArray();
        memoryStream.Close();
        cryptoStream.Close();
        return Convert.ToBase64String(cipherTextBytes);
    }

    /// <summary>
    /// Decrypts a text using a passPhrase
    /// </summary>
    /// <param name="cipherText">string that contains the encrypted text</param>
    /// <param name="passPhrase">string that containts the passPhrase for decryption</param>
    /// <returns></returns>
    public static string Decrypt(string cipherText, string passPhrase)
    {
        byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);
        PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, null);
        byte[] keyBytes = password.GetBytes(keysize / 8);
        RijndaelManaged symmetricKey = new RijndaelManaged();
        symmetricKey.Mode = CipherMode.CBC;
        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);
        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);
        CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
        byte[] plainTextBytes = new byte[cipherTextBytes.Length];
        int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
        memoryStream.Close();
        cryptoStream.Close();
        return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
    }

    /// <summary>
    /// Changes the reserved path characters to avoid issues with the URL
    /// </summary>
    /// <param name="encryptedText"></param>
    /// <returns></returns>
    public static string EncodeForURL(string encryptedText)
    {
        encryptedText = encryptedText.Replace("+", "__43__");
        encryptedText = encryptedText.Replace("/", "__47__");
        encryptedText = encryptedText.Replace(";", "__59__");
        encryptedText = encryptedText.Replace("?", "__63__");
        return encryptedText;
    }

    /// <summary>
    /// Returns to the original characters for the encrypted text
    /// </summary>
    /// <param name="encryptedText"></param>
    /// <returns></returns>
    public static string DecodeForURL(string encryptedText)
    {
        encryptedText = encryptedText.Replace("__43__", "+");
        encryptedText = encryptedText.Replace("__47__", "/");
        encryptedText = encryptedText.Replace("__59__", ";");
        encryptedText = encryptedText.Replace("__63__", "?");
        return encryptedText;
    }
}
}

I've tried reproducing it in PHP but I can't get the same result they are achieving with their algorithm. I've been reading other related threads like this or this but couldn't find a solution. Any help?

Community
  • 1
  • 1
Sendoa
  • 4,705
  • 5
  • 27
  • 21
  • Can you post your PHP code? – Varun Madiath Apr 23 '14 at 15:27
  • That's the problem :-), I can't manage to create a PHP code to reproduce the same encryption algorithm. I've tried to use variations of the `mcrypt_encrypt()` function but I'm going nowhere. My knowledge of C# is less than decent :-( – Sendoa Apr 23 '14 at 15:51
  • I've tried to reproduce the `Encoding.UTF8.GetBytes` method with PHP's `ord()` function but I get more than 32 bytes when converting so `mcrypt_encrypt()` fails to execute because the blocksize doesn't match… :-/ – Sendoa Apr 23 '14 at 15:52
  • I seems like the default padding of RijndaelManaged is PKCS7: http://msdn.microsoft.com/en-us/library/system.security.cryptography.symmetricalgorithm.padding%28v=vs.110%29.aspx . You should use the same in your PHP code. – Perseids Apr 24 '14 at 13:06

0 Answers0