How can I use this encryption method to save my data encrypted in core data? - cocoa

I have a method that encrypts a peace of string. Method seems to work just fine. My problem is that I don't know how to use it so I can store the data in core data encrypted.
Bellow of my implementation, I have the following lines of code:
#define CC_USERNAME #"myusername"
#define CC_PASSWORD #"mypassrod"
#define CC_SALTED_STRING [NSString stringWithFormat:#"someRandomStringHere%#anDhEreAsWEll", CC_PASSWORD]
Here is the method:
-(void)encryptWebsiteUrl {
NSData *hash = [NSData sha256forData:CC_SALTED_STRING];
NSData *iVector = [NSData generateRandomIV:16];
NSInteger row = [self.websitesTableView selectedRow];
NSTableColumn *column = [self.websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:row];
NSLog(#"cell value:%#", [cell stringValue]);
NSString *message = [cell stringValue]; // here, I should get the cell value
NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *encryptedData = [[NSMutableData alloc] initWithData:iVector];
NSData *payLoad = [NSData encrypt:messageData key:hash iv:iVector];
[encryptedData appendData:payLoad];
message = encryptedData;
NSLog(#"Encrypted message is: %#",message);
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];
//NSLog(#"Decrypted message is: %#",decryptedMessage);
}
Right now, I am calling this method like this:
-(void)controlTextDidEndEditing:(NSNotification *)obj {
[self encryptWebsiteUrl];
}
In the console log, I have the following output:
cell value:www.newone.com
Encrypted message is: <474ca213 c80b9135 ae5a31ad f5004006 556de1db 6835cad2 aa408084 442a8a1f>
In the encryption method, I use self.websitesTableView. That is the table view with one column only in which I store my data, and the column is named websiteUrl (see the code in the method)
My question is: how can I use this method to store encrypted value of the websiteUrl in core data which is now stored unencrypted.
I want to mention here 2 things. One, in core data, attribute websiteUrl is transformable, and second, I use binding, which is the reason why I didn't post any code related with saving or inserting data in the websitesTableView.

Yes you can store binary data in Core Data. The contents of that binary data is irrelevant to Core Data. Therefore, yes, you can store encrypted data in Core Data.
However, you might want to consider two other options:
Storing things like this in the keychain. That is what it is designed for.
Turning on file level encryption for Core Data so that the encryption is transparent to you and your application.
If you want to store encrypted data, configure the attribute of the entity to be binary data. Then you just get and set NSData to that property. You can even add convenience methods to the subclass so that everything outside of the subclassed NSManagedObject will only access the unencrypted data.
Update 1
You add the NSPersistentStoreFileProtectionKey key to the options when you add the NSPersistentStore to the NSPersistentStoreCoordinator.
let options:[String:AnyObject] = [NSPersistentStoreFileProtectionKey: NSFileProtectionComplete]
Then pass those options into the addPersistentStoreWithType....
There are several options for the encryption experience you are looking for.

Solution 1. Use a value transformer in the data model.
NSValueTranformer to encrypt data
Solution 2. Use a value transformer in the binding. This is the same value transformer as solution 1.
Solution 3. Do encryption and decryption in custom accessors.
Solution 4. Use an encrypted and decrypted property.

Related

Convert data to an UIImageView

I try to convert data from parse.com into my UIImageView.
for (PFObject *object in objects)
{
PFFile *file = [object objectForKey:#"imageData"];
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
[contentImageArray addObject: [UIImage imageWithData:data]];
}];
}
I load my data in a NSMutableArray, this still works, but then I want my data in an ImageView.
So my code:
cell.contentImage.image = [UIImage imageWithData:[contentImageArray objectAtIndex:(contentImageArray.count - indexPath.row - 1)]];
But it does not work, I just get an error message, please help!
First, you need to check the error and that the data isn't nil because this isn't safe:
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
[contentImageArray addObject: [UIImage imageWithData:data]];
}];
if parse has an issue returning the data your app will crash.
Also, in that code you are already creating the image from the data, so you don't need to do it again:
cell.contentImage.image = [contentImageArray objectAtIndex:(contentImageArray.count - indexPath.row - 1)];
Finally, you're making assumptions about what index each image has in the array and you have very specific indexing logic. That's unlikely to work well / properly in the future, even if it does now. You load images in the background and put them into an array - you have no idea what order the images are going to load in... You should apply logic to deal with that. If you load the table when you don't have any images they you'll be trying to get the (0 - 0 - 1)'th image from the array, and that isn't going to exist.
From your follow on comment:
Populate your contentImageArray with instances of NSNull for each of the objects you have. When you iterate the objects, keep the index and then when the image is ready you can:
[contentImageArray replaceObjectAtIndex:i withObject:[UIImage imageWithData:data]];
and when you try to use the image, check if it's available yet:
id image = [contentImageArray objectAtIndex:indexPath];
cell.contentImage.image = ([image isKindOfClass:[UIImage class]] ? image : nil);

