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

Swift(iOS)和PHP中AES256加密的不同结果,php,ios,encryption,swift,aes,Php,Ios,Encryption,Swift,Aes,我在AES256中工作,以便能够使用不安全的通道在iOS和PHP之间进行加密/解密 我看到过许多类似的问题围绕着关键尺寸、模式(CBC或ECB)、随机iv的使用等进行讨论。但在本例中,我发现了一个奇怪的行为,如下所示 两种环境中的配置: -密钥:32字节(256位) -块大小:128位(标准) -iv:16字节(静态用于测试) -模式:CBC 如果我加密一个16或32字节的文本(以匹配AES块大小),Swift和PHP中的结果类似,但不完全相同: key=“1234567890121345678

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

我看到过许多类似的问题围绕着关键尺寸、模式(CBC或ECB)、随机iv的使用等进行讨论。但在本例中,我发现了一个奇怪的行为,如下所示

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

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

key=“123456789012134567890123456789012” 明文=“1234567890121345678901234567890123456789012” iv=“1234567890123456”

Swift密码=E5RNNLJKV4QGNGHKMWFVGMHR80NWUVHBVVFCDQ5V2KYKJTX4KFWMN4HXI4DG0B8 PHP密码=E5RNNLJKV4QGNGHKMWFVGMHR80NWUVHBVVFCPQ5V2I=

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

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

Swift密码=bdwO/5C8a+pliIoIXtuzfA==

PHP密码=oPotHCkxpOwQhIaCz6hNMw==

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

随附使用的简化代码:

PHP

$key=“1234567890012345678901234567890123456789012”;
$iv=“1234567890123456”;
$plaintext=“你好,世界”;
$ciphertext=mcrypt_encrypt(mcrypt_RIJNDAEL_128,$key,$plaintext,mcrypt_MODE_CBC,$iv);
$ciphertext\u base64=base64\u编码($ciphertext);
回显“密文:.$ciphertext_base64。”
”;
迅捷的

let keyData:NSData!=(键为NSString)。数据使用编码(NSUTF8StringEncoding)作为NSData!
让keyBytes=UnsafePointer(keyData.bytes)
let keyLength=大小(kCCKeySizeAES256)
让明文=(明文作为NSString)。dataUsingEncoding(NSUTF8StringEncoding)作为NSData!
让dataLength=UInt(plainData.length)
让dataBytes=UnsafePointer(plainData.bytes)
var bufferData=NSMutableData(长度:Int(数据长度)+KCCBLOCKSIZEAEAS128)
var bufferPointer=unsafemeutablepointer(bufferData.mutableBytes)
让bufferLength=size\u t(bufferData.length)
let操作:cOperation=UInt32(kCCEncrypt)
let算法:CCAlgorithm=UInt32(kCCAlgorithmAES128)
let options=UInt32(kCCOptionPKCS7Padding)
让ivData:NSData!=(iv作为NSString)。数据使用编码(NSUTF8StringEncoding)作为NSData!
设ivPointer=UnsafePointer(ivData.bytes)
变量numBytesEncrypted:UInt=0
var cryptStatus=CCCrypt(操作、算法、选项、keyBytes、keyLength、ivPointer、dataBytes、dataLength、bufferPointer、bufferLength和numBytesEncrypted)
bufferData.length=Int(numBytesEncrypted)
让base64cryptString=bufferData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
println(base64cryptString)

为什么这些不同?

这是由于填充模式的不同

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

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

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

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


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

请注意,自2007年左右以来,底层的
mcrypt
库尚未更新。PHP mcrypt的维护很差,并且有可怕的示例和文档(我设法重写了
mcrypt_encrypt
sample代码,但现在代码上的注释不同步)。我将调查PKCS#7填充。但我认为,如果数据块大小是AES 128位块大小(例如16或32字节)的倍增,则不应成为问题。我说的对吗?。如果是这样,您是否认为PHP中不同的密码大小可能是维护不好的旧库中的一个缺陷?。你有什么建议吗?…没有。如果大小为16字节,那么PHP不会添加任何填充。在PKCS#7填充的情况下,它将添加16个字节。请注意,我无法使用您指定的密钥和IV解密任何数据,因此我无法检查Swift实现。用两行代码完成PKCS#7填充,在PHP中修复了它。$padding=16-(strlen($plaintext)%16);$data=$plaintext.stru repeat(chr($padding),$padding)@范库洛。您需要在调用crypt_encrypt()函数之前添加两行代码,如下所示:$padding=16-(strlen($text)%16)$data=$text.str_repeat(chr($padding),$padding)$密文=mcrypt_encrypt(mcrypt_RIJNDAEL_128,$key,$data,mcrypt_MODE_CBC,$iv);我希望它能帮助。。。。。你怎么计算静脉注射?
    $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)