【问题标题】:Decrypting in PHP a string encoded 3DES with C#在 PHP 中用 C# 解密一个字符串编码的 3DES
【发布时间】:2012-01-20 15:37:11
【问题描述】:

我必须在 PHP 中解密一个用这个 C# 类编码的字符串(它是here

使用系统; 使用 System.Security.Cryptography; 使用 System.Text; 公共静态类加密 { 公共静态字符串加密(字符串输入,字符串密钥) { byte[] inputArray = UTF8Encoding.UTF8.GetBytes(input); TripleDESCryptoServiceProvider TripleDES = new TripleDESCryptoServiceProvider(); TripleDES.Key = UTF8Encoding.UTF8.GetBytes(key); TripleDES.Mode = CipherMode.ECB; TripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = TripleDES.CreateEncryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); 三重DES.清除(); return Convert.ToBase64String(resultArray, 0, resultArray.Length); } 公共静态字符串解密(字符串输入,字符串密钥) { byte[] inputArray = Convert.FromBase64String(input); TripleDESCryptoServiceProvider TripleDES = new TripleDESCryptoServiceProvider(); TripleDES.Key = UTF8Encoding.UTF8.GetBytes(key); TripleDES.Mode = CipherMode.ECB; TripleDES.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = TripleDES.CreateDecryptor(); byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length); 三重DES.清除(); 返回 UTF8Encoding.UTF8.GetString(resultArray); } }

我尝试了在网上找到的不同示例,但似乎没有任何效果。我认为第一个问题来自 php mcrypt_generic_init 中的 $iv 参数,然后另一个问题来自 php 函数中缺少的填充。 你能帮我在PHP中转换上面的c#Decrypt函数吗? 谢谢。

【问题讨论】:

  • 如果您想尝试一个不需要mcrypt 的解决方案,并且可以让您的代码更容易移植到没有它的实例,您可以尝试phpseclib。如果 mcrypt 函数可用,这将使用它们,如果不可用,则使用内部实现。
  • IV 应该无关紧要,因为 C# 代码使用的是CipherMode.ECB(这对 IMO 来说很糟糕)。
  • @poupou 是的,IV 无关紧要,ECB 只能用于无法与随机数据区分开来的纯文本(例如其他安全生成的密钥)
  • Pons,不要设置 IV,它不应该出现在 ECB 模式中,并且一个糟糕的实现可能会 XOR 第一个纯文本块与给定的 IV。不过,您最好切换到 CBC 并使用 IV,它也可能与实现之间更兼容(因为在我在 stackoverflow 上看到的大多数描述中,ECB 都是不安全的)。

标签: php encryption 3des tripledes


【解决方案1】:

因为在 ECB 模式下 IV 无关紧要,我们可以忽略它。但是,mcrypt 不是很宽松。我们仍然需要提供一个 IV,即使它是假的。

// We'll be encrypting this data
    $key = 'password';
    $data = 'The quick brown fox jumped over the lazy dogs.';
    $encrypted = null;

// 3des in ECB mode
    $m = mcrypt_module_open(MCRYPT_3DES, null, MCRYPT_MODE_ECB, null);
// Our IV will be enough NUL bytes to satisfy mcrypt.
    $fake_iv = str_repeat(chr(0), mcrypt_enc_get_iv_size($m));
    mcrypt_generic_init($m, $key, $fake_iv);
    $encrypted = mcrypt_generic($m, $data);
// "s/6HOXpVyMyFdSPYUgIgneMRY0o3Kubkwc++hSg9kC4Sw0TWsNTqzrhXY3z4PH9w"
    echo base64_encode($encrypted), "\n";
    unset($m);

// And now, in reverse!
    $n = mcrypt_module_open(MCRYPT_3DES, null, MCRYPT_MODE_ECB, null);
// Another fake IV
    $fake_iv = str_repeat(chr(0), mcrypt_enc_get_iv_size($n));
    mcrypt_generic_init($n, $key, $fake_iv);
    $original = mdecrypt_generic($n, $encrypted);
// string(48) "The quick brown fox jumped over the lazy dogs."
    var_dump($original);

