php iOS和PHP之间的AESCrypt解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6461419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 00:27:33  来源:igfitidea点击:

AESCrypt decryption between iOS and PHP

phpiphoneiosencryption

提问by Nils Munch

I am having a heck of a time figuring out how to decrypt a string encrypted with the NSData+AESCrypt.m (Explained here)

我花了很长时间弄清楚如何解密用 NSData+AESCrypt.m 加密的字符串(在此处解释

I have been looking at a handful of other threads, but I only need the iDevice to send a string to a PHP file encrypted, and then it gets decrypted inside PHP (where it gets stored into a database).

我一直在查看其他一些线程,但我只需要 iDevice 将一个字符串发送到一个加密的 PHP 文件,然后它在 PHP 中被解密(它被存储到数据库中)。

This code :

此代码:

NSString *encryptedString = [@"Hello" AES256EncryptWithKey:@"a16byteslongkey!"];
NSLog(@"The strign encrypted : %@",encryptedString);

Returns the string encrypted : 7opqbb7sEVNoXplyQv/X8g==

返回加密的字符串:7opqbb7sEVNoXplyQv/X8g==

And here is my PHP code for decryption:

这是我用于解密的 PHP 代码:

function decrypt_data($data, $key) {
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key,$data,MCRYPT_MODE_ECB);
}

function unpadPKCS7($data, $blockSize) {
    $length = strlen ( $data );
    if ($length > 0) {
        $first = substr ( $data, - 1 );

        if (ord ( $first ) <= $blockSize) {
            for($i = $length - 2; $i > 0; $i --)
                if (ord ( $data [$i] != $first ))
                    break;

            return substr ( $data, 0, $i );
        }
    }
    return $data;
}

function decrypt_string($string) {
    $string = unpadPKCS7($string,128);
    $string = decrypt_data($string,"a16byteslongkey!");
    return $string;
}
die('<br>Basic :'.decrypt_string('7opqbb7sEVNoXplyQv/X8g=='));

UPDATE:

更新:

Been doing some MD5 decryption and experimenting a lot, but still far from achieving usable results. This is what I got so far:

做了一些 MD5 解密并进行了大量实验,但仍远未达到可用的结果。这是我到目前为止得到的:

Original string : Hello
AES256Encrypt result : 7opqbb7sEVNoXplyQv/X8
base64_decode Decrypted: ??jm?ìSh^?rB?×
mcrypt_rijndael_128 : ?ˉ????(ás2''u)
mcrypt_rijndael_128 & hex2bin : U?)?±+úy′e

Sadly, no matter how I bend and twist this, I just get jibberish. Can anyone see what I'm doing wrong?

可悲的是,无论我如何弯曲和扭曲它,我都会胡言乱语。谁能看到我做错了什么?

回答by Tails

Disclaimer: I have zero iPhone development experience.

免责声明:我的 iPhone 开发经验为零。

Short answer - what tc. said. Something is horribly wrong with the AES256EncryptWithKey:

简短的回答 - 什么 tc。说过。有什么可怕的错误AES256EncryptWithKey

Being AES256 you would expect it to require a 32 byte key, not a 16 byte key. But OK, say it pads shorter keys with null bytes to make them 32 bytes. This might explain why your 16 byte key is being padded with 16 null characters.

作为 AES256,您会期望它需要 32 字节的密钥,而不是 16 字节的密钥。但是好吧,假设它用空字节填充较短的键,使它们成为 32 个字节。这可能解释了为什么您的 16 字节密钥被 16 个空字符填充。

But, when it comes to the actual act of encryption, it's using AES 128, but with the 32 byte key. Say wha?

但是,当涉及到实际的加密行为时,它使用的是 AES 128,但使用 32 字节的密钥。说啥?

Converting tc.'s Python to PHP:

将 tc. 的 Python 转换为 PHP:

$base64encoded_ciphertext = '7opqbb7sEVNoXplyQv/X8g==';
$key = 'a16byteslongkey!';

$padded_key = $key . str_repeat(chr(0x00), 16); // Argh!

$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $padded_key, base64_decode($base64encoded_ciphertext), 'ecb');

// Yetch - $result ends up being padded with 0x0b's (vertical tab).
var_dump(rtrim($result, chr(0x0b)));

Result:

结果:

string(5) "Hello"

字符串(5)“你好”

~~

~~

Edit: This postfrom Henno has some relevant details.

编辑:来自 Henno 的这篇文章有一些相关的细节。

~~

~~

Did some additional research. The null padding on your key is likely because AES256 requires a 32 byte key. The 0x0B padding on the plaintext is thanks to PKCS7. PKCS7 is a padding scheme where the byte used for padding is equal in value to the number of bytes added. In this example, 11 bytes were added to the end of 'Hello' turning your 5 byte input into a 16 byte block for AES. 11 = 0x0B.

