AES 128解密失败

时间:2015-01-29 22:20:23

标签: php objective-c encryption mcrypt

我有一个使用AES 128 CBC加密数据的iOS应用程序。我可以在objective-c中对应用程序中的数据进行解密,这样至少可以告诉我加密在该上下文中正常工作(Common Crypto)。问题是我需要将这些加密数据发送到服务器并通过PHP解密。这就是我失败的地方。

我使用openssl手动在命令行上进行了加密。使用该输出并将其反馈回此php函数,我可以正确解密,所以我知道php函数正常工作,至少相对于openssl。因此,问题是如何让Objective-C以与openssl相同的方式输出密文(或者如何让php解密来自Common Crypto的密文)。换句话说,这些功能中的每一个都在其自身的环境中“起作用”。

<?php

function jsonEncode ($result, $message) {
    $arr = array('result' => $result, 'message' => $message);
    echo json_encode($arr);
}


//$ciphertext = base64_decode($_POST['ciphertext']);
//$iv         = $_POST['iv'];

// overriding the http post values with values copied in from console output for testing
$ciphertext = base64_decode('dwb7MWCQUUiVuJLzL2EzYm0NcodwORP47qPhLzaolAk=');
// openssl on the command line yields ciphertext of
//  'gRiOXseXTjhpPCiiHgnaQQoal3a9E87Gx3FVpZPtR1I=' which decrypts successfully
$iv = 'hkPDfznq1t1UpKrW';
$key = 'T8ZvJba0HHsmiVSD';

//$plaintext = openssl_decrypt($ciphertext, 'aes-128-cbc', $key, false, $iv);
//jsonEncode('success', $plaintext);

// this is the line that fails
$plaintext = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext, MCRYPT_MODE_CBC, $iv);
//$padding = ord($plaintext[strlen($plaintext) - 1]);
//jsonEncode('success', substr($plaintext, 0, -$padding));
jsonEncode('success', $plaintext);
?>

编辑:根据下面@Zaph的非常有用的评论,我在Objective-C中重写了我的加密函数来手动填充。我认为这是正确的。但是,当php函数返回时,mcrypt_decrypt函数的计算结果为false。这是新的Objective C功能:

- (NSData *)AES128EncryptWithKey:(NSString *)key iv:(NSString *)iv
{
    char keyPtr[kCCKeySizeAES128+1];
    bzero(keyPtr, sizeof(keyPtr));

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

    char ivPtr[kCCBlockSizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    if (iv) {
        [iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    }

    NSUInteger dataLength = [self length];
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
    int newSize = 0;

    if(diff > 0) {
        newSize = (int)(dataLength + diff);
    }

    // manually add padding to the end of the data array
    char dataPtr[newSize];
    memcpy(dataPtr, [self bytes], [self length]);
    for(int i = 0; i < diff; i++) {
        dataPtr[i + dataLength] = diff;
    }
    dataPtr[newSize] = '\0';

    size_t bufferSize = newSize + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    // print out the padded array for verification
    NSLog(@"diff: %d  new size: %d", diff, newSize);
    for (int i=0; i<newSize; i++)
        printf("0x%x ", dataPtr[i]);

    printf("\n");


    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          0x0000, //No padding
                                          keyPtr,
                                          kCCKeySizeAES128,
                                          ivPtr,
                                          dataPtr,
                                          sizeof(dataPtr),
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);

    if(cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    return nil;
}

Objective C控制台输出:

diff: 12  new size: 32
0x65 0x6e 0x63 0x72 0x79 0x70 0x74 0x69 0x6f 0x6e 0x20 0x69 0x73 0x20 0x74 0x72 0x69 0x63 0x6b 0x79 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 0xc 
encrypted text: dwb7MWCQUUiVuJLzL2EzYm0NcodwORP47qPhLzaolAk=

纯文本是'加密很棘手'。

1 个答案:

答案 0 :(得分:1)

php不支持kCCOptionPKCS7Padding,它有自己的想法应该如何填充。因此,您必须在CCCrypt之前提供填充。或者在php的代码中执行PKCS#7填充。 (顺便说一句:PKCS#5和PKCS#7填充基本相同。)

你应该看到第一个在第一个解密的块在php中解密,如果不存在另外的问题。

这是我的null(php)填充方法:

+ (NSData *)phpPadData:(NSData *)data {
    NSMutableData *newData = [data mutableCopy];
    NSUInteger paddLength = kCCBlockSizeAES128 - (data.length % kCCBlockSizeAES128);
    [newData increaseLengthBy:paddLength];

    return [newData copy];
}

当我使用它编码“加密很棘手”时,我得到:

ciphertextData: 81188e5e c7974e38 693c28a2 1e09da41 a5d64983 e124b73c 36da520a 8198d3e7
ciphertextBase64: gRiOXseXTjhpPCiiHgnaQaXWSYPhJLc8NtpSCoGY0+c=

如果我使用在线网站,那就完全相同:http://aes.online-domain-tools.com(可能使用的是php mcrypt)。这与问题中的OpenSSL不同。

这是我的测试代码,我将字符串与加密中的数据编码分开。我将thes类方法放在类名Test中,任何类都可以。

+ (NSString *)encryptCleartextString:(NSString *)cleartextString keyString:(NSString *)keyString ivString:(NSString *)ivString {
    NSData *cleartext = [cleartextString dataUsingEncoding:NSUTF8StringEncoding];
    NSData *key       = [keyString       dataUsingEncoding:NSUTF8StringEncoding];
    NSData *iv        = [ivString        dataUsingEncoding:NSUTF8StringEncoding];

    NSData *ciphertext = [Test phpEncryptCleartext:cleartext key:key iv:iv];
    NSLog(@"ciphertext: %@", ciphertext);
    NSString *ciphertextString = [ciphertext base64EncodedStringWithOptions:0];
    NSLog(@"ciphertextString: %@", ciphertextString);

    return ciphertextString;
}

+ (NSData *)phpEncryptCleartext:(NSData *)cleartext key:(NSData *)key iv:(NSData *)iv {
    NSLog(@"phpEncryptCleartext");
    NSLog(@"cleartext: %@", cleartext);
    NSLog(@"key:       %@", key);
    NSLog(@"iv:        %@", iv);

    NSData *cleartextPadded = [self phpPadData:cleartext];
    NSLog(@"cleartextPadded: %@", cleartextPadded);

    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
    NSMutableData  *ciphertext    = [NSMutableData dataWithLength:cleartextPadded.length];

    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmAES128,
                       0,
                       key.bytes,
                       kCCKeySizeAES128,
                       iv.bytes,
                       cleartextPadded.bytes,
                       cleartextPadded.length,
                       ciphertext.mutableBytes,
                       ciphertext.length,
                       &cryptBytes);

    if (ccStatus == kCCSuccess) {
        ciphertext.length = cryptBytes;
    }
    else {
        NSLog(@"kEncryptionError code: %d", ccStatus); // Add error handling
        ciphertext = nil;
    }
    NSLog(@"ciphertext:               %@", ciphertext);

    return ciphertext;
}

// Test code
NSString *cleartextString = @"encryption is tricky";
NSString *ivString  = @"hkPDfznq1t1UpKrW";
NSString *keyString = @"T8ZvJba0HHsmiVSD";

NSString *encryptedTextBase64 = [Test encryptCleartextString:cleartextString keyString:keyString ivString:ivString];
NSLog(@"encryptedTextBase64:     %@", encryptedTextBase64);