【问题标题】:Why does this AES encryption on an iPad and decryption in PHP fail?为什么 iPad 上的 AES 加密和 PHP 中的解密失败?
【发布时间】:2011-10-26 23:40:07
【问题描述】:

我有一个 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

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

【问题讨论】:

    标签: php objective-c ios ipad


    【解决方案1】:

    检查您正在使用的密钥。在 PHP 中,MCRYPT_RIJNDAEL_128 _256 等常量并不代表密钥强度,而是正在使用的块大小。

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

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

    另一个想法。看起来您在 C 中使用 PKCS#7 填充。我不相信 PHP 旨在默认使用该填充。如果没记错的话,我相信 Mcrypt 函数使用空填充。

    最后检查你在 PHP 中的初始化向量。我注意到您没有在 C 代码中使用一个,这意味着您不应该在 PHP 中接受 $iv 变量。这应该作为 NULL 传递到 mcrypt 函数中(但强烈建议不要这样做)。

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

    【讨论】:

    • 但是当我解密任何带有“é”的密码时,我会得到这个 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 中是 not 可选的,我认为您正在切片某些东西并将其用作 IV,这会导致您的 IV 和密文都不正确,从而导致输出损坏。
    【解决方案2】:

    请参阅此讨论以更好地使用 AES 加密/解密 AES with CommonCrypto uses too much memory - Objective-C

    【讨论】:

      猜你喜欢
      • 2011-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2021-04-13
      • 2014-07-01
      • 1970-01-01
      相关资源
      最近更新 更多