做了一些额外的研究。密钥上的空填充可能是因为 AES256 需要 32 字节的密钥。明文上的 0x0B 填充归功于PKCS7。PKCS7 是一种填充方案,其中用于填充的字节的值等于添加的字节数。在此示例中,将 11 个字节添加到“Hello”的末尾,将您的 5 字节输入转换为 AES 的 16 字节块。11 = 0x0B。

Thus, the code above will not work when the plaintext is not length = 5. Try the following instead:

因此,当明文不是 length = 5 时,上面的代码将不起作用。请尝试以下操作:

$pad_char = ord(substr($result, -1));
$result_without_padding = substr($result, 0, strlen($result) - $pad_char);

回答by tangrs

The encrypted string looks like it's been base64 encoded. Try decoding it before you decrypt it.

加密的字符串看起来像是经过 base64 编码的。在解密之前尝试对其进行解码。

回答by tc.

First off, the Objective-C code you're using is pretty terrible:

首先,您使用的 Objective-C 代码非常糟糕:

  • The keyspace is severely limited (presumably UTF-8 bytes terminated by a null byte, extended with null bytes to 32 bytes). The easiest way to generate a random key is to stick to ASCII, which limits you to about 223.6 bits for the default key size of 256 bits.
  • Encryption is done in ECB mode.
  • Data appears to be irreversibly padded with 0x0B.
  • 密钥空间受到严重限制(大概是 UTF-8 字节以空字节结束,用空字节扩展到 32 字节)。生成随机密钥的最简单方法是坚持使用 ASCII,对于 256 位的默认密钥大小,ASCII 将您限制为大约 223.6 位。
  • 加密是在 ECB 模式下完成的。
  • 数据似乎不可逆转地填充了 0x0B。

Avoid it at all costs. It is not secure.

不惜一切代价避免它。它不安全。

It can be "decrypted" in Python with something like this:

它可以在 Python 中“解密”,如下所示:

>>> import Crypto.Cipher.AES
>>> import base64
>>> Crypto.Cipher.AES.new('a16byteslongkey!'+'
$iv2 = '';
for($i=0;$i<16;$i++){
    $iv2 .= "##代码##";   
}
$plain_text_CBC = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_text, MCRYPT_MODE_CBC, $iv2);
var_dump($plain_text_CBC);
'*16).decrypt(base64.b64decode('7opqbb7sEVNoXplyQv/X8g==')) 'Hello\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'

回答by user1122069

see my post here: PHP iOS AES Encryption

在此处查看我的帖子:PHP iOS AES 加密



I just got through this same sort of project. I used the library you referenced in "also considered..."

我刚刚完成了同样的项目。我使用了您在“也考虑过……”中引用的库

Here is some example code to decrypt with php:

下面是一些用 php 解密的示例代码:

##代码##

Make sure your keys are both 256-bit (32 characters, I have not yet had any encoding issues, but if you do, remember that you are encrypting bytes, not characters). Note that 128 in MCRYPT_RIJNDAEL_128 is the block size and not the key size, while in the method AES256DecryptWithKey, 256 is a reference to the key size, while the block size is 128. AES256DecryptWithKey runs in CBC mode, but has a null initialization vector (iv).

确保您的密钥都是 256 位(32 个字符,我还没有遇到任何编码问题,但如果您这样做了,请记住您正在加密字节,而不是字符)。请注意,MCRYPT_RIJNDAEL_128 中的 128 是块大小而不是密钥大小,而在方法 AES256DecryptWithKey 中,256 是对密钥大小的引用,而块大小为 128。 AES256DecryptWithKey 运行在 CBC 模式下,但具有空初始化向量( iv).

CBC means that each block depends on the last block, and so it uses a pre-set, usually random, "block -1" called the IV

CBC 意味着每个块都依赖于最后一个块,因此它使用一个预先设置的,通常是随机的“块 -1”,称为 IV

ECB means that each block is encrypted in the same way, hence it reveals when two blocks in the same message are the same. The library mentioned does not use it, so I mentioned it just for contrast.

ECB 意味着每个块都以相同的方式加密,因此它会揭示同一消息中的两个块何时相同。提到的库没有使用它,所以我提到它只是为了对比。

The use of a zero iv (0000000000000000 in bytes) is considered insecure, but it does provide you with some additional security (but one might still be able to tell if the fist 16 characters of your plain text were the same each time). To fix this you would have to create an NSData *iv variable for the IV and modify the CCcrypt argument of NSData+AESCrypt.m to add [iv bytes] for the iv parameter (I have not yet tested this code), and you would need to store this iv and pass it to the php along with you message. But first I would test and have everything working with a zero iv.

使用零 iv(以字节为单位的 0000000000000000)被认为是不安全的,但它确实为您提供了一些额外的安全性(但人们可能仍然能够判断您的纯文本的前 16 个字符是否每次都相同)。要解决此问题,您必须为 IV 创建一个 NSData *iv 变量并修改 NSData+AESCrypt.m 的 CCcrypt 参数以添加 [iv bytes] 为 iv 参数(我尚未测试此代码),并且您将需要存储此 iv 并将其与您的消息一起传递给 php。但首先我会测试并让一切都在零 iv 下工作。