0xC0DED00D
0xC0DED00D

Reputation: 20368

EXC_BAD_ACCESS Code 2 on CCCrypt

I am trying to use DES encryption to encrypt passwords (Don't ask why DES, I know it's less secure). I am doing it for the first time in iOS, thus had to rely on another post about how to do it.

When I run the encryption it returns null, same with decrypting an already encrypted string(I used an online tool to encrypt). When I put a breakpoint to see what is going on, it stopped at CCCrypt mentioning EXC_BAD_ACCESS (Code 2).

I tried using different CCOptions, but it returns the same thing always. Any hint what's going wrong? Is iv string required?

I have used the following NSString category to encrypt or decrypt Strings -

#import "NSString+DES.h"

@implementation NSString(DES)

- (NSString*) encryptDES: (NSString *) key
{
    const void *vplainText;
    size_t plainTextBufferSize;

    plainTextBufferSize = [self length];
    vplainText = (const void *) [self UTF8String];

    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t *movedBytes;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    // memset((void *) iv, 0x0, (size_t) sizeof(iv));


    //NSString *initVec = @"init Vec";
    const void *vkey = (const void *) [key UTF8String];
    //const void *vinitVec = (const void *) [initVec UTF8String];

    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmDES,
                       kCCOptionPKCS7Padding | kCCOptionECBMode,
                       vkey,
                       kCCKeySizeDES,
                       NULL,
                       vplainText,
                       plainTextBufferSize,
                       (void *)bufferPtr,
                       bufferPtrSize,
                       movedBytes);

    NSString *result;
    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return result;
}

- (NSString *) decryptDES: (NSString *) key
{
    const void *vplainText;
    size_t plainTextBufferSize;

    plainTextBufferSize = [self length];
    vplainText = (const void *) [self UTF8String];

    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t *movedBytes;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    // memset((void *) iv, 0x0, (size_t) sizeof(iv));


    //NSString *initVec = @"init Vec";
    const void *vkey = (const void *) [key UTF8String];
    //const void *vinitVec = (const void *) [initVec UTF8String];

    ccStatus = CCCrypt(kCCDecrypt,
                       kCCAlgorithmDES,
                       kCCOptionPKCS7Padding | kCCOptionECBMode,
                       vkey, //"123456789012345678901234", //key
                       kCCKeySizeDES,
                       NULL,// vinitVec, //"init Vec", //iv,
                       vplainText, //"Your Name", //plainText,
                       plainTextBufferSize,
                       (void *)bufferPtr,
                       bufferPtrSize,
                       movedBytes);

    NSString *result;
    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return result;
}

@end

Update:

I have checked few more places and changed the code a little bit, the encryption works but doesn't get decrypted with correct value.

For example when I use YourName as string and 12345 as the key, I get Fu2sK61e7l5rkXRhAKjPWA== as the encrypted code, but the decryption returns +54qWCYTB5LkdARDZjAow== and not YourName.

Updated Code:

#import "NSString+DES.h"

@implementation NSString(DES)

- (NSString*) encryptDES: (NSString *) key
{
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
    size_t numBytesEncrypted = 0;
    size_t bufferSize = stringData.length + kCCBlockSizeDES;
    void *buffer = malloc(bufferSize);

    CCCryptorStatus result = CCCrypt( kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
                                     keyData.bytes, kCCKeySizeDES,
                                     NULL,
                                     stringData.bytes, stringData.length,
                                     buffer, bufferSize,
                                     &numBytesEncrypted);
    NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
    free(buffer);
    if( result == kCCSuccess )
    {
        NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        return resultStr;
    } else {
        NSLog(@"Failed DES encrypt...");
        return nil;
    }

}

- (NSString *) decryptDES: (NSString *) key
{
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *stringData = [[NSData alloc] initWithBase64EncodedString:self options:0];

    size_t numBytesEncrypted = 0;
    size_t bufferSize = stringData.length + kCCBlockSizeDES;
    void *buffer = malloc(bufferSize);

    CCCryptorStatus result = CCCrypt( kCCDecrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
                                     keyData.bytes, kCCKeySizeDES,
                                     NULL,
                                     stringData.bytes, stringData.length,
                                     buffer, bufferSize,
                                     &numBytesEncrypted);
    NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
    free(buffer);
    if( result == kCCSuccess )
    {
        NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        return resultStr;
    } else {
        NSLog(@"Failed DES decrypt...");
        return nil;
    }
}

@end

Upvotes: 4

Views: 588

Answers (1)

zaph
zaph

Reputation: 112873

There seems to be general confusion about the algorithm, DES or 3DES, a mix is being used but the key is 3DES (24-bytes). The key needs to be changed to 8-bytes. The block size constant should also be changed to kCCBlockSizeDES but that does not cause an error since it is the same value.

For the method:

- (NSString *) decryptDES: (NSString *) key

The bad access error is caused because no storage is allocated for movedBytes, just a pointer. Change the declaration to:

size_t movedBytes;

Change the reference to movedBytes in CCCrypt to &movedBytes.

Test output for encryption:

string: "Your Name"
key: "12345678"

movedBytes: 16
myData: 136142f6 6cd98e01 af1eef46 28d36499
result: E2FC9mzZjgGvHu9GKNNkmQ==

Notes from comments by request:

ECB mode does not use an iv.

The key needs to be exactly 8-bytes for DES, if it is to short the result will be undefined. In the updated code the key is 5-bytes but the length is given as 8-bytes (kCCKeySizeDES) so the three missing key bytes will be whatever bytes follow keyData.

The updated answer did not specify ECB mode, the default is CBC mode. Add kCCOptionECBMode.

In decrypt do not use Base64 encode, convert the data to a NSString:

NSString * resultStr = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];  

If using an online encryption that uses the php mcrypt function the last block of the data will be incorrect because mcrypt does not support PKCS#7 padding, it uses non-standard and insecure null padding.

Upvotes: 1

Related Questions