4

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
0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
  • @Bhavin 'ccStatus = CCCrypt(...);' is the culprit here. – 0xC0DED00D May 01 '15 at 10:13
  • ok..had you check this link...http://stackoverflow.com/questions/11717193/exc-bad-access-code-2 – Bhavin Bhadani May 01 '15 at 10:15
  • 1
    ECB mode does not use an iv. – zaph May 01 '15 at 11:29
  • 1
    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`. – zaph May 01 '15 at 15:16
  • 1
    Note that in the updated answer you did not specify ECB mode, the default is CBC mode. You need to add `kCCOptionECBMode`. – zaph May 01 '15 at 15:27
  • With the two above changes to the update code (key=12345679 and ECB Mode) it will produce the same result as my answer. – zaph May 01 '15 at 15:33
  • @Zaph Thanks for the comments. This actually solves the encryption part in both the code. But the decryption is not working. I am getting `9Bo4VzSXN4CePfTX2pdtVnrwJIR6plUR` in first code while getting `WW91ciBOYW1l` in second code after decryption. I guess that's related base64 decoding. – 0xC0DED00D May 01 '15 at 15:36
  • 2
    In decrypt you do not want to Base64 encode, you want to convert the data to a `NSString`: `NSString * resultStr = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];` – zaph May 01 '15 at 16:55
  • 1
    Note: If you are 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. – zaph May 02 '15 at 05:01
  • 1
    @Zaph Thanks a ton for your help. Decryption is working in second method, but not in first one. The first one returns null string. But that's enough for me. On a second note, can you also post these comments in your answer too? That would help out others too. – 0xC0DED00D May 02 '15 at 09:20

1 Answers1

1

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.

Community
  • 1
  • 1
zaph
  • 111,848
  • 21
  • 189
  • 228
  • Thanks for the answer. However I need DES algorithm only since there's already some encrypted data which I need to decrypt too. Apart from that I checked the result from online tools and it doesn't seem to match. I am using this tool - http://codebeautify.org/encrypt-decrypt – 0xC0DED00D May 01 '15 at 13:34