使用最新的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脚本返回诸如......
之类的数据数组([版本] =&gt; 1 [选项] =&gt; 1 [salt1] =&gt; 109 [salt2] =&gt; 195 [salt3] =&gt; 185 [salt4] =&gt; 71 [salt5] =&gt; 130 [salt6] =&gt; 209 [salt7] =&gt; 230 [salt8] =&gt; 25 [hmac1] =&gt; 8 [hmac2] =&gt; 152 [hmac3] =&gt; 188 [hmac4] =&GT; 135 [hmac5] =&gt; 117 [hmac6] =&gt; 169 [hmac7] =&gt; 25 [hmac8] =&gt; 228 [iv1] =&gt; 43 [iv2] =&gt; 220 [iv3] =&gt; 80 [iv4] =&gt; 102 [iv5] =&gt; 142 [iv6] =&GT; 144 [iv7] =&gt; 172 [iv8] =&gt; 104 [iv9] =&gt; 216 [iv10] =&gt; 45 [iv11] =&gt; 155 [iv12] =&gt; 117 [iv13] =&gt; 188 [iv14] =&gt; 67 [iv15] =&gt; 24 [iv16] =&gt; 191 [aes1] =&gt; 122 [aes2] =&gt; 227 [aes3] =&gt; 45 [aes4] =&gt; 194 [aes5] =&gt; 57 [aes6] =&gt; 123 [aes7] =&gt; 28 [aes8] =&gt; 130 [aes9] =&gt; 110 [aes10] =&gt; 122 [aes11] =&gt; 97 [aes12] =&gt; 118 [aes13] =&gt; 214 [aes14] =&gt; 117 [aes15] =&GT; 56 [aes16] =&gt; 168 [aes17] =&gt; 54 [aes18] =&gt; 198 [aes19] =&gt; 113 [aes20] =&gt; 120 [aes21] =&gt; 138 [aes22] =&gt; 67 [aes23] =&gt; 223 [aes24] =&gt; 200 [aes25] =&gt; 11 [aes26] =&gt; 109 [aes27] =&gt; 177 [aes28] =&gt; 167 [aes29] =&GT; 103 [aes30] =&gt; 139 [aes31] =&gt; 243 [aes32] =&gt; 199 [aes33] =&gt; 214 [aes34] =&gt; 214 [aes35] =&gt; 241 [aes36] =&gt; 199 [aes37] =&gt; 173 [aes38] =&gt; 219 [aes39] =&gt; 71 [aes40] =&gt; 97 [aes41] =&gt; 32 [aes42] =&gt; 27 [aes43] =&gt; 248 [aes44] =&gt; 175 [aes45] =&gt; 203 [aes46] =&gt; 123 [aes47] =&gt; 21)
我如何在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¸|uÀÆ&安培; BY8:f`ôShŽºÃ〜:¾ÉöÁß=Ç®nqäà€•Æ<ò
我回顾了RNCryptor并使用以下值来编写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字节密钥。
答案 0 :(得分:4)
这适用于iOS中最新的RNCryptor
$b64_data
: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));
pbkdf2
与上面的问题相同,来自https://defuse.ca/php-pbkdf2.htm。
答案 1 :(得分:1)
你不需要为此解压缩。
一旦你收到完整的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。
答案 2 :(得分:0)
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更灵活。)
在pbkdf2()
函数中,应传递32字节(256位)的密钥长度,而不是16字节。我相信如果传递256位密钥,PHP mcrypt模块将自动切换到256位AES(基于对Understanding PHP AES Encryption的评论;我对mcrypt并不是特别熟悉)。我假设你正确地实施了PBKDF2;我没有在那里研究你的代码。
请注意,RNCryptor会在末尾附加一个32字节的HMAC。我相信你当前的代码会尝试解密它,最后导致32字节的垃圾。通常,您应该关闭此HMAC并验证它以确保数据在传输过程中未被修改且密码正确。