【问题标题】:Decrypt string in C# encrypted in PHP (Blowfish)解密用 PHP 加密的 C# 中的字符串(Blowfish)
【发布时间】:2025-12-21 23:05:12
【问题描述】:

我在尝试解密 C# 中的一些在 PHP 中加密的值时遇到了困难。 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 模式,IV 可能没有使用它,但这仍然没有帮助。最大的问题是 PHP 文档太差了,并且没有指定函数使用什么编码!传递的字符串根据编码具有不同的字节值,最终加密(在本例中为 Blowfish)处理字节。

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

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

更新

我用 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,任何值我传递的结果都是一样的。

【问题讨论】:

  • 由于 mcrypt 已被弃用,由于在 PHP 7.2 中被删除,我可能会废弃它并重新开始......
  • 看来这个帖子可以帮到你! *.com/questions/18681526/php-mcrypt-encrypt-to-net
  • 您能否添加一个完整的示例(加密的 base64 文本、密码和原始纯文本)?
  • 很多人都成功了 - 我每周至少会看到几次这个问题的变化(不是特别是河豚)。
  • @CD001 在 PHP 端使用什么我别无选择。我只能控制C#端

标签: c# php encryption cryptography blowfish


【解决方案1】:

好吧,你的问题不是c#中的河豚解密部分,而是php中的加密部分。不,这不是关于使用 mcrypt_encrypt,在已经 utf8 编码的字符串上调用 utf8_encode 是错误的......

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

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

调试c#解密函数的第二次调用,看看Encoding.UTF8.GetBytes产生的第一个str1的结果。它是正确的,没有字符集的来回转换。

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();
}

【讨论】:

  • 实际上对 utf8_encode() 的调用并没有改变任何东西。我在 PHP 中对其进行了测试,无论有没有那个调用,结果都是一样的。正如我所说,我无法控制 php 部分。
  • @Albert 好吧,在我的测试环境中,删除utf8_encode 我能够在没有这种编码舞蹈(utf8 -> iso8859-1 -> utf8)的情况下解密数据。仅当要加密的数据包含更高的字符(例如我的示例中的欧元符号“€”)时,这才会起作用。是的,我知道你不控制 php 部分(你不止一次说过;)),我只是想表明这不是你的错或加密库的问题,因为解密数据很难,因为加密过程本来可以更好...
  • 这不是我的错,但我必须解决这个问题。同意加密本来可以更好,但我尝试过的一些库也很糟糕并且存在问题(至少它们在加密库中使用错误的字符串)
  • 澄清一下(我的回答如下): - 请注意您选择的库。我确实使用了github.com/b1thunt3r/blowfish-csharp - 如果库直接使用字符串,它可能是一个坏的。在任何情况下,只使用与字节一起工作的重载。 - 与不同平台打交道时,尽量说服对方使用base64编码。
【解决方案2】:

最后还是能做到的。几点建议:

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

  • 切勿使用直接处理字符串的方法。首先在任何库中提供这都是愚蠢的(即使是上面的那个也有与字符串一起使用的重载,并且它“假设”字符串是 Unicode 的!)

  • 在与不同平台打交道时,尽量说服对方使用base64编码。

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

【讨论】:

  • 1.不要使用 PHP mcrypt,它已被弃用并且不支持标准填充方法。 2、不要在新代码中使用Blowfish,它不是特别安全,注意作者没有使用它,使用AES。 3. 很多 CPU 都有直接支持 AES 的指令(AES-NI)。
  • @zaph 多次解释说我不控制 PHP 部分。我必须解密我在 .NET 中得到的内容
  • 解决问题了吗?似乎是。知道问题的真正原因吗?可能。但我不知道一个接受字符串作为参数的好的加密/解密库。 BouncyCastle 和微软都没有。
  • 我投了反对票,因为未经证实的陈述:“C# 中的一些 Blowfish 库似乎有糟糕的实现。” 1.“一些”含糊不清,无用。 2.“似乎执行不好”是模糊的,最好的猜测是你不能让它们在你的情况下工作。 3. 没有描述解决了什么问题。 4.除此之外,答案中还有一些优点。 5. 实际答案是指向适合您的实现的链接。 6. 反对使用 mcrypt 和 Blowfish 的信息面向未来的读者。
  • @LW001 首先我应该是准确的,然后是好的。在任何情况下都采取了