在Swift(iOS)和PHP中的AES256加密中有不同的结果 [英] Different results in AES256 encryption in Swift (iOS) and PHP

查看:292
本文介绍了在Swift(iOS)和PHP中的AES256加密中有不同的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我在AES256中工作,可以使用不安全的渠道对iOS和PHP进行加密/解密。 ,模式(CBC或ECB),使用随机iv等。但在这种情况下,我发现一个奇怪的行为如下。



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



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


key =12345678901234567890123456789012
plainText =12345678901234567890123456789012
iv =1234567890123456



Swift cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2KyKJTx4KfWmn4HXi4dG0b8
PHP cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2I =


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



但是如果我使用不是AES128块大小乘数的文本,那么我们来说Hello World,机器人环境报告不同(但是大小相同的)密码如下


Swift cipher = bdwO / 5C8a + pliIoIXtuzfA ==



PHP cipher = 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);
echociphertext:。$ ciphertext_base64。< / br>;

Swift

  let keyData:NSData! =(键为NSString).dataUsingEncoding(NSUTF8StringEncoding)为NSData! 
let keyBytes = UnsafePointer< UInt8>(keyData.bytes)
let keyLength = size_t(kCCKeySizeAES256)

let plainData =(plainText as NSString).dataUsingEncoding(NSUTF8StringEncoding)as NSData !
让dataLength = UInt(plainData.length)
让dataBytes = UnsafePointer< UInt8>(plainData.bytes)

var bufferData = NSMutableData(length:Int(dataLength)+ kCCBlockSizeAES128 )
var bufferPointer = UnsafeMutablePointer< UInt8>(bufferData.mutableBytes)
let bufferLength = size_t(bufferData.length)

允许操作:CCOperation = UInt32(kCCEncrypt)
let algorithmit:CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options = UInt32(kCCOptionPKCS7Padding)

让ivData:NSData! =(iv as NSString).dataUsingEncoding(NSUTF8StringEncoding)as NSData!
让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)

为什么这些不同?

解决方案

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



PHP使用零填充 >纯文本不是块大小的N倍。因此,PHP为128位块密码(如AES)的0..15个字节,值为 00 。对于以块边界结尾的明文,它不会添加任何填充字节。



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



PKCS#7填充是确定性的,不依赖于明文值(可以由具有任何值的字节,而不仅仅是文本);换句话说,它可以随时独立于内容进行应用和删除。



零填充有以 00结尾的纯文本的问题, code>字节可能会在解压缩期间删除那些 00 字节。这通常不是ASCII兼容字符串的问题,因为 00 是一个控制字符,通常意味着文件结尾(EOF)。



请检查 mcrypt_encrypt 上的意见,了解如何将PKCS#7填充应用于PHP。


I am working in AES256 to be able to encrypt/decrypt between iOS and PHP using insecure channels.

I have seen many similar questions that move around the key size, the mode (CBC or ECB), the use of a random iv, etc. But in this case, I found a weird behaviour as follows.

Configuration in both environments: - Key: 32 bytes(256 bits) - Block size: 128 bits (standard) - iv: 16 bytes (static for testing purposes) - Mode: CBC

If I encrypt a 16 or 32 bytes text (to match the AES block size), the result in Swift, and PHP are similar but not quite the same:

key = "12345678901234567890123456789012" plainText = "12345678901234567890123456789012" iv = "1234567890123456"

Swift cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2KyKJTx4KfWmn4HXi4dG0b8 PHP cipher = e5RnnlJkv4QGnGhkMwfvgMHr80NWUVhbvvfCdPQ5V2I=

As you can see, there is a difference in the cipher length and in the last 2 characters of the PHP Base64 String.

But if I use a text that is not a AES128 Block Size multiplier, let´s say "Hello World", bot environments report different (but same size) ciphers as follows

Swift cipher = bdwO/5C8a+pliIoIXtuzfA==

PHP cipher = oPotHCkxpOwQhIaCz6hNMw==

In both cases (Swift and PHP), the cipher is decrypted correctly regardless of the size of the plaintext. Also, the Swift results are consistent with the Objective-C version of the code

Attached the simplified code used:

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>";

Swift

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)

Why are these different?

解决方案

This is due to padding mode differences.

PHP uses "zero padding" if the plain text is not N-times the block size. So PHP pads 0..15 bytes with value 00 for 128 bit block ciphers such as AES. For plaintext that ends on a block boundary it will not add any padding bytes.

Most other languages use PKCS#7 padding, which pads up to the next block boundary, where the padding byte reflects the number of bytes added. So that would be 1..16 bytes with a value of 1..16 (or 01 to 10 in hexadecimals). For plaintext that ends on a block boundary it will add 16 bytes of padding.

PKCS#7 padding is deterministic and does not depend on the plaintext value (which could consist of bytes with any value, not just text); in other words, it can always be applied and removed independent of the content.

Zero padding has the issue that plain text ending with 00 bytes may have those 00 bytes removed during unpadding. This is usually not an issue for ASCII compatible strings as 00 is a control character, usually meaning End Of File (EOF).

Please check the comments on mcrypt_encrypt to see how you can apply PKCS#7 padding to PHP.

这篇关于在Swift(iOS)和PHP中的AES256加密中有不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