【问题标题】:WP: AesManaged encryption vs. mcrypt_encryptWP:AesManaged 加密与 mcrypt_encrypt
【发布时间】:2011-12-28 07:18:06
【问题描述】:

我正在尝试在 C# 和 PHP 之间同步我的加密和解密方法,但似乎出了点问题。

在 Windows Phone 7 SDK 中,您可以使用 AESManaged 来加密您的数据

我使用以下方法:

    public static string EncryptA(string dataToEncrypt, string password, string salt)
    {
        AesManaged aes = null;
        MemoryStream memoryStream = null;
        CryptoStream cryptoStream = null;

        try
        {
            //Generate a Key based on a Password, Salt and HMACSHA1 pseudo-random number generator 
            Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));

            //Create AES algorithm with 256 bit key and 128-bit block size 
            aes = new AesManaged();
            aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
            aes.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // rfc2898.GetBytes(aes.BlockSize / 8);

            // to check my results against those of PHP
            var blaat1 = Convert.ToBase64String(aes.Key);
            var blaat2 = Convert.ToBase64String(aes.IV);

            //Create Memory and Crypto Streams 
            memoryStream = new MemoryStream();
            cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write);

            //Encrypt Data 
            byte[] data = Encoding.Unicode.GetBytes(dataToEncrypt);
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();

            //Return Base 64 String 
            string result = Convert.ToBase64String(memoryStream.ToArray());

            return result;
        }
        finally
        {
            if (cryptoStream != null)
                cryptoStream.Close();

            if (memoryStream != null)
                memoryStream.Close();

            if (aes != null)
                aes.Clear();
        }
    }

我解决了生成密钥的问题。 Key 和 IV 与 PHP 端的类似。但是加密的最后一步出错了。

这是我的 PHP 代码

<?php

function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') {

    // experimentally determine h_len for the algorithm in question
     static $lengths;
     if (!isset($lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); }
    $h_len = $lengths[$algo];

    if ($dk_len > (pow(2, 32) - 1) * $h_len) {
         return false; // derived key is too long
     } else {
         $l = ceil($dk_len / $h_len); // number of derived key blocks to compute
         $t = null;
         for ($i = 1; $i <= $l; $i++) {
             $f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate
             for ($j = 1; $j < $c; $j++) {
                 $f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate
             }
             $t .= $f; // concatenate blocks of the derived key
         }
         return substr($t, 0, $dk_len); // return the derived key of correct length
     }

}


$password = 'test';
$salt = 'saltsalt';
$text = "texttoencrypt";

#$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
#echo $iv_size . '<br/>';
#$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
#print_r (mcrypt_list_algorithms());

$iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

$key = pbkdf2($password, $salt, 1000, 32);
echo 'key: ' . base64_encode($key) . '<br/>';
echo 'iv: ' . base64_encode($iv) . '<br/>';

echo '<br/><br/>';

function addpadding($string, $blocksize = 32){
     $len = strlen($string);
     $pad = $blocksize - ($len % $blocksize);
     $string .= str_repeat(chr($pad), $pad);
     return $string;
 }

echo 'text: ' . $text . '<br/>';
echo 'text: ' . addpadding($text) . '<br/>';

// -- works till here

$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);

echo '1.' . $crypttext . '<br/>';
$crypttext = base64_encode($crypttext);
echo '2.' . $crypttext . '<br/>';

$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, addpadding($text), MCRYPT_MODE_CBC, $iv);

echo '1.' . $crypttext . '<br/>';
$crypttext = base64_encode($crypttext);
echo '2.' . $crypttext . '<br/>';

?>

需要指出的是,Key 和 IV 在 .NET 和 PHP 上看起来很相似,但在执行 mcrypt_encrypt() 时的最终调用中似乎出现了问题。最终结果,加密字符串,与 .NET 不同。

谁能告诉我我做错了什么。据我所知,一切都应该是正确的。

谢谢!

编辑:

.NET 中 AESManaged 对象的其他信息

密钥大小 = 256 模式 = CBC 填充 = PKCS7

【问题讨论】:

  • 似乎出错了是什么意思?您收到错误消息吗?你得到不同的结果吗? (这是正常的,如果 IV 是随机的。)你不能再次解密吗?还有什么?
  • 嗨 Paulo,最终结果,加密字符串,在 PHP 和 .NET 之间有所不同,但我几乎可以肯定我输入了正确的密钥和 IV(以及要加密的文本)。希望能多解释一点。

标签: php windows-phone-7 encryption aes


【解决方案1】:

MCRYPT_RIJNDAEL_256 是块大小为 256 位的 Rijndael 算法的版本,而 AES 只是块大小为 128 位的版本。这些不兼容。

使用MCRYPT_RIJNDAEL_128,得到一个等效于AES的算法。它仍然支持标准化为 AES 的所有三种密钥大小,即 128 位(16 字节)、196 位(24 字节)和 256 位(32 字节)。只需传递足够长的字符串作为键。

