.NET WebService 加密 -> PHP 解密错误:mcrypt_encrypt(): IV 参数必须与块大小一样长

Posted

技术标签:

【中文标题】.NET WebService 加密 -> PHP 解密错误:mcrypt_encrypt(): IV 参数必须与块大小一样长【英文标题】:.NET WebService encrypt -> PHP decrypt error: mcrypt_encrypt(): The IV parameter must be as long as the blocksize in 【发布时间】:2015-05-12 05:58:42 【问题描述】:

从用 .NET 编写的 Web 服务接收参数,但我无法解密这些

参数已使用 SHA1,Rijndael 256 位加密。

php代码:

  $passphrase='16charskey';
$salt = '16charssat';
$iterations = 2;
$keysize = 32;

$key = pbkdf2($passphrase,$salt, $iterations, $keysize);
$text = 'my crypted text';
$iv = '16charsinitvector';
$result =  mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CBC, $iv)

函数 pbkdf2 是下一个

function pbkdf2( $p, $s, $c, $kl, $a = 'sha1' ) 
    $hl = strlen(hash($a, null, true)); # Hash length
    $kb = ceil($kl / $hl);              # Key blocks to compute
    $dk = '';                           # Derived key
    # Create key
    for ( $block = 1; $block <= $kb; $block ++ ) 
        # Initial hash for this block
        $ib = $b = hash_hmac($a, $s . pack('N', $block), $p, true);
        # Perform block iterations
        for ( $i = 1; $i < $c; $i ++ )
            # XOR each iterate
            $ib ^= ($b = hash_hmac($a, $b, $p, true));
        $dk .= $ib; # Append iterated block
    
    # Return derived key of correct length
    return substr($dk, 0, $kl);

当我执行时给出警告: mcrypt_encrypt():IV参数必须和

中的blocksize一样长

我测试了将 $iv 的长度更改为 32 个字符并且警告消失了。当我将字符串 $iv 更改为任何小于 32 个字符的字符串时,结果与 $iv 为空时相同。

有什么想法吗?

更新

这是加密中的WebService代码

Public Function strEncrypt( _
        ByVal strText As String _
        , ByVal strPass As String _
        , ByVal strSalt As String _
        , ByVal strHASH As String _
        , ByVal nIterations As Integer _
        , ByVal strIV As String _
        , ByVal nSize As Integer _
    ) As String

        Try
            Dim btText As Byte() = Encoding.UTF8.GetBytes(strText)
            Dim btSalt As Byte() = Encoding.UTF8.GetBytes(strSalt)
            Dim btIV As Byte() = Encoding.UTF8.GetBytes(strIV)
            Dim objPasswordDeriveBytes As PasswordDeriveBytes = New PasswordDeriveBytes(strPass, btSalt, strHASH, nIterations)
            Dim btKey As Byte() = objPasswordDeriveBytes.GetBytes(nSize / 8)
            Dim objRijndaelManaged As RijndaelManaged = New RijndaelManaged()
            objRijndaelManaged.Mode = CipherMode.CBC
            Dim objICryptoTransform As ICryptoTransform = objRijndaelManaged.CreateEncryptor(btKey, btIV)
            Dim objMemoryStream As MemoryStream = New MemoryStream()
            Dim objCryptoStream As CryptoStream = New CryptoStream(objMemoryStream, objICryptoTransform, CryptoStreamMode.Write)
            objCryptoStream.Write(btText, 0, btText.Length)
            objCryptoStream.FlushFinalBlock()
            Dim btEncrypt As Byte() = objMemoryStream.ToArray()
            objMemoryStream.Close()
            objCryptoStream.Close()
            strEncrypt = Convert.ToBase64String(btEncrypt)

        Catch ex As Exception
            strEncrypt = ""
        End Try

编辑

我将 pbkdf2 调用更改为 pbkdf1

function PBKDF1($pass, $salt, $count, $dklen)

    $t = $pass.$salt;
    $t = sha1($t, true);
    for($i=2; $i <= $count; $i++)
    
        $t = sha1($t, true);
    
    $t = substr($t,0,$dklen-1);
    return $t;

MCRYPT_RIJNDAEL_128 的算法是正确的,但是 mcrypt_encrypt 的输出和 web 服务对于相同的字符串,具有相同的盐、迭代、密钥大小、密码,是不同的......

我看不出获得不同输出的区别

【问题讨论】:

您确定 .net 网络服务使用 Rijndael 256 而不仅仅是 AES 256? IV 也必须与密文一起出现。您不能只使用任何 IV。 我不确定,我用网络服务中的 .net 代码更新了帖子,谢谢!!! 我已经回滚了最新的更改。你不应该从根本上改变问题本身。 *** 不是在线调试器。检查函数的输入/输出!例如。 PBKDF2 的输出在两个运行时都不会相同,您可以打印出十六进制值并进行比较。 对不起,你是对的。但是我在 pbkdf2(和 pbkdf1)中的两个运行时都得到相同的输出,我不知道我是否在执行中出错 已解决:此 php 代码对我有用 ***.com/a/22920556/4654981 【参考方案1】:

Artjom 是对的,您应该将MCRYPT_RIJNDAEL_256 替换为MCRYPT_RIJNDAEL_128

请注意,使用静态 IV 并不安全。然而,它比在传输协议中使用 CBC 模式加密更安全(因为没有完整性保护并且因为填充预言是可能的);只有在攻击者无法更改密文时才应使用这种方案。


在编辑之后,您还可以清楚地看到您实现了 PBKDF2 而不是PasswordDeriveBytes 提供的 PBKDF1。

【讨论】:

在此 Web 服务中,潜在的攻击者无法更改密文。但是感谢您提供的信息,我不确定,我用网络服务加密的代码更新了帖子。谢谢你,你评论我的一切都很有用 与 MCRYPT_RIJNDAEL_128 警告消失,但加密与 Web 服务不同。 Web 服务的开发人员说我是“Rijndael (AES) 256 bits”

以上是关于.NET WebService 加密 -> PHP 解密错误:mcrypt_encrypt(): IV 参数必须与块大小一样长的主要内容,如果未能解决你的问题,请参考以下文章

webservice 采用SSL实现加密传输

如何发布https的webservice

如何通过HTTPS方式访问webservice

JAVA和C# 3DES加密解密

加密许可错误

调用webservice接口,加密的WSDL怎样用wsimport命令生成客户端代码?