Использование простого текста в качестве ключа и IV в PHP mcrypt
У меня есть приложение, которое обменивается данными между приложением поставщика в шифровании TripleDES с использованием метода CBC по согласованному ключу и IV. Мое приложение представляет собой приложение VB.NET, а приложение производителя представляет собой веб-страницу PHP. Странно то, что я не могу соответствовать выводу приложения вендора.
Ключ и начальный вектор даны нам обоим в виде открытого текста. Самое смешное, что в приложении производителя они не хэшируют и не преобразуют ключ и IV в 256-битный ключ и 128-битный IV. Они просто используют формат открытого текста в своем коде, используя плагин mcrypt в PHP.
$key = 'plaintextkey';
$iv = 'plaintextIV'
$enc = mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_CBC, $iv)
И это привело к забавному тексту, такому как:
û! ‰ + "°z0"üÐÑn
Мои вопросы:
- должен ли открытый текст использоваться в качестве параметра, как PHP реализует / преобразовывает его в 256-битный символ?
- если используется метод CBC, не должен ли он зависеть от ранее зашифрованного текста?
- есть ли результат TripleDES в моем данном формате? Потому что, когда я искал в интернете и никогда не видел, в результате шифрование в такой форме.
2 ответа
должен ли открытый текст использоваться в качестве параметра, как PHP реализует / преобразовывает его в 256-битный символ?
Тройной DES и применение DES трижды с тремя (разными) ключами DES. Один ключ DES имеет длину 56 бит и 64 бит с четностью. Таким образом, ключ 3DES должен состоять из трех разных ключей DES, что должно привести к одному 192-битному ключу.
Предполагается, что ключи имеют высокую энтропию, так что потребуется перебор значительного количества пространства ключей. Если ключ является паролем, то это значительно проще, потому что пароли имеют собственный формат и ограниченный набор символов. Вот почему ключ должен быть получен из паролей. Обычно это делается с помощью PBKDF2, bcrypt или scrypt (со случайно сгенерированной солью и большим количеством итераций в тысячах или миллионах / с высокой стоимостью).
Теперь Mcrypt принял несколько сомнительных решений. Например, он с радостью принял (в более ранних версиях PHP) недопустимые ключи и IV, дополнив их 0x00 байтами до следующего допустимого размера или обрезав их до следующего допустимого размера. Вот почему использование "открытого текста" не очень хорошая идея. Это приведет к 0x00 байтов для некоторых байтов второго ключа и полных 0x00 байтов для третьего ключа.
mcrypt не используется и не должен больше использоваться. Вы можете использовать расширение OpenSSL в PHP или одну из многих хороших библиотек шифрования, таких как libsodium или defuse/php-encryption.
если используется метод CBC, не должен ли он зависеть от ранее зашифрованного текста?
Вы можете использовать последний блок зашифрованного текста в качестве IV для следующего шифрования, но это только усложняет код шифрования. Вы действительно должны использовать случайный IV каждый раз и просто добавлять его к зашифрованному тексту. Это не должно быть секретом, а скорее непредсказуемым. Вы можете хранить его вместе со случайной солью из ранее. См. Также: Зачем использовать вектор инициализации (IV)?
есть ли результат Triple DES в моем данном формате? Потому что, когда я искал в интернете и никогда не видел, в результате шифрование в такой форме.
Современные шифры (при этом сохраняющее формат шифрование является заметным исключением) создают шифротексты, которые должны быть неотличимы от случайного "шума". Таким образом, вы можете получить непечатаемые символы, такие как \x01 и многие другие, как часть зашифрованного текста. Вы хотите напечатать зашифрованный текст, затем вам нужно кодировать в какой-нибудь печатный формат, например, используя Hex или Base 64.
Спасибо ответу Artjom за упоминание о том, что вам нужно добавить несколько нулей, пока ключ и IV не достигнут длины 24 и 8 соответственно. Вот коды VB.NET на случай, если это кому-то нужно.
Dim byteKey As Byte() = System.Text.Encoding.UTF8.GetBytes("myplaintextkey")
Dim byteVector As Byte() = System.Text.Encoding.UTF8.GetBytes("myplaintextiv")
Dim base64Key As String = Convert.ToBase64String(byteKey)
Dim base64Vector As String = Convert.ToBase64String(byteVector)
Dim key As Byte() = Convert.FromBase64String(base64Key)
Dim iv As Byte() = Convert.FromBase64String(base64Vector)
Dim encryptor As SymmetricEncryptor = New SymmetricEncryptor() 'Note, this an internal library
Try
encryptor.Provider = New System.Security.Cryptography.TripleDESCryptoServiceProvider
encryptor.Encoder = System.Text.Encoding.UTF8
encryptor.Provider.Mode = CipherMode.CBC
encryptor.Provider.Padding = PaddingMode.Zeros
'Add missing zeros to key and IV
If key.Length < 24 Then
Dim i As Integer = key.Length
ReDim Preserve key(23)
While i < 24
key(i) = 0
i += 1
End While
ElseIf key.Length > 24 Then
ReDim Preserve key(23)
End If
If iv.Length < 8 Then
Dim i As Integer = iv.Length
ReDim Preserve iv(8)
While i < 8
iv(i) = 0
i += 1
End While
ElseIf iv.Length > 8 Then
ReDim Preserve iv(8)
End If
encryptor.IV = iv
encryptor.Key = key
Dim output As String = encryptor.Encrypt(output)
Console.Write(output)
Catch ex As Exception
Console.Write(ex.Message)
End Try
Надеюсь, это кому-нибудь поможет и еще раз, спасибо Артём!