当前位置: 首页 > 知识库问答 >
问题:

从 RNCryptor AES 256 报头中检索 IV 在 PHP 中

贺光华
2023-03-14

使用最新的RNCryptor源代码并尝试将加密数据发送到PHP脚本。

RNCryptor将IV打包到标头部分中,标头部分附加到实际加密数据中。

- (NSData *)header
{
  uint8_t header[2] = {kRNCryptorFileVersion, self.options};
  NSMutableData *headerData = [NSMutableData dataWithBytes:header length:sizeof(header)];
  if (self.options & kRNCryptorOptionHasPassword) {
    [headerData appendData:self.encryptionSalt]; // 8 bytes
    [headerData appendData:self.HMACSalt]; // 8 bytes
  }
  [headerData appendData:self.IV]; // BlockSizeAES128
  return headerData;
}

我不熟悉在PHP中处理二进制数据,我使用以下解包函数是否正确?

<?
$baseEncodedString = "...";
$data = mb_convert_encoding($baseEncodedString, "UTF-8", "BASE64" );
$array = unpack("Cversion/Coptions/C8salt/C8hmac/C16iv/C*aes", $data);
print_r($array);
?>

注意:加密数据是在传输前从cocoa编码的Base64。

上面的PHP脚本返回如下数据...

阵列([版本]=

我怎样才能在PHP MCrypt函数中使用它呢?

谢谢。

编辑

为了回应drew010的回答,我将PHP脚本更新为以下内容。。。

<?
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}

$base = $_GET['base'];
$data = mb_convert_encoding($base, "UTF-8", "BASE64" );
//$data = base64_decode($base);

$header = array();
$header['ver'] = substr($data, 0, 1);
$header['options'] = substr($data, 1, 1);
$header['salt'] = substr($data, 2, 8);
$header['hmac'] = substr($data, 10, 8);
$header['iv'] = substr($data, 18, 16);
$data = substr($data, 34);

$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($td, pbkdf2('SHA256', 'password', $header['salt'], 10000, 16), $header['iv']);

//$decrypted = mcrypt_decrypt('rijndael-256','password',$data,'',$header['iv']);
$decrypted = mdecrypt_generic($td, $data);
echo $decrypted;
?>

我怎么还在收到混乱的文本。

UˆÆ

我回顾了 RN 加密器,并将以下值用于 PHP 脚本

static const RNCryptorSettings kRNCryptorAES256Settings = {
    .algorithm = kCCAlgorithmAES128,
    .blockSize = kCCBlockSizeAES128,
    .IVSize = kCCBlockSizeAES128,
    .options = kCCOptionPKCS7Padding,
    .HMACAlgorithm = kCCHmacAlgSHA256,
    .HMACLength = CC_SHA256_DIGEST_LENGTH,

    .keySettings = {
        .keySize = kCCKeySizeAES256,
        .saltSize = 8,
        .PBKDFAlgorithm = kCCPBKDF2,
        .PRF = kCCPRFHmacAlgSHA1,
        .rounds = 10000
    },

    .HMACKeySettings = {
        .keySize = kCCKeySizeAES256,
        .saltSize = 8,
        .PBKDFAlgorithm = kCCPBKDF2,
        .PRF = kCCPRFHmacAlgSHA1,
        .rounds = 10000
    }
};

我相信这个函数能产生密钥。

+ (NSData *)keyForPassword:(NSString *)password salt:(NSData *)salt settings:(RNCryptorKeyDerivationSettings)keySettings
{
  NSMutableData *derivedKey = [NSMutableData dataWithLength:keySettings.keySize];

  int result = CCKeyDerivationPBKDF(keySettings.PBKDFAlgorithm,         // algorithm
                                    password.UTF8String,                // password
                                    password.length,                    // passwordLength
                                    salt.bytes,                         // salt
                                    salt.length,                        // saltLen
                                    keySettings.PRF,                    // PRF
                                    keySettings.rounds,                 // rounds
                                    derivedKey.mutableBytes,            // derivedKey
                                    derivedKey.length);                 // derivedKeyLen

  // Do not log password here
  // TODO: Is is safe to assert here? We read salt from a file (but salt.length is internal).
  NSAssert(result == kCCSuccess, @"Unable to create AES key for password: %d", result);

  return derivedKey;
}

再次感谢。

MCRYPT_RIJNDAEL_128正确吗?尽管RNCryptor设置建议使用256,但实际算法是128,IV大小与128块大小相关。我在某处读到过强制PHP使用16字节的IV,你必须使用MCRYPT_RIJNDAEL_128,然后让256给它一个32字节的密钥。

共有3个答案

朱通
2023-03-14

MCRYPT_RIJNDAEL_128正确吗?尽管RNCryptor设置建议使用256,但实际算法是128,IV大小与128块大小相关。我在某处读到过强制PHP使用16字节的IV,你必须使用MCRYPT_RIJNDAEL_128,然后让256给它一个32字节的密钥。

MCRYPT_RIJNDAEL_128中的128指的是块大小,而不是密钥大小。Rijndael算法可以处理几个块大小,但AES只能处理128位块。这与密钥大小无关。CBC IV应该始终是块大小,在AES中也始终是16字节。(Rijndael和AES非常相似,但不完全相同。Rijndael比AES更灵活。)

