在 PHP 的 mcrypt 中使用纯文本作为密钥和 IV

Using plain text as key and IV in PHP's mcrypt

我有一个应用程序,它使用 CBC 方法根据商定的密钥和 IV 在供应商的应用程序之间交换数据。我的应用程序是 VB.NET 应用程序,而供应商的应用程序是 PHP 网页。奇怪的是,我似乎无法匹配供应商应用程序的输出。

密钥和初始向量以明文形式提供给我们双方。有趣的是,在供应商的应用程序中,他们不会将密钥和 IV 散列或转换为 256 位密钥和 128 位 IV。他们只是在代码中使用明文格式,使用 PHP 中的 mcrypt 插件。

$key = 'plaintextkey';
$iv = 'plaintextIV'
$enc = mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_CBC, $iv)

它产生了一个有趣的文本,例如:

û!‰+«°z0"üÐÑn

我的问题是:

  1. 是否应该使用明文作为参数,如何PHP implement/convert它变成一个256位的字符?
  2. 如果使用CBC方法,是不是应该依赖于之前的 加密文本?
  3. 我给定的格式是否有 TripleDES 结果?因为像我 通过互联网搜索,我从来没有看到结果 以这种形式加密。

should a plaintext be used as a parameter, how does PHP implement/convert it into a 256 bit character?

Triple DES 是使用三个(不同的)DES 密钥应用三次 DES。一个 DES 密钥是 56 位长和 64 位奇偶校验。因此,一个 3DES 密钥应该由三个 不同的 DES 密钥组成,这应该会产生一个 192 位密钥。

密钥应该具有高熵,因此有必要暴力破解相当数量的密钥 space。如果密钥是密码,那么这就容易多了,因为密码有固有的格式和有限的字符集。这就是为什么密钥需要从密码中派生出来的原因。这通常使用 PBKDF2、bcrypt 或 scrypt(使用随机生成的盐和数千次或 millions/high 成本因子的大量迭代)完成。

现在,mcrypt 做出了一些有问题的决定。例如,它愉快地接受(在早期 PHP 版本中)无效密钥和 IV,方法是用 0x00 字节填充它们到下一个有效大小或将它们裁剪到下一个有效大小。这就是为什么使用 "plaintextkey" 不是一个好主意。它将导致第二个密钥的某些字节为 0x00 字节,第三个密钥为完整的 0x00 字节。

mcrypt 是废弃软件,不应再使用。 您可以使用 PHP 中的 OpenSSL 扩展或许多优秀的加密库之一,如 libsodium 或 defuse/php-encryption.

if CBC method is used, shouldn't it depend on the previously encrypted text?

您可以使用最后一个密文块作为下一次加密的IV,但这只会使加密代码复杂化。您确实应该每次都使用随机 IV,并将其简单地添加到密文中。它不必是秘密的,而是不可预测的。您可以将它与之前的随机盐一起存放。另见:Why use an Initialization Vector (IV)?

is there a TripleDES result in my given format? Because as I searched through the internet and never have I seen a resulted encryption in such form.

现代密码(保留格式的加密是一个明显的例外)产生的密文应该是 indistinguishable from random "noise"。因此,您可能会收到不可打印的字符,例如 \x01 等,作为密文的一部分。你想打印密文,然后你需要编码成一些可打印的格式,例如使用十六进制或 Base 64。

感谢Artjom 的回答中提到您需要添加几个0,直到key 和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

希望对大家有所帮助,再次感谢 Artjom!