Search code examples
objective-cencryptionopensslcommoncrypto

How to port OpenSSL-based DES decryption method to CommonCrypto?


I have the following method, which I would like to port to a CommonCrypto-based approach, but I am completely stuck. Any help is highly appreciated.

- (NSString*) decryptCiscoPassword:(NSString*) encPassword
{
    NSUInteger i, k = 0;
    NSData *rawData = nil;
    int rawInt, rawDataLength = [encPassword length] >> 1;
    const char *encString = [encPassword cStringUsingEncoding:NSUTF8StringEncoding];
    const char *tmpString;
    unsigned char *rawDataBytes = (unsigned char*) malloc(rawDataLength*sizeof(unsigned char));

    for(i = 0; i < [encPassword length]; i = i+2)
    {
        tmpString = &encString[i];
        sscanf(tmpString,"%2x",&rawInt);
        rawDataBytes[k++] = (unsigned char) rawInt;
    }
    rawData = [NSData dataWithBytesNoCopy:rawDataBytes length:rawDataLength freeWhenDone:YES];

    /* now let's start the decryption */

    NSString *returnString = nil;

    /* --- calculate 3DES-Key --- */
    DES_cblock desKey1, desKey2, desKey3;

    unsigned char tempHash[20];
    [rawData getBytes:tempHash length:20];
    tempHash[19]++;

    unsigned char hashV1[20];
    CC_SHA1(tempHash,20,hashV1);

    unsigned char hashV2[20];
    tempHash[19] += 2;
    CC_SHA1(tempHash,20,hashV2);

    memcpy(&desKey1, hashV1, 8);
    memcpy(&desKey2, &hashV1[8], 8);
    memcpy(&desKey3, &hashV1[16], 4);
    memcpy(&desKey3[4], hashV2, 4);

    /* --- Decryption (8 byte blockSize, 24 byte Keylength) --- */
    DES_cblock iv;
    [rawData getBytes:iv length:8];
    NSInteger length = [rawData length];
    unsigned char *rawDataChar = (unsigned char*) malloc(length * sizeof(unsigned char));
    [rawData getBytes:rawDataChar length:length];

    NSInteger blockCount = (length - 40) / 8;
    if(blockCount < 1)
    {
        free(rawDataChar);
        return nil; // encPassword is no valid DES-encrypted password!
    }
    NSUInteger pwLength = blockCount*8;
    char* output = (char*) malloc(pwLength*sizeof(char));

    DES_key_schedule key_schedule1, key_schedule2, key_schedule3;

    DES_set_key_unchecked(&desKey1, &key_schedule1);     // generate key_schedule
    DES_set_key_unchecked(&desKey2, &key_schedule2);     // generate key_schedule
    DES_set_key_unchecked(&desKey3, &key_schedule3);     // generate key_schedule
    DES_ede3_cbc_encrypt((unsigned char*)&rawDataChar[40],(unsigned char*)output, pwLength,&key_schedule1,&key_schedule2,&key_schedule3,&iv,0);

    unsigned char len = output[pwLength-1];

    /* create null-terminated c-string */
    output[pwLength-len] = 0;

    /* rescue decrypted string */
    returnString = @(output);

    /* free allocated memory */
    free(rawDataChar);
    free(output);

    return returnString;

}

I already found the CommonCrypto function

CCCryptorStatus CCCrypt(CCOperation op, CCAlgorithm alg, CCOptions options, const void *key, size_t keyLength, const void *iv, const void *dataIn, size_t dataInLength, void *dataOut, size_t dataOutAvailable, size_t *dataOutMoved);

but I am not sure on how to port the OpenSSL parameters that I derive in my original method to the parameters required by CCCrypt(...).


Solution

  • I solved the task by implementing the attached replacement method. Thanks again for all the helpful and inspiring comments.

    NSString* CSDecryptCiscoPassword(NSString* encPassword)
    {
        // convert to C
        NSUInteger rawDataLength = [encPassword length] >> 1;
        const char *encString = [encPassword cStringUsingEncoding:NSUTF8StringEncoding];
    
        // convert hex to bytes
        NSUInteger k = 0;
        unsigned char rawDataBytes[rawDataLength];
        for(NSUInteger i = 0; i < [encPassword length]; i = i+2)
        {
            const char *tmpString = &encString[i];
            int rawInt;
            sscanf(tmpString,"%2x",&rawInt);
            rawDataBytes[k++] = (unsigned char) rawInt;
        }
    
        const char *h1  = (const char*)rawDataBytes;
        const char *h4  = (const char*)rawDataBytes + 20;
        const char *enc = (const char*)rawDataBytes + 40;
    
        unsigned char ht[20], h2[20], h3[20], key[24];
        const char *iv = h1;
    
        if (rawDataLength < 48)
            return nil;
        rawDataLength -= 40;
    
        memcpy(ht, h1, 20);
    
        ht[19]++;
        CC_SHA1(ht, 20, h2);
    
        ht[19] += 2;
        CC_SHA1(ht, 20, h3);
    
        memcpy(key, h2, 20);
        memcpy(key+20, h3, 4);
    
        CC_SHA1(enc, rawDataLength, ht);
    
        if (memcmp(h4, ht, 20) != 0)
            return nil;
    
        size_t outLength = 0;
        NSMutableData *outputData = [NSMutableData dataWithLength:(rawDataLength+kCCBlockSize3DES)];
    
        CCCryptorStatus result = CCCrypt(kCCDecrypt, // operation
                         kCCAlgorithm3DES, // Algorithm
                         0, // options
                         key, // key
                         24, // keylength
                         iv,// iv
                         enc, // dataIn
                         rawDataLength, // dataInLength,
                         outputData.mutableBytes, // dataOut
                         outputData.length, // dataOutAvailable
                         &outLength); // dataOutMoved
    
        NSString* outString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
    
        return [outString autorelease];
    }