在< code>pbkdf2()函数中,应该传递32字节(256位)的密钥长度,而不是16字节。我相信PHP mcrypt模块如果传递一个256位的密钥会自动切换到256位AES(基于了解PHP AES加密的评论;我对mcrypt不是特别熟悉)。我假设您正确地实现了PBKDF2我没有在那里研究过你的代码。

注意,RNCryptor在末尾附加了一个32字节的HMAC。我相信您当前的代码会尝试解密它,最终导致32字节的垃圾。通常情况下,您应该剥掉这个HMAC并进行验证,以确保数据在传输过程中没有被修改,并且密码是正确的。

盖成弘
2023-03-14

您不需要为此使用unpack。

收到完整的base64编码字符串后,对其进行解码,现在您应该有一个二进制字符串,该字符串的开头有IV。

然后,您可以使用substr()从数据中获取所需的每个片段。

例如:

$base = $_GET['base'];
$data = base64_decode($base);

$iv   = substr($data, 0, 32);  // get 32 byte IV
$data = substr($data, 32);     // set data to begin after the IV now

如果密文前面有其他字段,请确保按照正确的顺序对其他数据执行上述操作。

获得这些数据后,您可以将$data与IV和密钥一起传递给mcrypt。

太叔正文
2023-03-14

这适用于iOS中最新的RN加密器

$b 64_数据:base64 编码的加密数据
$pwd:密码

// back to binary
$bin_data = mb_convert_encoding($b64_data, "UTF-8", "BASE64");
// extract salt
$salt = substr($bin_data, 2, 8);
// extract HMAC salt
$hmac_salt = substr($bin_data, 10, 8);
// extract IV
$iv = substr($bin_data, 18, 16);
// extract data
$data = substr($bin_data, 34, strlen($bin_data) - 34 - 32);
// extract HMAC
$hmac = substr($bin_data, strlen($bin_data) - 32);

// make HMAC key
$hmac_key = $this->pbkdf2('SHA1', $password, $hmac_salt, 10000, 32, true);
// make HMAC hash
$hmac_hash = hash_hmac('sha256', $data , $hmac_key, true);
// check if HMAC hash matches HMAC
if($hmac_hash != $hmac) return false;

// make data key
$key = $this->pbkdf2('SHA1', $password, $salt, 10000, 32, true);
// decrypt
$ret = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
return trim(preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/u', '', $ret));

< code>pbkdf2与上面问题中的相同,来自https://defuse.ca/php-pbkdf2.htm.

 类似资料:
  • 问题内容: 其实我有两个问题。 (1)如果仅检索标头而不是使用php和curl进行全页检索,那么在远程服务器上使用的 处理能力 或 带宽 是否有所减少? (2)因为我认为并且可能是错误的,所以第一个问题的答案是 YES ,我试图获取远程文件的最后修改日期或If-Modified- Since标头只是为了与它的时间日期进行比较本地存储的数据,因此,如果数据已更改,我可以将其存储在本地。但是,运行此脚

  • 有没有人知道我可以使用PHP从MySql数据库中的两个表中获取数据的方法?我的android应用程序允许用户在购物车(MySql中的表)中放置物品。当用户点击应用程序中的购物车按钮时,它会加载“购物车activity”,并根据“会话ID”或“客户ID”(如果他们已经登录)加载一个列表视图,其中包含他们添加到购物车中的所有内容。我现在所做的是,当项目被添加到购物车时,我捕获产品ID、产品名称、图像U

  • 问题内容: 我很好奇是否有任何图书馆已经在处理这种事情,或者我必须自己再做一次。所以,问题是我想从服务器上的访问者HTTP标头请求中获取IP地址字段,然后用Java完成整个工作?你能帮忙的话,我会很高兴。提前致谢。 问题答案: 使用对象的方法检索变量的值。这是示例代码: 如果此代码返回空字符串,则使用以下方式:

  • > < li >我们公开了一个Apache camel-cxf webservice。使用camel处理器,我们试图从soapUi客户端获取我们在soap请求中传递的soap头。 < li> 交换对象包含soap消息的正文(不是soap消息头)。在exchange.getIn.getHeader()中,我们只获得传递的HTTP头,而不是SOAP头。 如何在Camel中从交换对象中检索SOAP头?

  • 我使用Java8 lambdas轻松筛选集合。但我没有找到一种简洁的方法来在同一语句中检索作为新列表的结果。这里是我迄今为止最简洁的方法: 网上的例子并没有回答我的问题,因为它们在没有生成新的结果列表的情况下就停止了。一定有更简洁的方式。我希望类具有、、…等方法 变量是否可以通过第三行直接赋值?

  • 我正在用python开发一个二叉查找树。但是我的检索方法并不像我希望的那样工作。只有当我想检索根节点时,它才返回正确的值,对于所有其他节点,它都不返回任何值。 下面是我的节点类的代码: 我的二叉树代码: 所以Bintree中的最后一个方法为除Root之外的所有值返回Not,但它应该返回节点的值。 填充树: