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 使用 IV 对 AES CBC 中的字符串进行编码。
在 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 使用类似于 mcrypt 的非标准空填充,这是不幸的,因为填充标准是 PKCS#7。不幸的是,必须阅读代码才能找到答案。提供 256 位(32 字节)密钥很重要,因为它设置了算法的密钥大小。
FBEncryptor 仅支持 PKCS#7 填充。
所以,这两种方法是不兼容的。
一种解决方案是在调用 phpAES 之前向 php 中的字符串添加 PKCS#7 填充,这样就不会添加空填充。然后 FBEncryptor 将与加密数据兼容。
PKCS#7 填充 总是 添加填充。填充是一系列字节,其值是添加的填充字节数。填充的长度是 block_size - (length(data) % block_size.
对于块为 16 字节的 AES(并希望 php 有效,已经有一段时间了):
$pad_count = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($pad_count), $pad_count);
请在问题中添加工作示例密钥、iv 清除数据和加密数据作为十六进制转储。
不要使用 phpAES。 你是在搬起石头砸自己的脚。
来自他们的页面:
The free version only supports ECB mode, and is useful for encrypting/decrypting credit card numbers.
这是非常错误和误导的。 ECB 模式不适合 除了作为其他操作模式的基础之外的任何目的。你想要一个 AEAD 模式;或者,如果失败,则使用 HMAC-SHA2 和 CSPRNG 派生的 CBC 或 CTR IV/nonce。 Using unauthenticated encryption is a very bad idea.
为了与 iOS 的互操作性,您应该 use libsodium。
- Objective-C: SodiumObjc or NAChloride
- PHP: libsodium-php(在 PECL 中也可用)
如果您不能使用 libsodium,最好的选择是 OpenSSL 和明确 not mcrypt,以及 iOS 端的兼容接口。
所有当前支持的 PHP 版本 (5.4+) 公开了 openssl_encrypt()
和 openssl_decrypt()
,它们允许快速安全的 AES-CBC 和 AES-CTR 加密。但是,您应该 consider using a library that implements these functions for you 而不是自己编写它们。
我的一个应用程序需要下载一个包含 AES 256 加密内容的数据库。所以我在服务器端 phpAES 使用 IV 对 AES CBC 中的字符串进行编码。
在 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 使用类似于 mcrypt 的非标准空填充,这是不幸的,因为填充标准是 PKCS#7。不幸的是,必须阅读代码才能找到答案。提供 256 位(32 字节)密钥很重要,因为它设置了算法的密钥大小。
FBEncryptor 仅支持 PKCS#7 填充。
所以,这两种方法是不兼容的。
一种解决方案是在调用 phpAES 之前向 php 中的字符串添加 PKCS#7 填充,这样就不会添加空填充。然后 FBEncryptor 将与加密数据兼容。
PKCS#7 填充 总是 添加填充。填充是一系列字节,其值是添加的填充字节数。填充的长度是 block_size - (length(data) % block_size.
对于块为 16 字节的 AES(并希望 php 有效,已经有一段时间了):
$pad_count = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($pad_count), $pad_count);
请在问题中添加工作示例密钥、iv 清除数据和加密数据作为十六进制转储。
不要使用 phpAES。 你是在搬起石头砸自己的脚。
来自他们的页面:
The free version only supports ECB mode, and is useful for encrypting/decrypting credit card numbers.
这是非常错误和误导的。 ECB 模式不适合 除了作为其他操作模式的基础之外的任何目的。你想要一个 AEAD 模式;或者,如果失败,则使用 HMAC-SHA2 和 CSPRNG 派生的 CBC 或 CTR IV/nonce。 Using unauthenticated encryption is a very bad idea.
为了与 iOS 的互操作性,您应该 use libsodium。
- Objective-C: SodiumObjc or NAChloride
- PHP: libsodium-php(在 PECL 中也可用)
如果您不能使用 libsodium,最好的选择是 OpenSSL 和明确 not mcrypt,以及 iOS 端的兼容接口。
所有当前支持的 PHP 版本 (5.4+) 公开了 openssl_encrypt()
和 openssl_decrypt()
,它们允许快速安全的 AES-CBC 和 AES-CTR 加密。但是,您应该 consider using a library that implements these functions for you 而不是自己编写它们。