【讨论】:

  • 我切换到 MCRYPT_RIJNDAEL_128 并且我的密钥大小是 32 位。 .NET 和 PHP 之间匹配的密钥相同,但 mcrypt_encrypt 的最终结果仍然与 .NET 上加密的最终结果不匹配。我正在使用以下输入: $text = "this is my text"; $password = '这是我的密码这是我的密码'; $salt = 'thisismysalt'; IV 和 KEY 的 base64_encode 字符串在两个系统上看起来相似。任何其他想法可能会出现什么问题?感谢您的宝贵时间!
  • “看起来相似”还是“相同”?
  • 您确定在 .NET 端使用的是 256 位版本吗?我在您的代码中没有看到任何设置密钥大小的内容(documentation 没有说明默认值)。
  • 它们的密钥和 IV 在两个系统上都是相同的。我用 .NET 上的 AESManaged 对象的详细信息更新了帖子(底部)。
  • 还有一个想法:修正你的 PHP addpadding 函数的块大小,它应该是 16,而不是 32。
【解决方案2】:

我解决了问题。您需要确保对字符串使用 UTF8 编码并且使用正确的填充 (PKCS7)

代码如下:

    public static string EncryptA(string dataToEncrypt, string password, string salt)
    {
        AesManaged aes = null;
        MemoryStream memoryStream = null;
        CryptoStream cryptoStream = null;

        try
        {
            //Generate a Key based on a Password, Salt and HMACSHA1 pseudo-random number generator 
            Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));

            //Create AES algorithm with 256 bit key and 128-bit block size 
            aes = new AesManaged();
            aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
            aes.IV = Encoding.UTF8.GetBytes("AAAAAAAAAAAAAAAA"); // new byte[] { 0x41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // rfc2898.GetBytes(aes.BlockSize / 8);

            //Create Memory and Crypto Streams 
            memoryStream = new MemoryStream();
            cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(aes.Key, aes.IV), CryptoStreamMode.Write);

            //Encrypt Data 
            byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt);
            cryptoStream.Write(data, 0, data.Length);
            cryptoStream.FlushFinalBlock();

            //Return Base 64 String 
            var temp = memoryStream.ToArray();
            string result = Convert.ToBase64String(temp);

            return result;
        }
        finally
        {
            if (cryptoStream != null)
                cryptoStream.Close();

            if (memoryStream != null)
                memoryStream.Close();

            if (aes != null)
                aes.Clear();
        }
    }

在 php 中:

<?php
function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') {

    // experimentally determine h_len for the algorithm in question
     static $lengths;
     if (!isset($lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); }
    $h_len = $lengths[$algo];

    if ($dk_len > (pow(2, 32) - 1) * $h_len) {
         return false; // derived key is too long
     } else {
         $l = ceil($dk_len / $h_len); // number of derived key blocks to compute
         $t = null;
         for ($i = 1; $i <= $l; $i++) {
             $f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate
             for ($j = 1; $j < $c; $j++) {
                 $f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate
             }
             $t .= $f; // concatenate blocks of the derived key
         }
         return substr($t, 0, $dk_len); // return the derived key of correct length
     }
}

$text = "blaat";
$password = 'this is my secret passwordthis is my secret password';
$salt = 'thisismysalt';

#$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
#$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

$iv = 'AAAAAAAAAAAAAAAA';

$key = pbkdf2($password, $salt, 1000, 32);
echo 'key size: ' . strlen($key) . '<br/>';
echo 'key: ' . base64_encode($key) . '<br/>';
echo 'iv size: ' . strlen($iv) . '<br/>';
#echo 'iv: ' . $iv . '<br/>';
echo 'iv: ' . base64_encode($iv) . '<br/>';

echo '<br/><br/>';

#    $data = $this->paddingAlgorithm->padData($data, $blockSize);
#    return $iv . mcrypt_encrypt($this->MCRYPT_DES, $keyBytes, $data, MCRYPT_MODE_CBC, $iv);

function addpadding($string)
{
     $blocksize = 16;
     $len = strlen($string);
     $pad = $blocksize - ($len % $blocksize);
     $string .= str_repeat(chr($pad), $pad);

     return $string;
}

$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, addpadding($text), MCRYPT_MODE_CBC, $iv);
$crypttext = base64_encode($crypttext);
echo '3. [' . $crypttext . ']<br/>';

echo '<br/>';

?>

希望这也能对某人有所帮助。

保罗感谢您的帮助!

【讨论】:

  • 当我使用这个函数集成加密时,我从 c# 和 php 得到两个不同的值。我环顾所有领域,如 key、salt 等,都是一样的。如果上面的 C# 代码中缺少任何东西。如果你能帮助我,请帮助我。
  • 你好,Deepu,这段代码是完整的,已经用于一个程序。如果您希望有人帮助您解决问题,您需要提供源代码和数据示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-13
  • 2011-02-15
  • 2016-02-22
  • 2015-03-13
  • 2015-05-12
  • 1970-01-01
相关资源
最近更新 更多