Core Data Transformable attributes NOT working with NSPredicate

I often use Transformable for Core Data attributes, so I can change them later.
However, it seems like, if I want to use NSPredicate to find a NSManagedObject, using "uniqueKey == %#", or "uniqueKey MATCHES[cd] %#", it's not working as it should.
It always misses matching objects, until I change the attributes of the uniqueKey of the matching object to have specific class like NSString, or NSNumber.
Can someone explain the limitation of using NSPredicate with Transformable attributes?
Note: I'm not sure when/if this has changed since 5/2011 (from Scott Ahten's accepted answer), but you can absolutely search with NSPredicate on transformable attributes. Scott correctly explained why your assumptions were broken, but if Can someone explain the limitation of using NSPredicate with Transformable attributes? was your question, he implied that it is not possible, and that is incorrect.
Since the is the first google hit for "Core Data transformable value search nspredicate" (what I searched for trying to find inspiration), I wanted to add my working answer.
How to use NSPredicate with transformable properties
Short, heady answer: you need to be smart about your data transformers. You need to transfrom the value to NSData that contains what I'll call "primitive identifying information", i.e. the smallest, most identifying set of bytes that can be used to reconstruct your object. Long answer, ...
Foremost, consider:
Did you actual mean to use a transformable attribute? If any supported data type -- even binary data -- will suffice, use it.
Do you understand what transformable attributes actually are? How they pack and unpack data to and from the store? Review Non-Standard Persistent Attributes in Apple's documentation.
After reading the above, ask: does custom code that hides a supported type "backing attribute" work for you? Possibly use that technique.
Now, past those considerations, transformable attributes are rather slick. Frankly, writing an NSValueTransformer "FooToData" for Foo instances to NSData seemed cleaner than writing a lot of adhoc custom code. I haven't found a case where Core Data doesn't know it needs to transform the data using the registered NSValueTransformer.
To proceed simply address these concerns:
Did you tell Core Data what transformer to use? Open the Core Data model in table view, click the entity, click the attribute, load the Data Model Inspector pane. Under "Attribute Type: Transformable", set "Name" to your transformer.
Use a default transformer (again, see the previous Apple docs) or write your own transformer -- transformedValue: must return NSData.
NSKeyedUnarchiveFromDataTransformerName is the default transformer and may not suffice, or may draw in somewhat-transient instance data that can make two similar objects be different when they are equal.
The transformed value should contain only -- what I'll call -- "primitive identifying information". The store is going to be comparing bytes, so every byte counts.
You may also register your transformer globally. I have to do this since I actually reuse them elsewhere in the app -- e.g. NSString *name = #"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
You probably don't want to use transforms heavily queried data operations - e.g. a large import where the primary key information uses transformers - yikes!
And then in the end, I simply use this to test for equality for high-level object attributes on models with NSPredicates -- e.g. "%K == %#" -- and it works fine. I haven't tried some of the various matching terms, but I wouldn't be surprised if they worked sometimes, and others not.
Here's an example of an NSURL to NSData transformer. Why not just store the string? Yeah, that's fine -- that's a good example of custom code masking the stored attribute. This example illustrates that an extra byte is added to the stringified URL to record if it was a file URL or not -- allowing us to know what constructors to use when the object is unpacked.
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
#interface URLToDataTransformer : NSValueTransformer
#end
...
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = #"URLToDataTransformer";
#implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
#end
Transformable attributes are usually persisted as archived binary data. As such, you are attempting to compare an instance of NSData with an instance of NSString or NSNumber.
Since these classes interpret the same data in different ways, they are not considered a match.
you can try this way
NSExpression *exprPath = [NSExpression expressionForKeyPath:#"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];

Core Data - get/create NSManagedObject performance

I'm creating an iphone/ipad app that basically reads XML documents and creates tableviews from objects created based on the xml. The xml represents a 'level' in a filesystem. Its basically a browser.
Each time i parse the xml documents i update the filesystem which is mirrored in a core-data sqllite database. For each "File" encountered in the xml i attempt to get the NSManagedObject associated with it.
The problem is this function which i use to get/create either a new blank entity or get the existing one from database.
+(File*)getOrCreateFile:(NSString*)remotePath
context:(NSManagedObjectContext*)context
{
struct timeval start,end,res;
gettimeofday(&start,NULL);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"File" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
[fetchRequest setFetchLimit:1];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"remotePath == %#",remotePath];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *items = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
File *f;
if ([items count] == 0)
f = (File*)[NSEntityDescription insertNewObjectForEntityForName:#"File" inManagedObjectContext:context];
else
f = (File*)[items objectAtIndex:0];
gettimeofday(&end, NULL);
[JFS timeval_subtract:&res x:&end y:&start];
count++;
elapsed += res.tv_usec;
return f;
}
For eksample, if i'm parsing a document with 200ish files the total time on a iPhone 3G is about 4 seconds. 3 of those seconds are spent in this function getting the objets from core data.
RemotePath is a unique string of variable length and indexed in the sqllite database.
What am i doing wrong here? or.. what could i do better/different to improve performance.
Executing fetches is somewhat expensive in Core Data, though the Core Data engineers have done some amazing work to keep this hit minimal. Thus, you may be able to improve things slightly by running a fetch to return multiple items at once. For example, batch the remotePaths and fetch with a predicate such as
[NSPredicate predicateWithFormat:#"remotePath IN %#", paths];
where paths is a collection of possible paths.
From the results, you can do the searches in-memory to determine if a particular path is present.
Fundamentally, however, doing fetches against strings (even if indexed) is an expensive operation. There may not be much you can do. Consider fetching against non-string attributes, perhaps by hasing the path and saving the hash in the entity as well. You'll get back a (potentially) larger result set which you could then search in memory for string equality.
Finally, do not make any changes without some performance data. Profile, profile, profile.

How do I get Core Data to use my own NSManagedObjectID URI scheme?

I am writing an app that connects to a database to fetch data. Since the fetching is expensive and the data is generally unchanging, I'm using CoreData to cache the results so that I can do fast, local queries.
From the database, for each type, there is a string property that is guaranteed to be unique. In fact, there is a URI scheme for the database which is a unique address for each item.
The URL scheme is very basic along the lines of:
ngaobject://<server_license_id>/<type>/<identifier>
I'd like to be able to use this in CoreData as well. I've made a method to fetch a single item from the CoreData store:
-(NSFetchRequest*)fetchRequestForType:(NSString*)typeName identifier:(NSString*)identifier
{
NSFetchRequest * fetchRequest = [self fetchRequestForType:typeName];
[fetchRequest setFetchLimit:1];
NSString * identifierProperty = [self identifierPropertyNameForObjectType:typeName];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"%K == %#", identifierProperty, identifier];
[fetchRequest setPredicate:predicate];
return fetchRequest;
}
-(NGAObject*)objectWithType:(NSString*)typeName
identifier:(NSString*)identifier
{
// First try to retrieve it from the cache
NSAssert1( (identifier != nil), #"Request to create nil-name object of type %#", typeName );
NSFetchRequest * fetchRequest = [self fetchRequestForType:typeName identifier:identifier];
if ( !fetchRequest )
return nil;
NSError * error = nil;
NSArray * fetchResults = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
if ( !fetchResults )
{
NSLog(#"%#", error);
[NSApp presentError:error];
return nil;
}
if ( [fetchResults count] )
return [fetchResults objectAtIndex:0];
return nil;
}
When I retrieve an item from the server, I want to first get a reference to it in the cache and if it's there, update it. If it's not, create a new one.
Since I'm getting back thousands of objects from the server, performing a fetch for a single object for which I know a unique ID brings my machine to a crawl.
Instead, what I'm doing is pre-loading all the objects of a type, then creating a dictionary of identifiers->object, then processing the thousands of objects for that type by running it through the dictionary. This works fine, but is awkward.
Could I not write a method that takes the type/identifier combo and get a single object from CoreData without having to execute a lengthy fetch request?
It seems there is a solution if I can get CoreData to use my own URI specification. I could then call -(NSManagedObjectID*)managedObjectIDForURIRepresentation:(NSURL*)url on the persistent store coordinator.
So, the question is, how can I get CoreData to use my URI scheme? How can I make CoreData use my own unique identifiers?
You can't make Core Data use a custom URI scheme. The URI scheme is hardcoded into Core Data such that the URI can be decoded to locate particular data in a particular store in a particular apps on a particular piece of hardware. If the URI was customizable, that system would break down.
Fetching object singularly is what is killing you. Instead you need to batch fetch all objects whose customID matches those provided by the server. The easiest way to that is to use the IN predicate operator:
NSArray *customIDs=//... array of customIDs provided by server
NSPredicate *p;
p=[NSPredicate predicateWithFormat: #"customIdAtrribute IN %#", customIDs];
This will return all existing objects that you can ignore.
Alternatively, you could
Do a fetch on just the customID property by setting the fetch's propertiesToFetch to the customID attribute.
Set the fetch result type to dictionary.
Use the above predicate.
You will get an array of one key dictionaries returned with the customID as each value.
Convert the dictionary to an array of values e.g cachedIDs
Convert customIDs above to a mutable array.
Filter the customIDs array using the predicate, #"NOT (SELF IN %#)", cachedIDs"
The filtered customIDs array will now only contain the customID values NOT cached in Core Data.
You can create managed objects for only the new ids.
(This is how you use a filter predicate if you are unfamilar with it.)
NSMutableArray *f=[NSMutableArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",nil];
NSArray *g=[NSArray arrayWithObjects:#"5",#"6",nil];
[f filterUsingPredicate:[NSPredicate predicateWithFormat:#"NOT (SELF IN %#)",g]];
NSLog(#"f=%#",f);
...which outputs:
f=(
1,
2,
3,
4
)
Are all the fields which you are using for unique-ID lookup marked as "Indexed" in the CoreData designer? If that has been done then the CoreData fetches shouldn't be lengthy ...

Store selector as value in an NSDictionary

Is there a way to store a selector in an NSDictionary, without storing it as an NSString?
SEL is just a pointer, which you could store in an NSValue:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSValue valueWithPointer:#selector(foo)], #"foo",
nil];
To get the selector back, you can use:
SEL aSel = [[dict objectForKey:#"foo"] pointerValue];
An alternative to Georg's solution would be to convert the selector into an NSString before storing it the NSDictionary:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
NSStringFromSelector(#selector(foo)), #"foo",
nil];
SEL selector = NSSelectorFromString([dict objectForKey:#"foo"]);
This technique, though uses more memory, gives you the ability to serialize the entire NSDictionary as a string via libraries like JSONKit.
An NSDictionary is really just a CFDictionary that retains and releases all keys and values. If you create a CFDictionary directly, you can set it up to not retain and release values. You can typecast a CFDictionaryRef to an NSDictionary * and vice versa.
In case of using UILocalNotification the only way is to use NSSelectorFromString([dict objectForKey:#"foo"]). With valueWithPointer the app crashing when setting userInfo property of UILocalNotification object. Be careful.
While Georg's answer should work, NSValue does also support encoding any value using an Objective-C type encoding string, which has a special way of representing SEL— with a ":" (as opposed to the "^v" produced by -valueWithPointer:, which translates into void *).
source: Objective-C Runtime Programming Guide - Type Encodings
Working off of Georg's solution, the best API-compliant way to put a SEL into an NSValue into an NSDictionary would be:
// store
NSDictionary *dict = #{
#"foo": [NSValue value:&#selector(foo) withObjCType:#encode(SEL)]
};
// retrieve
SEL aSel;
[dict[#"foo"] getValue:&aSel];
The rationale for handling a SEL as its own beast is that the docs describe it as “an opaque type”— which means that its internal workings (even what it's typedefd to) are off-limits to app programmers; Apple may mix it up at any time in the future.
Also, using void *s to force the system to do what you want it to do was useful in C back in the '90s, when most of us didn't know any better.  You're better than that now.
The above approach should only be used if the retrieval of the SEL happens during the program's running duration— you shouldn't be storing that NSDictionary to disk.  If you do need to store SELs long-term (across app launches), you should follow David H's approach and convert it to an NSString.

Resources