使用openssl_encrypt/openssl_decrypt将C# TripleDES ECB解密/加密转换为PHP

gt0wga4j  于 2022-12-02  发布在  PHP
关注(0)|答案(2)|浏览(178)

我正在尝试使用openssl_encrypt和openssl_decrypt在PHP中重新创建以下带有PKCS 7填充的TripleDES ECB的C#实现。

private static string Key = "<some random key with umlauts and special characters length of 24>";

public static string Decrypt(string cypherText)
{
    using(var des = CreateDes(Key))
    {
        var ct     = des.CreateDecryptor();
        var input  = Convert.FromBase64String(cypherText);
        var output = ct.TransformFinalBlock(input, 0, input.Length);
        return Encoding.UTF8.GetString(output);
    }
}

public static string Encrypt(string plainText)
{
    using(var des = CreateDes(Key))
    {
        var ct     = des.CreateEncryptor();
        var input  = Encoding.UTF8.GetBytes(plainText);
        var output = ct.TransformFinalBlock(input, 0, input.Length);
        return Convert.ToBase64String(output);
    }
}

private static TripleDES CreateDes(string key)
{
    MD5       md5    = new MD5CryptoServiceProvider();
    TripleDES des    = new TripleDESCryptoServiceProvider();
    var       desKey = md5.ComputeHash(Encoding.UTF8.GetBytes(key));
    des.Key     = desKey;
    des.IV      = new byte[des.BlockSize / 8];
    des.Padding = PaddingMode.PKCS7;
    des.Mode    = CipherMode.ECB;
    return des;
}

到目前为止,我已经设法弄清楚,我不得不使用PHP中md5-function的raw_output参数来获得完全相同的密钥(与C#中的breakpoint和PHP中的getByteFromString-function相比),加密/解密基本上在两端都工作。除了在C#中加密的值不能在PHP中解密,反之亦然,因为加密结果是不同的。
到目前为止,我在PHP中得到了:

function getByteFromString( $value )
{
    $ret = '';

    for($i = 0; $i < strlen($value); $i++)
    {
        $ret .= '[' . $i . '] => ' . ord($value[$i])."<br/>";
    }
    return $ret;
}

function encrypt( $key, $value )
{
    if( function_exists( 'openssl_encrypt' ) )
    {
        return base64_encode( openssl_encrypt( $value, 'DES-EDE3', $key,  OPENSSL_RAW_DATA ) );
    }

    return 'openssl missing';
}

function decrypt( $key, $value )
{
    if( function_exists( 'openssl_decrypt' ) )
    {
        return openssl_decrypt( base64_decode( $value ), 'DES-EDE3', $key, OPENSSL_RAW_DATA );
    }

    return 'openssl missing';
}

$sKey = md5("<the same random key with umlauts and special characters length of 24 as in c#>", true);
$number = '1234567890';
$encrypted = encrypt( $sKey, $number );
$decrypted = decrypt( $sKey, $encrypted );

// For key debugging only:
echo 'key:<br>' . getByteFromString($sKey) . '<br>';

echo 'encrypted: ' . var_export($encrypted, true) . '<br>';
echo 'decrypted: ' . var_export($decrypted, true). '<br>';

我知道TripleDES不应该再使用了,尤其是ECB模式,但是我不能改变C#代码,所以PHP代码必须创建与C#相同的结果,并且必须能够解密用C#加密的值,以及加密值,以便C#可以解密它们-使用TripleDES和ECB。我只是不知道我在PHP方面错过了什么。

2wnc66cl

2wnc66cl1#

好的,我通过阅读相关的问题找到了解决方案。我在一个7年前的问题中找到了它,尽管它是针对过时的mcrypt函数而提出的,但不知何故,它仍然可以使用openssl函数。
所有要做的就是把原始密钥的前8个字节附加到它本身,如下所示:

$sKey = md5("<the same random key with umlauts and special characters length of 24 as in c#>", true);
$sKey .= substr( $sKey, 0, 8 );

下面是PHP中的一个工作示例:

function encrypt( $key, $value )
{
    if( function_exists( 'openssl_encrypt' ) )
    {
        return base64_encode( openssl_encrypt( $value, 'DES-EDE3', $key,  OPENSSL_RAW_DATA ) );
    }

    return 'openssl missing';
}

function decrypt( $key, $value )
{
    if( function_exists( 'openssl_decrypt' ) )
    {
        return openssl_decrypt( base64_decode( $value ), 'DES-EDE3', $key, OPENSSL_RAW_DATA );
    }

    return 'openssl missing';
}

$sKey = md5("<the same random key with umlauts and special characters length of 24 as in c#>", true);
$sKey .= substr( $sKey, 0, 8 ); //Added this line to fix it
$number = '1234567890';
$encrypted = encrypt( $sKey, $number );
$decrypted = decrypt( $sKey, $encrypted );

echo 'encrypted: ' . var_export($encrypted, true) . '<br>';
echo 'decrypted: ' . var_export($decrypted, true). '<br>';

如果有人可以评论为什么这是解决方案,请这样做。虽然我很高兴它的工作,我真的很想了解为什么它的工作。我看不到这样的事情发生在C#,为什么我必须在PHP中这样做?

x4shl7ld

x4shl7ld2#

我认为您需要向sKey添加额外的8个字节的原因是MD5 binary参数设置为true的()函数返回长度为16的原始二进制格式(如文档https://www.php.net/manual/en/function.md5.php所示)。那么,要使tripleDES工作,需要一个24字节的密钥。在末尾加上前8个字节,总共是24个字节。这里(https://en.wikipedia.org/wiki/Triple_DES)在“密钥选项”下,你可以选择密钥选项2 - K1和K2是独立的,并且K3 = K1。有时被称为2 TDEA或双倍长度密钥。(根据维基百科)

相关问题