【问题标题】:.Net and PHP Rijndael encryption not matching.Net 和 PHP Rijndael 加密不匹配
【发布时间】:2011-11-15 06:28:36
【问题描述】:

起初我认为这是填充,因为 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);
}
}

VB .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

【问题讨论】:

    标签: php vb.net encryption mcrypt rijndael


    【解决方案1】:

    对于初学者,这 2 位代码将创建不同的初始化向量(PHP 使用 sha256 和 .net md5)。并且您不会在第一个空字符之前截断 PHP 输出。代码中也存在几个潜在的字符集问题。

    【讨论】:

    • 我会检查 iv 的,但应该没问题,你只是读错了代码,两边的键使用 sha 256,两边的 ivs 使用 md5
    • ivs 不一样,因为 .nets md5 以 16 字节输出 md5,而不是 php 输出的 32 字节十六进制。 .net 现在告诉我:指定的初始化向量 (IV) 与此算法的块大小不匹配。 Rijndael 块大小始终为 16 字节,因此 32 字节的十六进制 md5 不起作用
    • 我可以让 php 以 16 字节格式输出 md5,但 mcrypt 会抛出 iv 不够大的错误。当 iv 始终为 16 字节进行 rijndael 加密时,mcrypt 如何使用 32 字节的 iv?
    • 我读错了 Rijndael,支持 128、192 和 256 位的块和密钥大小,但在 AES 中,块大小始终为 128 位。 AES 标准没有采用额外的块大小。所以我将块大小更改为 256 并且它可以工作,但它们仍然不匹配
    【解决方案2】:

    你的两段代码的问题是:

    • 在 .NET 和 PHP 代码中使用 Rijndael-128 和 16 字节/128 位的密钥和块大小。对于 Rijndael-256,您的代码会生成长度错误的 IV。而且我不知道如何在PHP中使用AES-256(密钥长度为32字节/256位,块大小为16字节/128位)。

    • MD5 的使用:在 PHP 代码中,将第二个参数 true 添加到 md5() 函数(在两个位置),因此结果是二进制数据而不是十六进制字符串。

    • 在 PHP 代码的 encrypt() 函数中,将变量 $str 替换为 $decrypted(在两个位置)。 $str 从未被赋值,也从未被使用过,因此填充无效。

    如果你解决了这些问题,那么两个程序都会返回结果:

    Encrypted: /DMkj7BL9Eu2LMxKhdGT+A==
    

    我没有尝试解密它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 2014-11-30
      • 2011-05-18
      • 1970-01-01
      相关资源
      最近更新 更多