2013-05-10 141 views
3

我在使用PHP来解密与iOS 5.x中的CommonCrypto库进行加密的字符串的麻烦。下面是参数:解密AES CTR小端用PHP

Algorithm: AES-128 
Mode: CTR 
Mode options: CTR Little-Endian 
Padding: None 

这是我最好的尝试的样品,在它:

<?php 
$encrypted = base64_decode('MlNFlnXE1sqIsmKZRtjChBvUMgiJlXgdjHVxQJ6JK24Id4uaN9NK/nBtY+cgrMJR/PRJRCmIUx0boQO5XqJYZ8VJ0w=='); 
$key = base64_decode('HB+dD1Irj2rXQ/nO+IuqSiK9xVE3PD9cZGIGzrMtwtA='); 
$iv = base64_decode('2gxxKYU/G4lj7174e5wj+g=='); 

$cryptor = mcrypt_module_open('rijndael-128', '', 'ctr', ''); 
mcrypt_generic_init($cryptor, $key, $iv); 
echo mdecrypt_generic($cryptor, $encrypted); 

mcrypt_generic_deinit($cryptor); 
mcrypt_module_close($cryptor); 

输出看起来是这样的:

Lorem ipsum dolo?N??]ѕȢ?+? 
              ????x??k????}??'???Ŧ??;t 

但它应该是“Lorem存有悲坐阿梅德,consectetur adipisicing ELIT,SED做...“(包括尾随省略号。)

块大小为16,它的前16个字符正确。这似乎指向Mcrypt和CommonCrypto之间的AES CTR反递增过程不匹配。我从目前听到的每个人都认为这是Big Endian vs. Little Endian的问题。

我花了几天,试图找出这一切的字节顺序和反递增的东西对我自己的,但它仍然是巫术我。 :-(我只需要一些能正确解密我的字符串的PHP代码,我不在乎算法运行的速度有多快,我可以放弃Mcrypt而选择PHP本地解决方案或其他PHP扩展,只要这是一个常见的一种。但是,在iOS端改变的事情是一个选项。

请帮帮忙!

+0

什么是由mencrypt_enc_get_iv_size返回的大小()?这应该是其他情况下使用的长度; http://www.php.net/manual/en/function.mcrypt-enc-get-iv-size.php – 2013-05-10 19:34:17

+0

它返回16,与我的IV长度相同。 – curtisdf 2013-05-10 19:48:26

回答

3

块加密模式是非常简单的,你可以自己实现这些功能,如果两个实现是不兼容的。

这里是你的特殊情况下,CTR实现:

function ctr_crypt($str, $key, $iv) { 
    $numOfBlocks = ceil(strlen($str)/16); 

    $ctrStr = ''; 
    for ($i = 0; $i < $numOfBlocks; ++$i) { 
     $ctrStr .= $iv; 

     // increment IV 
     for ($j = 0; $j < 16; ++$j) { 
      $n = ord($iv[$j]); 
      if (++$n == 0x100) { 
       // overflow, set this one to 0, increment next 
       $iv[$j] = "\0"; 
      } else { 
       // no overflow, just write incremented number back and abort 
       $iv[$j] = chr($n); 
       break; 
      } 
     } 
    } 

    return $str^mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $ctrStr, MCRYPT_MODE_ECB); 
} 

的算法很简单:你总是追加和递增IV,直到你有一个字符串,它是长度(或长度相等的)作为输入字符串。然后,您使用ECB模式对此字符串进行加密,并将其与输入字符串异或。

的增量是复杂的部分在这里,因为我们面对的是二进制的数字。 Little Endian意味着我们从左到右递增(j = 0,j < 16,j ++)。 Big Endian意味着我们从右到左递增(j = 15,j> = 0,j--)。

试试看:

