用PHP加密C#中的解密字符串(Blowfish)

时间:2017-11-08 15:35:50

标签: c# php encryption cryptography blowfish

我正在努力解密用PHP加密的C#中的某些值。 PHP中的加密使用以下方法完成:

function encrypt($pure_string, $encryption_key) {
  $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  $iv = 'fÔdñá1f¦';
  $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
  $encrypted_string = base64_encode($encrypted_string);
  return $encrypted_string;
}

由于使用了ECB模式,可能它没有被使用,但仍然无济于事。最大的问题是PHP文档很差,并没有指定函数使用的编码!传递的字符串具有不同的字节值,具体取决于编码,最后加密(在本例中为Blowfish)处理字节。

在不知道编码的情况下,我只是在我的C#代码中尝试不同的编码,但没有成功。在某处,我读到PHP正在使用内部“iso-8859-1”编码,但即便如此,它也无法正常工作。

有没有人成功地使用愚蠢的函数mcrypt_encrypt()在C#中解密一些用PHP加密的值?

更新

我在PHP中做了一个例子。代码:

define("ENCRYPTION_KEY", "1234asdf");
define("IV", "1#^ÊÁñÔ0");

$clearText = "abc";

function encrypt($pure_string, $encryption_key, $iv) {
  $iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
  $encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
  $encrypted_string = base64_encode($encrypted_string);
  return $encrypted_string;
}

$encrypted_string = encrypt($clearText, ENCRYPTION_KEY, IV);

echo "Key:" . ENCRYPTION_KEY . "<br />";
echo "IV:" . IV . "<br />";
echo "Clear Text:" . $clearText . "<br />";
echo "Encrypted Text:" . $encrypted_string . "<br />";

结果是:

Key:1234asdf
IV:1#^ÊÁñÔ0
Clear Text:abc
Encrypted Text:OiZ6QIdhXYk=

我也确认没有使用IV,我传递结果的任何值都是相同的。

2 个答案:

答案 0 :(得分:0)

嗯,你的案例中的问题不是 c#中的blowfish解密部分,它是php中的加密部分。不,这不是关于使用mcrypt_encrypt,在已经使用utf8编码的字符串上调用utf8_encode是错误的...

我创建的解密功能使用BouncyCastle。有两个加密的字符串,第一个是使用您发布的php函数创建的,第二个是我删除了utf8_encode内的mbcrypt_encrypt调用。

第一个示例使用(坏)php_utf8_encoded字符串,我们需要来回转换解密的字节数组以获得正确的结果。

调试c#decryption函数的第二次调用,并查看str1生成的第一个Encoding.UTF8.GetBytes的结果。它是正确的,没有charset的来回转换。

public static string BlowfishDecrypt(string encrypted, string key)
{
    var cipher = new BufferedBlockCipher(new BlowfishEngine());
    var k = new KeyParameter(Encoding.UTF8.GetBytes(key));
    cipher.Init(false, k);

    var input = Convert.FromBase64String(encrypted);
    var length = cipher.GetOutputSize(input.Length);
    var block = new byte[length];
    var len = cipher.ProcessBytes(input, 0, input.Length, block, 0);
    var output = cipher.DoFinal(block, len);

    // dont know how we get the real length of the content here... but this will do it. But I am sure there is a better way...
    var idx = Array.IndexOf(block, (byte)0);
    var str1 = Encoding.UTF8.GetString(block, 0, idx);
    var raw1 = Encoding.GetEncoding("iso-8859-1").GetBytes(str1);
    var str2 = Encoding.UTF8.GetString(raw1);

    return str2;
}

static string original = "@€~>|";
static string encrypted_with_utf8_encode = "7+XyF+QGcA8lz5AQlLf1FA==";
static string encrypted_without = "3oWsAOEF+Kc=";
static string key = "t0ps3cr3t";

public static void Main()
{
    var decrypted1 = BlowfishDecrypt(encrypted_with_utf8_encode, key);
    var decrypted2 = BlowfishDecrypt(encrypted_without, key);
    var same = original.Equals(decrypted1);
    Debugger.Break();
}

答案 1 :(得分:-1)

最终能够做到了。一些指示:

  • C#中的一些Blowfish库似乎有不好的实现。正常工作的是https://github.com/b1thunt3r/blowfish-csharp

  • 永远不要使用直接处理字符串的方法。这在任何库中提供的第一个位置都是愚蠢的(即使是上面的那个也有使用字符串的重载,它“假设”字符串是Unicode格式!)

  • 在处理不同平台时,请尝试说服对方使用base64编码。

最后,我感到惊讶的是,为什么这么多的开发人员(甚至是开发加密库的开发人员)都没有得到它在没有指定编码的情况下使用字符串是愚蠢的并且没有任何意义!