【问题标题】:How to decrypt a file in Objective C/IOS that is encrypted in php?如何解密在 php 中加密的 Objective C/IOS 中的文件?
【发布时间】:2012-05-08 06:16:25
【问题描述】:

我为这个错误搜索了太多,但没有发现任何有用的信息。 我得到一个使用以下代码在 php 中加密的文件:

mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $privateencryptkey, base64_encode(file), MCRYPT_MODE_CBC, $hardvector);

我无法在 IOS 中解密它。我尝试了许多库,如 NSDATA+CommonCrypto、NSFileManager-AES、NSDATA-aes,但我没有成功解密文件。

以下是使用的 Objective-C 代码:

- (NSData *)AESDecryptWithPassphrase:(NSString *)pass
{
    NSMutableData *ret = [NSMutableData dataWithCapacity:[self length]];
    unsigned long rk[RKLENGTH(KEYBITS)];
    unsigned char key[KEYLENGTH(KEYBITS)];
    const char *password = [pass UTF8String];
    for (int i = 0; i < sizeof(key); i++)
        key[i] = password != 0 ? *password++ : 0;

    int nrounds = rijndaelSetupDecrypt(rk, key, KEYBITS);
    unsigned char *srcBytes = (unsigned char *)[self bytes];
    int index = 0;
    while (index < [self length])
    {
        unsigned char plaintext[16];
        unsigned char ciphertext[16];
        int j;
        for (j = 0; j < sizeof(ciphertext); j++)
        {
            if (index >= [self length])
                break;

            ciphertext[j] = srcBytes[index++];
        }
        rijndaelDecrypt(rk, nrounds, ciphertext, plaintext);
        [ret appendBytes:plaintext length:sizeof(plaintext)];

    }
    return ret;
}

此代码适用于文本,但无法解密文件。 当我保存解密的文件时,它会说文件系统错误。那些解密后的文件无法在任何系统上打开,我认为文件格式在这个过程中被打乱了。

我也尝试了以下代码,但没有成功:

- (NSData *) decryptedDataUsingAlgorithm: (CCAlgorithm) algorithm
                                     key: (id) key      // data or string
                    initializationVector: (id) iv       // data or string
                                 options: (CCOptions) options
                                   error: (CCCryptorStatus *) error
{
    CCCryptorRef cryptor = NULL;
    CCCryptorStatus status = kCCSuccess;

    NSParameterAssert([key isKindOfClass: [NSData class]] || [key isKindOfClass: [NSString class]]);
    NSParameterAssert(iv == nil || [iv isKindOfClass: [NSData class]] || [iv isKindOfClass: [NSString class]]);

    NSMutableData * keyData, * ivData;
    if ( [key isKindOfClass: [NSData class]] )
        keyData = (NSMutableData *) [key mutableCopy];
    else
        keyData = [[key dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];

    if ( [iv isKindOfClass: [NSString class]] )
        ivData = [[iv dataUsingEncoding: NSUTF8StringEncoding] mutableCopy];
    else
        ivData = (NSMutableData *) [iv mutableCopy];    // data or nil

    [keyData autorelease];
    [ivData autorelease];

    // ensure correct lengths for key and iv data, based on algorithms
    FixKeyLengths( algorithm, keyData, ivData );

    status = CCCryptorCreate( kCCDecrypt, algorithm, options,
                              [keyData bytes], [keyData length], [ivData bytes],
                              &cryptor );

    if ( status != kCCSuccess )
    {
        if ( error != NULL )
            *error = status;
        return ( nil );
    }

    NSData * result = [self _runCryptor: cryptor result: &status];
    if ( (result == nil) && (error != NULL) )
        *error = status;

    CCCryptorRelease( cryptor );

    return ( result );
}

上面代码的第二个函数:

- (NSData *) _runCryptor: (CCCryptorRef) cryptor result: (CCCryptorStatus *) status
{
    size_t bufsize = CCCryptorGetOutputLength( cryptor, (size_t)[self length], true );
    void * buf = malloc( bufsize );
    size_t bufused = 0;
    size_t bytesTotal = 0;
    *status = CCCryptorUpdate( cryptor, [self bytes], (size_t)[self length], 
                              buf, bufsize, &bufused );
    if ( *status != kCCSuccess )
    {
        free( buf );
        return ( nil );
    }

    bytesTotal += bufused;

    // From Brent Royal-Gordon (Twitter: architechies):
    //  Need to update buf ptr past used bytes when calling CCCryptorFinal()
    *status = CCCryptorFinal( cryptor, buf + bufused, bufsize - bufused, &bufused );
    if ( *status != kCCSuccess )
    {
        free( buf );
        return ( nil );
    }

    bytesTotal += bufused;

    return ( [NSData dataWithBytesNoCopy: buf length: bytesTotal] );
}

我已经一个星期没能解决这个问题了……

【问题讨论】:

    标签: iphone objective-c ios encryption


    【解决方案1】:

    需要注意的一点是 mcrypt_encrypt 的文件参数,似乎该文件在加密之前是经过 base64 编码的(这没有任何意义),这意味着您必须在解密后进行 base64 解码。

    其他参数很简单:
    MCRYPT_RIJNDAEL_128 是 AES,128 具有 128 位密钥
    MCRYPT_MODE_CBC 是 cbc 模式,CommonCrypto 的默认值。
    块大小的填充是空字符,而不是标准的,因此非填充长度可能是一个问题。

    并不是说您还需要另一种 AES 方法,这是我使用的方法:

    #import <CommonCrypto/CommonCryptor.h>
    
    + (NSData *)doCipher:(NSData *)dataIn
                      iv:(NSData *)iv
                     key:(NSData *)symmetricKey
                 context:(CCOperation)encryptOrDecrypt
    {
        CCCryptorStatus ccStatus   = kCCSuccess;
        size_t          cryptBytes = 0;    // Number of bytes moved to buffer.
        NSMutableData  *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];
    
        ccStatus = CCCrypt( encryptOrDecrypt,
                           kCCAlgorithmAES128,
                           kCCOptionPKCS7Padding,
                           symmetricKey.bytes, 
                           kCCKeySizeAES128,
                           iv.bytes,
                           dataIn.bytes,
                           dataIn.length,
                           dataOut.mutableBytes,
                           dataOut.length,
                           &cryptBytes);
    
        if (ccStatus != kCCSuccess) {
            NSLog(@"CCCrypt status: %d", ccStatus);
        }
    
        dataOut.length = cryptBytes;
    
        return dataOut;
    }
    // Also add Security.framework to your project.
    

    请注意,它需要 NSData 输入,并且填充被指定为标准 PKCS。

    CommonCryptor.h

    【讨论】:

    • 感谢您的回答 Zaph。现在我已经使用了上面给定的函数,但它返回以下错误:CCCrypt 状态:-4304 .. 如果我需要做其他事情,请建议。我们是否还需要在 php 端更改某些内容?谢谢。
    • 从头文件中:“kCCDecodeError= -4304,输入数据没有正确解码或解密”。这个错误很难得到,我最好的猜测是填充,因为 php 似乎使用非标准填充,而不是 kCCOptionPKCS7Padding 为该参数传递 0。有关填充信息,请参阅mcrypt_encrypt man page
    • 修改padding后解密成功。但是我怎样才能对 nsdata 进行 base 64 解码,因为我在解密文件后得到的 nsdata 没有被转换为字符串,它显示“无效的 CF 字符串”。我正在使用以下函数从 NSData 生成字符串: NSString *sttr = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
    • 对于 Base64 解码,您必须使用 3rd 方代码,请参阅 Cocoa With Love Base64 blog entry。请记住,您可能需要删除填充,可能尾随 0 个字符。
    • 如何从文件中删除填充?
    猜你喜欢
    • 2014-01-13
    • 1970-01-01
    • 2012-07-12
    • 2016-07-28
    • 2014-05-30
    • 2016-03-19
    • 2020-04-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多