首页 文章

Swift(iOS)和PHP中AES256加密的结果不同

提问于
浏览
11

我在AES256工作,能够使用不安全的渠道在iOS和PHP之间加密/解密 .

我看到周围的按键尺寸移动很多类似的问题,模式(CBC或ECB),用在这种情况下,随机IV,等等,但是,我发现了一个怪异的行为如下 .

在两种环境中配置: - 密钥:32字节(256位) - 块大小:128位(标准) - iv:16字节(静态用于测试目的) - 模式:CBC

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

键= “12345678901234567890123456789012” 明文= “12345678901234567890123456789012” IV = “1234567890123456” 快速加密= e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2KyKJTx4KfWmn4HXi4dG0b8 PHP加密器= e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2I =

如您所见,PHP Base64字符串的密码长度和最后2个字符存在差异 .

但是,如果我使用的文本不是AES128块大小乘数,请说“Hello World”,bot环境会报告不同(但大小相同)的密码,如下所示

夫特密码= 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)

为什么这些不同?

1 回答

  • 8

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

    如果纯文本不是块大小的N倍,则PHP使用"zero padding" . 所以PHP填充0..15字节,其值为 00 ,用于128位块密码,例如AES . 对于以块边界结束的明文,它不会添加任何填充字节 .

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

    PKCS#7填充是确定性的,不依赖于明文值(可以包含任何值的字节,而不仅仅是文本);换句话说,它总是可以独立于内容来应用和删除 .

    零填充有一个问题,即以 00 字节结尾的纯文本可能会在取消填充期间删除那些 00 字节 . 对于ASCII兼容字符串,这通常不是问题,因为 00 是控制字符,通常表示文件结束(EOF) .

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

相关问题