同样,如果您坚持使用 ECB 模式,您只会想要这样做。欧洲央行模式可能非常糟糕。您可能需要查看the Wikipedia article on block cipher modes 了解更多信息。

这里唯一没有处理的是填充。 mcrypt 不允许您选择填充方法,并且会根据密码执行不同的操作。通常,它根本不添加任何填充。

如果您选择的填充方法使用 NUL 字节,您需要自己预先填充数据以确保互操作性。您可以使用 mcrypt_get_block_sizestr_padSTR_PAD_RIGHT 选项来执行此操作。

同样,您可能需要在解密后从右侧修剪 NUL 字节。 trim 的第二个参数会有所帮助。

【讨论】:

  • Charles 做了正确的事情,将 IV 设置为值为 00h 的字节,并使用适当的函数来确定字节数。在 CBC 模式下,纯文本与 IV 向量进行异或,并且与 00h 值字节进行异或不会改变纯文本。因此,即使 IV 将被底层代码使用,将其输入零也不会受到影响。
【解决方案2】:

即使我今天尝试了 PHP 和 C# 的代码

<?php
$key64 = "YOUR_KEY";
$iv64 = "YOUR_IV";


$keybytes = base64_decode($key64);
$ivbytes = base64_decode($iv64);

$text = ("4111111111111111");

// Padding the text
$padding = strlen($text)%8;
for($i=$padding; $i<8; $i++){
   $text .= chr(8-$padding);
}

$decryptRaw = mcrypt_encrypt(MCRYPT_3DES, $keybytes, $text, MCRYPT_MODE_CBC, $ivbytes);
$encoded = base64_encode($decryptRaw);

print "$encoded<br/>";
$encryptedString64 = $encoded;
$decryptbytes = base64_decode($encryptedString64);

$decryptRaw = mcrypt_decrypt(MCRYPT_3DES, $keybytes, $decryptbytes, MCRYPT_MODE_CBC, $ivbytes);
$decryptString=trim($decryptRaw,"\x00..\x1F");
print "$decryptString<br/>";

?>

C#

private string Decrypt(string encryptedValue)
{
    SymmetricAlgorithm tripleDESKey = SymmetricAlgorithm.Create("TripleDES") ;
    tripleDESKey.Key = Convert.FromBase64String("YOUR_KEY");
    tripleDESKey.IV = Convert.FromBase64String("YOUR_IV") ;

    MemoryStream encryptedStream = new MemoryStream();
    encryptedStream.Write(Convert.FromBase64String(encryptedValue), 0,
    Convert.FromBase64String(encryptedValue).Length);
    encryptedStream.Position = 0;
    CryptoStream cs = new CryptoStream(encryptedStream,
    tripleDESKey.CreateDecryptor(), CryptoStreamMode.Read);
    MemoryStream decryptedStream = new MemoryStream();

    byte[] buf = new byte[2049];
    int bytesRead = 0;
    bytesRead = cs.Read(buf, 0, buf.Length);
    while ((bytesRead > 0))
    {
        decryptedStream.Write(buf, 0, bytesRead);
        bytesRead = cs.Read(buf, 0, buf.Length);
    }
    return Encoding.ASCII.GetString(decryptedStream.ToArray());
}
private string Encrypt(string encrypt)
{
    SymmetricAlgorithm sa = SymmetricAlgorithm.Create("TripleDES") ;
    sa.Key = Convert.FromBase64String("YOUR_KEY");
    sa.IV = Convert.FromBase64String("YOUR_IV") ;
    byte[] inputByteArray = Encoding.ASCII.GetBytes(encrypt);
    MemoryStream mS = new MemoryStream();
    ICryptoTransform trans = sa.CreateEncryptor();
    byte[] buf = new byte[2049];
    CryptoStream cs = new CryptoStream(mS, trans, CryptoStreamMode.Write);
    cs.Write(inputByteArray, 0, inputByteArray.Length);
    cs.FlushFinalBlock();
    return Convert.ToBase64String(mS.ToArray());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    • 2016-06-03
    • 2010-09-18
    • 1970-01-01
    相关资源
    最近更新 更多