Swift(iOS)和PHP中AES256encryption的结果不同

我在AES256工作,能够使用不安全的通道在iOS和PHP之间进行encryption/解密。

我看到很多类似的问题,围绕关键尺寸,模式(CBC或ECB),使用随机四等。但在这种情况下,我发现了一个奇怪的行为如下。

在这两种环境中configuration: – 密钥:32字节(256位) – 块大小:128位(标准) – iv:16字节(用于testing的静态) – 模式:CBC

如果我encryption一个16或32字节的文本(以匹配AES块大小),结果在Swift和PHP是相似的,但不完全相同:

key =“12345678901234567890123456789012”plainText =“12345678901234567890123456789012”iv =“1234567890123456”

Swift cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2KyKJTx4KfWmn4HXi4dG0b8 PHP cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2I =

如您所见,密码长度和PHP Base64string的最后两个字符有所不同。

但是,如果我使用不是AES128块大小乘数的文本,让我们说“Hello World”,则漫游器环境报告以下不同(但相同大小)的密码

Swift cipher = bdwO / 5C8a + pliIoIXtuzfA ==

PHP密码= oPotHCkxpOwQhIaCz6hNMw ==

在这两种情况下(Swift和PHP),无论明文大小如何,密码都是正确解密的。 另外,Swift结果与代码的Objective-C版本一致

附上使用的简化代码:

PHP

$key = "12345678901234567890123456789012"; $iv = "1234567890123456"; $plaintext = "Hello World"; $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv); $ciphertext_base64 = base64_encode($ciphertext); echo "ciphertext: ".$ciphertext_base64."</br>"; 

迅速

 let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let keyBytes = UnsafePointer<UInt8>(keyData.bytes) let keyLength = size_t(kCCKeySizeAES256) let plainData = (plainText as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let dataLength = UInt(plainData.length) let dataBytes = UnsafePointer<UInt8>(plainData.bytes) var bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128) var bufferPointer = UnsafeMutablePointer<UInt8>(bufferData.mutableBytes) let bufferLength = size_t(bufferData.length) let operation: CCOperation = UInt32(kCCEncrypt) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options = UInt32(kCCOptionPKCS7Padding) let ivData: NSData! = (iv as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! let ivPointer = UnsafePointer<UInt8>(ivData.bytes) var numBytesEncrypted: UInt = 0 var cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, ivPointer, dataBytes, dataLength, bufferPointer, bufferLength, &numBytesEncrypted) bufferData.length = Int(numBytesEncrypted) let base64cryptString = bufferData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength) println(base64cryptString) 

为什么这些不同?

这是由于填充模式的差异。

如果纯文本不是块大小的N倍, PHP使用“零填充”。 所以PHP填充0到15个字节,值为00用于128位分组密码,如AES。 对于结束于块边界的明文,它不会添加任何填充字节。

大多数其他语言使用PKCS#7填充,填充到下一个块边界,其中填充字节反映了添加的字节数。 所以这将是1..16个字节,值为1..16(或hex的0110 )。 对于结束于块边界的明文,它将添加16个字节的填充。

PKCS#7填充是确定性的并且不依赖于明文值(可以由具有任何值的字节组成,而不仅仅是文本); 换句话说,它总是可以独立于内容而被应用和移除。

零填充的问题是以00字节结尾的纯文本可能会在非填充期间删除那些00字节。 这通常不是ASCII兼容string的问题,因为00是控制字符,通常意思是文件结束(EOF)。

请查看关于mcrypt_encrypt的注释,以了解如何将PKCS#7填充应用于PHP。