解密在PHP中加密的C#中的数据时如何修复无效密钥大小

问题描述:

I am trying to solve an encryption issue I am having between php and c#.

I have encrypted data using the following php and openssl operation.

$encrypt_method = "AES-256-CBC";
$secret_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$secret_iv = 'XXXXXXXXXXXXXXXX';

$key = hash ('sha256', $secret_key);
$iv = substr (hash ('sha256', $secret_iv), 0, 16);

$output = openssl_encrypt ($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode ($output);

I have tried a couple of methods in C# to decrypt but this is what I am trying now.

public string Encrypt_Decrypt(string action, string value) {
    string secretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
    string secretIV = "XXXXXXXXXXXXXXXX";

    string key = Hash(secretKey);

    string iv = Hash(secretIV).Substring(0,16);

    string retValue = "";

    if (action == "encrypt") {
        retValue = EncryptString(value, key, iv);
    }
    else if (action == "decrypt") {
        retValue = DecryptString(value, key, iv);
    }
}

// Hash to match php hash function
public static string Hash(string unhashedString) {
    return BitConverter.ToString(new SHA256CryptoServiceProvider().ComputeHash(Encoding.Default.GetBytes(unhashedString))).Replace("-", String.Empty).ToLower();
}

    public static string DecryptString(string cipherData, string keyString, string ivString) {
        byte[] key = Encoding.UTF8.GetBytes(keyString);
        Console.WriteLine(key.Length);
        byte[] iv = Encoding.UTF8.GetBytes(ivString);
        Console.WriteLine(iv.Length);
        byte[] cipherCrypt = Convert.FromBase64String(cipherData);


        for (int i = 0; i < cipherCrypt.Length; i++) {
            Console.Write(cipherCrypt[i] + " ");
        }


        try {
            RijndaelManaged crypto = new RijndaelManaged();
            crypto.Key = key;
            crypto.IV = iv;
            crypto.Mode = CipherMode.CBC;
            crypto.KeySize = 256;
            crypto.BlockSize = 128;
            crypto.Padding = PaddingMode.None;

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

            using (MemoryStream memStream = new MemoryStream(cipherCrypt)) {
                using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read)) {
                    using (StreamReader streamReader = new StreamReader(cryptoStream)) {
                        return streamReader.ReadToEnd();
                    }
                }
            }
        }
        catch (CryptographicException e) {
            Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
            return null;
        }
    }

I have tried a couple different encoding types when getting the byte[] for the operation.

I keep getting the following error:

Specified key is not a valid size for this algorithm.

Not sure what I am missing. Any help is appreciated.

Also, I already read through this and tried what the solution suggestion recommended. I got the same resulting error.

UPDATE - 01 I have updated the code here to reflect the code I have changed.

The key length is 32,

The iv length is 16,

The data coming in at "cipherData" is length 32,

When "cipherData" goes through "FromBase64String(cipherData)" it comes out as a 24 byte array. This is causing an issue for the decryptor which wants a 32 byte array.

There are obviously problems with the key size. The code between PHP and C# seem to match. The problem seems to be that the code is wrong in both cases.

Let's see how long the key actually is:

  1. Start with a 32 byte key (non-encoded).
  2. Hash the key with SHA-256: 32 bytes (non-encoded).
  3. Encode to hex (integrated into PHP's hash() function by default): 64 bytes.

AES only supports the following key sizes: 16, 24 and 32 bytes. openssl_encrypt() will only use the first 32 bytes of the hex key silently. So, you need to use the first 32 bytes in C#.

Note that openssl_encrypt() takes an options argument which denotes that the output is Base64 when OPENSSL_RAW_DATA is not set. It means that the PHP output was encoded twice with Base64. So you need to decode it twice in C#.