$encrypted = base64_decode('MlNFlnXE1sqIsmKZRtjChBvUMgiJlXgdjHVxQJ6JK24Id4uaN9NK/nBtY+cgrMJR/PRJRCmIUx0boQO5XqJYZ8VJ0w=='); 
$key = base64_decode('HB+dD1Irj2rXQ/nO+IuqSiK9xVE3PD9cZGIGzrMtwtA='); 
$iv = base64_decode('2gxxKYU/G4lj7174e5wj+g=='); 

var_dump(ctr_crypt($encrypted, $key, $iv)); 
// string(67) "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do..." 

注:既作为加密和解密功能ctr_crypt工作。

+0

+尼斯......但你不觉得你应该反对'ECB'吗? – Baba 2013-05-18 16:09:57

+0

@Baba这实现了CTR加密模式。 ) – NikiC 2013-05-18 17:14:36

+0

我并不是指CTR的实现,而是一般的ECB ......如果key&IV没有被重用,他可能是安全的,但iOS 5.x的CommonCrypto仍然有更好的表现替代品......但我想这个问题是关于'解密AES CTR Little Endian' ......不错的一个:) – Baba 2013-05-18 21:16:39

0

看起来像PHP的mcrypt的使用等CTR模式(大尾数法,而不是小端的)。主要日程和IV都OK(你可以在解密的第一块看),但不顺心的事在IV递增函数。

请参见下面的PHP代码,它通过手册册解决您的问题Ÿ增加IV和ECB模式加密伽玛:

<?php 
$encrypted = base64_decode('MlNFlnXE1sqIsmKZRtjChBvUMgiJlXgdjHVxQJ6JK24Id4uaN9NK/nBtY+cgrMJR/PRJRCmIUx0boQO5XqJYZ8VJ0w=='); 
$key = base64_decode('HB+dD1Irj2rXQ/nO+IuqSiK9xVE3PD9cZGIGzrMtwtA='); 
$iv = base64_decode('2gxxKYU/G4lj7174e5wj+g=='); 

$ivarr = array_values(unpack('C*', $iv)); 
$ivdata = array_merge($ivarr); 
$blocklen = count($ivarr); 

for ($i = 1; $i < strlen($encrypted)/strlen($iv); $i++) 
{ 
    // incrementing IV 
    $ivarr[0] += 1; 
    if ($ivarr[0] == 256) 
    $ivarr[0] = 0; 

    $j = 0; 
    while ($ivarr[$j] == 0) 
    { 
    $j++; 
    if ($j == $blocklen) 
     break; 
    $ivarr[$j]++; 
    } 
    // appending to array 
    var_dump($ivarr); 
    $ivdata = array_merge($ivdata, $ivarr); 
} 

// now ivdata contains the full CTR gamma. Encrypting it. 

$cryptor = mcrypt_module_open('rijndael-128', '', 'ecb', ''); 
$res = mcrypt_generic_init($cryptor, $key, ""); 

$ivdatastr = implode(array_map("chr", $ivdata)); 
$ivdecr = mcrypt_generic($cryptor, $ivdatastr); 

$ivdecr = array_values(unpack('C*', $ivdecr)); 
$decrypted = array_values(unpack('C*', $encrypted)); 
$i = 0; 

for ($i = 0; $i < count($decrypted); $i++) 
{ 
    $decrypted[$i] = $decrypted[$i]^$ivdecr[$i % count($ivdecr)]; 
}  

$string = implode(array_map("chr", $decrypted)); 

var_dump($string); 

mcrypt_generic_deinit($cryptor); 
mcrypt_module_close($cryptor); 
?> 
+0

任何关于如何使用Little Endian的指针?是否有替代MCrypt的PHP可以做到这一点? – curtisdf 2013-05-10 19:44:09

+0

更改iOS兼容代码会更容易,但我不知道您是否可以更改该代码。 – 2013-05-11 00:21:19

+0

至少您可以手动为每个块增加IV并使用它。但是,这会很慢。按照owlstead的建议,更容易转换到CBC模式,或更改iOS端的endiannes。 – 2013-05-11 07:51:23