Friday, April 1, 2016

How to encrypt data in core data (sqllite) in OS-X application

Leave a Comment

I have found that if I use transformable type of attributes and NSXMLStoreType my data is encrypted, that is attributes that has been of transformable type, are not readable. There is no need of doing anything else, no code is required. Please note that I am working on OS-X application that uses core data.

However, if I change my store type to NSSQLiteStoreType, that is not the case.

I can open the database with sqllitebrowser, select the transformable field, and If I click on export button, in the generated text file, I can read the value normally, that is the value (data) is not encrypted.

I have asked the same question about 4 months ago and I get no answer.

Also, I have found this post here on stackoverflow.

You can encrypt individual properties in your Core Data model entities by making them transformable properties, then creating an NSValueTransformer subclass which will encrypt and decrypt the data for that property.

Unlucky for me, the author of the answer, @Brad Larson, didn't provide an simple example of how this can be done.

Can anyone provide any sample code of how I can encrypt transformable properties so that It' cant be readable in any way?

1 Answers

Answers 1

you could do something like shown here Cross-platform-AES-encryption

add a new Objective-C file to project select category and NSData class call it Additions

NSData+Additions.h

#import <Foundation/Foundation.h> #import <CommonCrypto/CommonDigest.h> #import <CommonCrypto/CommonCryptor.h>  @interface NSData (Additions)  #pragma mark - data encryption  + (NSData *)encrypt:(NSData *)plainText key:(NSData *)key iv:(NSData *)iv; + (NSData *)decrypt:(NSData *)encryptedText key:(NSData *)key iv:(NSData *)iv;  + (NSData *)dataFromHexString:(NSString *)string; + (NSData *)sha256forData:(id)input;  + (NSData *)generateRandomIV:(size_t)length;  @end 

NSData+Additions.m

#import "NSData+Additions.h"  @implementation NSData (Additions)  + (NSData *)encrypt:(NSData *)dataToEncrypt key:(NSData *)key iv:(NSData *)iv {      NSUInteger dataLength = [dataToEncrypt length];      size_t buffSize = dataLength + kCCBlockSizeAES128;     void *buff = malloc(buffSize);      size_t numBytesEncrypted = 0;      CCCryptorStatus status = CCCrypt(kCCEncrypt,                                      kCCAlgorithmAES128,                                      kCCOptionPKCS7Padding,                                      [key bytes], kCCKeySizeAES256,                                      [iv bytes],                                      [dataToEncrypt bytes], [dataToEncrypt length],                                      buff, buffSize,                                      &numBytesEncrypted);      if (status == kCCSuccess) {         return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];     }      free(buff);     return nil; }  + (NSData *)decrypt:(NSData *)encryptedData key:(NSData *)key iv:(NSData *)iv {      NSUInteger dataLength = [encryptedData length];      size_t buffSize = dataLength + kCCBlockSizeAES128;      void *buff = malloc(buffSize);      size_t numBytesEncrypted = 0;     CCCryptorStatus status = CCCrypt(kCCDecrypt,                                      kCCAlgorithmAES128,                                      kCCOptionPKCS7Padding,                                      [key bytes], kCCKeySizeAES256,                                      [iv bytes],                                      [encryptedData bytes], [encryptedData length],                                      buff, buffSize,                                      &numBytesEncrypted);     if (status == kCCSuccess) {         return [NSData dataWithBytesNoCopy:buff length:numBytesEncrypted];     }      free(buff);     return nil; }  + (NSData *)dataFromHexString:(NSString *)string {      NSMutableData *stringData = [[NSMutableData alloc] init];     unsigned char whole_byte;     char byte_chars[3] = {'\0','\0','\0'};      for (int counter = 0; counter < [string length] / 2; counter++) {         byte_chars[0] = [string characterAtIndex:counter * 2];         byte_chars[1] = [string characterAtIndex:counter * 2 + 1];         whole_byte = strtol(byte_chars, NULL, 16);         [stringData appendBytes:&whole_byte length:1];     }      return stringData; }  + (NSData *)sha256forData:(id)input {     NSData *dataIn;      if ([input isKindOfClass:[NSString class]]) {         dataIn = [input dataUsingEncoding:NSUTF8StringEncoding];     } else if ([input isKindOfClass:[NSData class]]) {          NSUInteger dataLength = [input length];         NSMutableString *string = [NSMutableString stringWithCapacity:dataLength * 2];         const unsigned char *dataBytes = [input bytes];          for (NSInteger idx = 0; idx < dataLength; ++idx)             [string appendFormat:@"%02x", dataBytes[idx]];          dataIn = [string dataUsingEncoding:NSUTF8StringEncoding];     }      NSMutableData *macOut = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];      CC_SHA256(dataIn.bytes, (CC_LONG)[dataIn length],  [macOut mutableBytes]);      return macOut; }  + (NSData *)generateRandomIV:(size_t)length {     NSMutableData *data = [NSMutableData dataWithLength:length];      SecRandomCopyBytes(kSecRandomDefault, length, [data mutableBytes]);      return data; }  @end 

then you are going to need username, password, iVector and some random salt. in the salt i have used replace # with random characters but make sure that if u use % do not forget to double it %% otherwise it will be incomplete format specifier warning.

in your class use it like this

#define CC_USERNAME         @"secretName" #define CC_PASSWORD         @"secretPassword" #define CC_SALTED_STRING    [NSString stringWithFormat:@"####################%@#####################", CC_PASSWORD] 

then create NSData representation of your salted string ran through SHA256

NSData *hash = [NSData sha256forData:CC_SALTED_STRING]; 

next step is to generate 16 bytes of random generated iVector data

NSData *iVector = [NSData generateRandomIV:16]; 

and use these objects to encrypt your string. create a NSMutableData object with first 16 bytes of iVector data (make sure u use iVector object and do not generate new random or you will be unable to decrypt).

NSString *message = @"my secret message to the world"; NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];  NSMutableData *encryptedData = [[NSMutableData alloc] initWithData:iVector];  NSData *payLoad = [NSData encrypt:messageData key:hash iv:iVector];  [encryptedData appendData:payLoad]; 

to decrypt, separate first 16 bytes and the rest of data and use it with the hash.

NSData *pureData = [encryptedData subdataWithRange:NSMakeRange(16, [encryptedData length] - 16)]; NSData *extractedVector = [encryptedData subdataWithRange:NSMakeRange(0, 16)];  NSData *decryptedData = [NSData decrypt:pureData key:hash iv:extractedVector];  NSString *decryptedMessage = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding]; 

you can do some extra md5 on the hash or even pack encrypted data with zlib before storing it.

enjoy your custom made crypto.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment