Шифрование .Net и PHP Rijndael не соответствует

Сначала я подумал, что это заполнение, так как mcrypt использует нулевое заполнение, но я изменил php, чтобы использовать PKCS7, и получил те же точные результаты.

Кто-нибудь может помочь? Я думаю, что это как-то связано с отступами в php

Тестовый вывод из .Net:

Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
Encrypted after base64 decode: ?3$??K?K?,?J???
Decrypted: Testing123

Тестовый вывод из PHP:

Key: d88f92e4fa27f6d45b49446c7fc76976
Text: Testing123
Encrypted: K+ke5FNI5T6F6B/XvDF494+S8538Ze83cFz6v1FE89U=
Encrypted after base64 decode: +éäSHå>…è×¼1x÷’óüeï7p\ú¿QDóÕ
Decrypted: Testing123����������������������

PHP:

class rijndael{
var $mcrypt_cipher = MCRYPT_RIJNDAEL_256;
var $mcrypt_mode = MCRYPT_MODE_CBC;
function decrypt($pass, $encrypted)
{
    $encrypted = base64_decode($encrypted);
    $key = $this->getkey($pass);
    $iv = $this->getiv($pass);
    $decrypted = mcrypt_decrypt($this->mcrypt_cipher, $key, $encrypted, $this->mcrypt_mode, $iv);

    $block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
    $pad = ord($decrypted[($len = strlen($decrypted)) - 1]);
    return substr($decrypted, 0, strlen($decrypted) - $pad);

}
function encrypt($pass, $decrypted)
{
    $key = $this->getkey($pass);
    $iv = $this->getiv($pass);
    $block = mcrypt_get_block_size($this->mcrypt_cipher, $this->mcrypt_mode);
    $pad = $block - (strlen($str) % $block);
    $str .= str_repeat(chr($pad), $pad);
    $encrypted = mcrypt_encrypt($this->mcrypt_cipher, $key, $decrypted, $this->mcrypt_mode, $iv);
    return base64_encode($encrypted);
}
function getkey($passphrase)
{
    $L1 = base64_encode(hash("sha256", $passphrase, true));
    $L2 = $passphrase.$L1;
    return hash("sha256", $L2, true);
}
function getiv($passphrase)
{
    $L1 = base64_encode(md5($passphrase));
    $L2 = $passphrase.$L1;
    return md5($L2);
}
}

ВБ .Net:

Public Class RijnDael

    Public Shared Function Decrypt(ByVal sData As String, ByVal sKey As String)
        Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
        Return Decrypt(bytData, sKey)
    End Function
    Public Shared Function Decrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
        Dim bytResult As Byte()
        Using oRM As New System.Security.Cryptography.RijndaelManaged
            oRM.KeySize = 256
            oRM.Key = GeKey(strPass)
            oRM.IV = GetIV(strPass)
            oRM.Mode = CipherMode.CBC
            oRM.Padding = PaddingMode.PKCS7
            Using oMS As New MemoryStream(bytData)
                Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateDecryptor, Security.Cryptography.CryptoStreamMode.Read)
                    Dim TempDecryptArr As Byte()
                    ReDim TempDecryptArr(bytData.Length)
                    Dim decryptedByteCount As Integer
                    decryptedByteCount = oCS.Read(TempDecryptArr, 0, bytData.Length)
                    '
                    ReDim bytResult(decryptedByteCount)
                    Array.Copy(TempDecryptArr, bytResult, decryptedByteCount)
                    '
                    oCS.Close()
                End Using
                oMS.Close()
            End Using
        End Using
        Return bytResult
    End Function

    Public Shared Function Encrypt(ByVal sData As String, ByVal sKey As String)
        Dim bytData() As Byte = Encoding.UTF8.GetBytes(sData)
        Return Encrypt(bytData, sKey)
    End Function
    Public Shared Function Encrypt(ByVal bytData As Byte(), ByVal strPass As String) As Byte()
        Dim bytResult As Byte()
        Using oRM As New Cryptography.RijndaelManaged
            oRM.KeySize = 256
            oRM.Key = GeKey(strPass)
            oRM.IV = GetIV(strPass)
            oRM.Mode = CipherMode.CBC
            oRM.Padding = PaddingMode.PKCS7
            Using oMS As New MemoryStream
                Using oCS As New Cryptography.CryptoStream(oMS, oRM.CreateEncryptor, Cryptography.CryptoStreamMode.Write)
                    oCS.Write(bytData, 0, bytData.Length)
                    oCS.FlushFinalBlock()
                    bytResult = oMS.ToArray()
                    oCS.Close()
                End Using
                oMS.Close()
            End Using
        End Using
        Return bytResult
    End Function

    Private Shared Function GeKey(ByVal strPass As String) As Byte()
        Dim bytResult As Byte()
        'Generate a byte array of required length as the encryption key.
        'A SHA256 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
        Using oSHA256 As New Cryptography.SHA256Managed
            Dim L1 As String = System.Convert.ToBase64String(oSHA256.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
            Dim L2 As String = strPass & L1
            bytResult = oSHA256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
            oSHA256.Clear()
        End Using
        Return bytResult
    End Function

    Private Shared Function GetIV(ByVal strPass As String) As Byte()
        Dim bytResult As Byte()
        'Generate a byte array of required length as the iv.
        'A MD5 hash of the passphrase has just the required length. It is used twice in a manner of self-salting.
        Using oMD5 As New Cryptography.MD5CryptoServiceProvider
            Dim L1 As String = System.Convert.ToBase64String(oMD5.ComputeHash(Encoding.UTF8.GetBytes(strPass)))
            Dim L2 As String = strPass & L1
            bytResult = oMD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(L2))
            oMD5.Clear()
        End Using
        Return bytResult
    End Function

End Class

person user940427    schedule 12.09.2011    source источник


Ответы (2)


Проблемы в ваших двух частях кода:

  • Используйте Rijndael-128 с ключом и размером блока 16 байт / 128 бит как в коде .NET, так и в коде PHP. Для Rijndael-256 ваш код генерирует IV неправильной длины. И я не знаю, как использовать AES-256 в PHP (длина ключа 32 байта/256 бит, размер блока 16 байт/128 бит).

  • Использование MD5: в коде PHP добавьте второй параметр true к функции md5() (в двух местах), чтобы результатом были двоичные данные, а не шестнадцатеричная строка.

  • В функции encrypt() в вашем PHP-коде замените переменную $str на $decrypted (в двух местах). $str никогда не присваивается значение и никогда не используется, поэтому заполнение не имеет значения.

Если исправить эти проблемы, то обе программы вернут результат:

Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==

Я не пытался его расшифровать.

person Codo    schedule 12.09.2011

Для начала 2 бита кода создадут разные векторы инициализации (PHP использует sha256 и .net md5). И вы не усекаете вывод PHP до первого нулевого символа. В коде также есть несколько потенциальных проблем с набором символов.

person symcbean    schedule 12.09.2011
comment
Я проверю iv, но они должны быть в порядке, вы просто неправильно прочитали код, ключи с обеих сторон используют sha 256, а iv с обеих сторон используют md5 - person user940427; 12.09.2011
comment
IVs не были одинаковыми, потому что .nets md5 выводит md5 в 16 байтах вместо 32-байтового шестнадцатеричного числа, которое выдает php. .net теперь говорит мне: указанный вектор инициализации (IV) не соответствует размеру блока для этого алгоритма. размер блока Rijndael всегда равен 16 байтам, поэтому 32-байтовый шестнадцатеричный md5 не будет работать. - person user940427; 12.09.2011
comment
Я могу заставить php выводить md5 в 16-байтовом формате, но mcrypt выдает ошибку, что тогда iv недостаточно велик. как mcrypt использует 32-байтовый iv, когда iv всегда составляет 16 байтов для шифрования rijndael? - person user940427; 12.09.2011
comment
Я неправильно прочитал Rijndael, поддерживает размеры блоков и ключей 128, 192 и 256 бит, но в AES размер блока всегда 128 бит. Дополнительные размеры блоков не были приняты стандартом AES. Поэтому я изменил размер блока на 256, и он работает, но они все еще не совпадают. - person user940427; 12.09.2011