AES 256和Base64加密字符串在iOS 8上工作,但在iOS 7上被截断


AES 256 and Base64 Encrypted string works on iOS 8 but truncated on iOS 7

我的一个应用程序需要下载一个包含AES 256加密内容的数据库。因此,我在服务器端使用phpAES在AES CBC中使用IV编码字符串。

在iOS方面,我使用FBEncryptor来解密字符串。

这是服务器端的代码:

$aes = new AES($key, "CBC", $IV);
$crypt = $aes->encrypt($string);
$b64_crypt = base64_encode($crypt);

在iOS端,我这样做:

NSString* decrypt = [FBEncryptorAES decryptBase64String:b64_crypt keyString:key iv:iv];

实际上在iOS 8上一切都很好。问题是在iOS 7上,解码的字符串被截断为随机长度。

想法吗?

不要使用phpAES。你这是在搬起石头砸自己的脚。

From their page:

免费版仅支持ECB模式,用于加密/解密信用卡号码。

这是非常错误和误导的。ECB模式不适合用于任何目的,除非作为其他操作模式的构建块。你想要AEAD模式;或者,如果失败,CBC或CTR与HMAC-SHA2和csprng衍生的IV/nonce。使用未经身份验证的加密是一个非常糟糕的主意。

为了与iOS的互操作性,你应该使用libsodium.

  • Objective-C:盐酸布洛杰或盐酸钠
  • PHP: libsodium-php(也可在PECL中使用)

如果你不能使用lib钠,你最好的选择是OpenSSL和显式而不是 mcrypt,以及iOS端的兼容接口。

所有当前支持的PHP版本(5.4+)暴露openssl_encrypt()openssl_decrypt(),允许快速和安全的AES-CBC和AES-CTR加密。但是,您应该考虑使用为您实现这些函数的库,而不是自己编写它们。

截断可能是由于不兼容的填充。

phpAES使用类似于加密的非标准空填充,这是不幸的,因为填充的标准是pkcs# 7。不幸的是,人们必须阅读代码才能发现这一点。提供256位(32字节)密钥非常重要,因为它设置了算法的密钥大小。

FBEncryptor只支持pkcs# 7填充。

所以,这两种方法是不兼容的。

一个解决方案是在调用phpAES之前在php中添加pkcs# 7填充到字符串中,这样就不会添加空填充。然后FBEncryptor将与加密的数据兼容。

pkcs# 7 padding always添加padding。填充是一个以字节为单位的序列,加上填充字节数的值。填充的长度为block_size - (length(data) % block_size.

对于AES,块是16字节(希望php是有效的,它已经有一段时间了):

$pad_count = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($pad_count), $pad_count);

请在问题中添加工作示例密钥,iv清晰数据和加密数据作为十六进制转储。