为什么iPad上的AES加密和PHP中的解密都失败了?

为什么iPad上的AES加密和PHP中的解密都失败了?,php,objective-c,ios,ipad,Php,Objective C,Ios,Ipad,我有一个iPad应用程序,可以将加密信息传输到基于PHP的网站,但我很难正确解密这些信息。我使用以下代码进行PHP端解密: //Decryption function function mc_decrypt($decrypt, $key, $iv) { $decoded = base64_decode($decrypt); $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');

我有一个iPad应用程序,可以将加密信息传输到基于PHP的网站,但我很难正确解密这些信息。我使用以下代码进行PHP端解密:

//Decryption function

function mc_decrypt($decrypt, $key, $iv)  
{  
    $decoded = base64_decode($decrypt);  
    $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');  
    mcrypt_generic_init($td, $key, $iv);  
    $decrypted = mdecrypt_generic($td, $decoded);  
    mcrypt_generic_deinit($td);  
    mcrypt_module_close($td);  
    return trim($decrypted);  
}  
我的iPad应用程序中的Objective-C代码:

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

@end
#导入
@实现NSData(AES256)
-(NSData*)AES256EncryptWithKey:(NSString*)密钥{
//AES256的“键”应为32字节,否则将填充为空
char keyPtr[kCCKeySizeAES256+1];//为终止符预留的空间(未使用)
bzero(keyPtr,sizeof(keyPtr));//用零填充(用于填充)
//获取关键数据
[key-getCString:keyPtr-maxLength:sizeof(keyPtr)编码:NSUTF8StringEncoding];
NSU整数数据长度=[自身长度];
//参见文档:对于分组密码,输出大小将始终小于或
//等于输入大小加上一个块的大小。
//这就是为什么我们需要在这里添加一个块的大小
size\u t bufferSize=dataLength+kccblocksizeaaes128;
void*buffer=malloc(bufferSize);
大小\u t numBytesEncrypted=0;
CCCryptorStatus cryptStatus=CCCrypt(kCCEncrypt,kCCAlgorithmAES128,kCCOptionPKCS7Padding,
keyPtr,kCCKeySizeAES256,
NULL/*初始化向量(可选)*/,,
[self bytes],数据长度,/*输入*/
缓冲区,缓冲区大小,/*输出*/
&(未加密);
if(cryptStatus==kCCSuccess){
//返回的NSData拥有缓冲区的所有权,并在释放时释放缓冲区
返回[NSData DATAFTHBYTESNOCOPY:缓冲区长度:numBytesEncrypted];
}
释放(缓冲区);//释放缓冲区;
返回零;
}
-(NSData*)AES256DecryptWithKey:(NSString*)密钥{
//AES256的“键”应为32字节,否则将填充为空
char keyPtr[kCCKeySizeAES256+1];//为终止符预留的空间(未使用)
bzero(keyPtr,sizeof(keyPtr));//用零填充(用于填充)
//获取关键数据
[key-getCString:keyPtr-maxLength:sizeof(keyPtr)编码:NSUTF8StringEncoding];
NSU整数数据长度=[自身长度];
//参见文档:对于分组密码,输出大小将始终小于或
//等于输入大小加上一个块的大小。
//这就是为什么我们需要在这里添加一个块的大小
size\u t bufferSize=dataLength+kccblocksizeaaes128;
void*buffer=malloc(bufferSize);
大小\u t numBytesDecrypted=0;
CCCryptorStatus cryptStatus=CCCrypt(kCCDecrypt,kCCAlgorithmAES128,kCCOptionPKCS7Padding,
keyPtr,kCCKeySizeAES256,
NULL/*初始化向量(可选)*/,,
[self bytes],数据长度,/*输入*/
缓冲区,缓冲区大小,/*输出*/
&不加密);
if(cryptStatus==kCCSuccess){
//返回的NSData拥有缓冲区的所有权,并在释放时释放缓冲区
返回[NSData DATAFTHBYTESNOPY:缓冲区长度:numbytes加密];
}
释放(缓冲区);//释放缓冲区;
返回零;
}
@结束

为什么我在解密iPad上编码的数据和PHP端解密的数据时会看到数据损坏?

检查您使用的密钥。在PHP中,MCRYPT_RIJNDAEL_128_256 etc常量并不表示密钥强度,而是表示所使用的块大小

要使用PHP实现128位加密,您需要使用16字节长的密钥。对于256,您需要32个字节,以此类推

你的PHP和C代码在我看来都是正确的。确保在这两种情况下都正确使用了钥匙

另一个想法是。看起来您在C中使用的是PKCS#7填充。我不相信PHP在默认情况下可以使用这种填充。如果内存对我有用的话,我相信Mcrypt函数使用空填充

最后检查PHP中的初始化向量。我注意到您在C代码中没有使用一个变量,这意味着您不应该在PHP中接受$iv变量。这应该作为NULL传递到mcrypt函数中(但这是非常不鼓励的)


你应该做的是在你的C代码中随机设置一个IV(数据被加密的地方),然后将IV和加密的数据一起发送。您可以检测正在使用的算法的IV的大小,并将其从加密数据的前端分离出来,然后用于填充PHP方面的内容。这将进一步保护您的加密。

请参阅本讨论,以更好地使用AES加密/解密

但是当我解密任何带有“é”的密码时,我会得到这个né这是一个文本编码问题(例如,UTF-8)。它与加密无关。双向加密可用于对任何数据进行编码。不仅仅是字符串。因此,解密的输出实际上是二进制信息。如果该信息恰好映射到UTF字符串,您将获得所需的输出。您是否检查了PHP中$iv参数的问题?您的C代码中没有使用IV,因此不应该使用IV进行解密。你之所以会胡言乱语,是因为解密没有正确执行。解密并不“验证”,它只是运行算法并给出输出。这取决于您确定它是否有效。为了澄清,我在这里指的是函数mc_decrypt($decrypt,$key,$iv)声明和$iv变量的用法:mcrypt_generic_init($td,$key,$iv);VS这里的C代码:NULL/*初始化向量(可选)*/因为您没有使用IV,并且$IV参数在PHP中不是可选的,我假设您正在切掉一些东西并将其用作IV,这将导致IV和密码文本都不正确,从而导致输出损坏。