Using CommonCrypto with an IV but always returning nil

╄→尐↘猪︶ㄣ 提交于 2019-12-18 09:49:37

问题


I am using the CommonCrypto CCCryptorCreate to decrypt a message. I am using a password and an IV but it always returns nil.

If I use the CCCryptorCreate to decrypt, but don't use an IV on during encryption on the RUBY side and don't use the IV on the obj-c decrypt side then decryption works perfectly and I can see the message.

But if I use an IV on the RUBY and IV on the obj-c side decryption ends with a nil message object.

I am using this Encrypt in Objective-C / Decrypt in Ruby using anything

OBJ-C method:

    - (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

        #if !__has_feature(objc_arc)
            [keyData autorelease];
            [ivData autorelease];
        #endif

        // 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 );
    }




=== DOES NOT WORK ====
NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmAES128
                                                key: [[password dataUsingEncoding:NSUTF8StringEncoding] SHA256Hash]
                               initializationVector: [anIV dataUsingEncoding:NSUTF8StringEncoding]
                                            options: kCCOptionPKCS7Padding
                                              error: &status];


=== DOES WORK ===
NSData * result = [self decryptedDataUsingAlgorithm: kCCAlgorithmAES128
                                                key: [[password dataUsingEncoding:NSUTF8StringEncoding] SHA256Hash]
                               initializationVector: nil
                                            options: kCCOptionPKCS7Padding
                                              error: &status];

回答1:


Looks like the iv may be different, ensure that the data bytes are the same and the length is correct.

You want CCCrypt to do one-shot encryption.

From Apple: CCCrypt is a Stateless, one-shot encrypt or decrypt operation. This basically performs a sequence of CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease().

Since you are not using CCCrypt then you will have to at least add CCCryptorFinal() to your example.

Also note that the key and iv really need to be exactly the correct size in bytes. Using NSUTF8StringEncoding may not produce the number of bytes expected if there are some characters that require multiple byte encodings. Note: "i" can be encoded as a surrogate pair.

Do not use a password string without using PBKDF2 to generate a good key.

Consider using RNCryptor unless you really know what you are doing with crypto.

Here is simple example code of a one-shot encrypt/decrypy method
The key and iv must be exactly the required length.
Any encoding (Base64, NSString, etc) is done outside of this method.

+ (NSData *)doCipher:(NSData *)dataIn
                  iv:(NSData *)iv
                 key:(NSData *)symmetricKey
             context:(CCOperation)encryptOrDecrypt // kCCEncrypt or kCCDecrypt
               error:(NSError **)error
{
    CCCryptorStatus ccStatus   = kCCSuccess;
    size_t          cryptBytes = 0;
    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) {
        dataOut.length = cryptBytes;
    }
    else {
        if (error) {
            *error = [NSError errorWithDomain:@"kEncryptionError"
                                         code:ccStatus
                                     userInfo:nil];
        }
        dataOut = nil;
    }

    return dataOut;
}


来源:https://stackoverflow.com/questions/24456020/using-commoncrypto-with-an-iv-but-always-returning-nil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!