Конвертировать C# TripleDES ECB расшифровать / зашифровать в PHP с openssl_encrypt / openssl_decrypt - PullRequest
2 голосов
/ 31 марта 2020

Я пытаюсь воссоздать следующую C# реализацию TripleDES ECB с дополнением PKCS7 в PHP с использованием openssl_encrypt и openssl_decrypt.

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

Пока мне удалось выяснить, что я пришлось использовать параметр raw_output функции md5 в PHP, чтобы получить точно такой же ключ (по сравнению с точкой останова в C# и функцией getByteFromString в PHP), и шифрование / дешифрование в основном работает с обеих сторон. За исключением того, что значения, зашифрованные в 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 стороне.

1 Ответ

0 голосов
/ 31 марта 2020

Хорошо, так что я нашел решение, прочитав связанные вопросы. Я нашел его в 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?

...