Objective-C, how to obfuscate or encrypt NSString? - objective-c

I have an NSString (which is a path to a file) in my code that I would like to somehow obfuscate or encrypt,
but still be able to call up the file path easily when needed.
I searched for an answer to this, but everything I've seen either deals specifically with iOS or seems overly complicated.
I would simply like to use it with something such as this:
- (void)method {
NSString *obfuscate = #"/path/to/something/secret"; // encrypt or obfuscate
[self manageFiles:obfuscate]
- (void)manageFiles(NSString *)obfuscate {
NSFileManager *files = [[NSFileManager alloc] init];
if ([files fileExistsAtPath:obfuscate])
... .
— any help is appreciated, thank you.

(This is an old question, but I'm replying anyway)
There's no such way to in Obj-C. Obj-C is dynamic enough that any of these methods can be trapped and intercepted. Do not ship anything in a application that absolutely needs to be secret. If your application is run on a jailbroken phone, or if it is made available on piracy sites, than it has already been exposed and it's memory contents dumped. All these above methods copy the decoded data to main memory where it is exposed.
See:
https://www.youtube.com/watch?v=Ii-02vhsdVk
None of these methods above is actually secure. Again, do not embed these sorts of things in your applications with an assurance they are actually secure.

What I have done in the past to obfuscate a string was something to this extent:
-(NSString*)myString {
NSString *string = nil;
string = [#"ozzzzzzzzzzzzhazzzzzzzizzzzzz" stringByReplacingOccurrencesOfString:#"z" withString:#""];
return string;
}
What it would do is remove all the occurences of the letter z, leaving you with ohai as a string. Not sure if this will suffice for your case, but it has worked for me.
Hope this helps!

Related

"error:NULL" or "error:nil"?

Just trying to figure out what's the best practice: when using method that takes (NSError**), is it better to send it nil or NULL?
For example,
NSArray *items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
In the documentation it says "You may specify nil for this parameter if you do not want the error information." On the other hand, since its a double pointer, NULL seems to make sense as well?
Technically, NULL is the right answer and the docs are wrong.
In practice, it matters not. NULL and nil are the same, for all intents and purposes.
While that could change and remain language compliant, it couldn't change without breaking tons and tons of stuff.
Feel free to file a bug, though.

How to find file types in objective c

I have done a lot of research on this and haven't found anything useful. I want am making a simple program in objective c for personal use that opens files and gives information about them. The only problem i have encountered is that i cannot find the file of a file i am opening. Without simply looking at the extension, is there a way to find the full file format of a file in objective c?
If possible, i would also like to be able to save that file in a different format. Information on this subject is also important for this application. Help will be greatly appreciated.
Mac OS X has type information attached to each file which specifies what the type of the file is supposed to be. This information is given by the application which last saved the file, so it is not necessarily correct. Also, new versions of OS X ignore this information and go entirely off of the file extension. However, the information is still stored and can be retrieved using NSFileManager's attributesOfItemAtPath:error: method.
As mentioned by quixoto above, OS X now maps extensions to UTIs. The UTI of a file can be retrieved using NSWorkspace, which can also tell you what the UTI means. This code will get the localized description of the file at /full/path/to/file:
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSString *description = [ws localizedDescriptionForType:[ws typeOfFile:#"/full/path/to/file" error:nil]];
The typeOfFile:error: method requires an absolute path.
Consider: what do you mean by "full file format"? What kinds of files and level of detail do you care about?
You can't really get "format" information from the file system like you want. Believe it or not, the file system has no idea what format files are in.
File systems traditionally store files as a stream of bytes with a name, a size, and some other attributes ("hidden", permissions, etc). That's all that it's responsible for, and it's the application's problem to read those bytes and interpret them to mean something useful.
The extension is the traditional hint to an application about what a file contains, but as you might guess, it's certainly not a verified guarantee.
Modern Mac OS X has Quick Look, which uses a system-wide framework that adds some smarts on top of this, with mappings between extensions and UTIs, which are a richer notion of file type. Docs are here. I don't think there's a way to query this system for the mappings between extensions and UTIs, but I'm not sure.
Loading a file of one format and saving in another is 100% dependent on the file types you're talking about, and you're going to have ask very specific questions about specific formats if you really care to accomplish this. (And that topic extends well beyond a couple built-in method calls in Cocoa.)
This information is now (since OS X 10.5) handled through UTIs.
You can get it like this:
NSURL *desktopURL = [[[NSFileManager defaultManager] URLsForDirectory: NSDesktopDirectory
inDomains: NSUserDomainMask] lastObject];
NSURL *workingdirURL = [desktopURL URLByAppendingPathComponent:#"WorkingDir" isDirectory:YES];
NSArray *docURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:workingdirURL
includingPropertiesForKeys:#[NSURLTypeIdentifierKey] options:NSDirectoryEnumerationSkipsHiddenFiles
error: nil];
NSMutableArray *pdfURLs = [NSMutableArray array];
for (NSURL *docURL in docURLs) {
id resourceValue;
BOOL found = [docURL getResourceValue: &resourceValue
forKey: NSURLTypeIdentifierKey
error: nil];
if ( found && [resourceValue isEqual:#"com.adobe.pdf"]) {
[pdfURLs addObject: docURL];
}
}
You can see the docs for more information about the file properties that can be retrieved this way. There is quite a lot of information available through this method.

Discover the environment and relative path of the running application

While playing with RubyCocoa, I keep progressing with my idea for my application. Because my application will be going to use configuration files, I would like to know how I discover the relative path to store these inside my application structure (or if a better idea emerges, please elaborate also the "why").
Also good for me to know is to discover environment variables, such as operating system version, the amount of memory that is available and such. Hyperlinks would be awesome too.
Please notice I use RubyCocoa and thank you for your feedback, comments and answers!
To access inside the application bundle, you use NSBundle. See NSBundle reference. In Obj-C, you use +[NSBundle mainBundle] to get the main bundle of the app. Then you use -[NSBundle pathForResource:ofType:] to get the file. I don't know RubyCocoa syntax, but I assume you know how to translate to it :)
If by the configuration file you mean a user-configurable things, remember you can't write inside the app bundle at runtime. Instead one uses NSUserDefaults. See User Defaults Guide.
Here's some Cocoa code I use to write all the environment variables to the console. Again, I don't use RubyCocoa, so you'll have to translate:
NSProcessInfo *myProcessInfo = [NSProcessInfo processInfo];
NSDictionary *env = [myProcessInfo environment];
for (id key in env)
{
NSLog (#"key: %#, value: %#", key, [env objectForKey: key]);
}

What is the purpose of having both NSMutableString and NSString?

Why does Objective C provide both class NSString and subclass NSMutableString rather than just provide NSMutableString? Isn't a NSString equivalent to "const NSMutableString"?
In C++, you have only one string class, std::string, and if you want a constant you declare a const std:string.
I'm interested in knowing why I shouldn't just use NSMutableString everywhere and never bother with NSString? There must be a reason, or the language designers wouldn't provide both. maybe it takes up less storage or something?
It is very possible, and even likely, that there are optimizations in place that are only allowed when strings are immutable.
In fact running
NSString *A = #"Bob";
NSString *B = #"Bob";
in the debugger immediately shows that they are both pointers to the same string. In fact
NSString *C = [NSString stringWithString:#"Bob"];
NSString *D = [A copy];
both point to the same memory address as well. Meanwhile
NSString *E = [NSMutableString stringWithString:#"Bob"];
points to a different string.
So yes, using NSStrings are more efficient in some cases. And in general cocoa lends itself to returning a new copy of a string rather than an edited one. However, I can't really argue that you shouldn't use a mutable string everywhere, but it does seem to go against the general guidelines for the framework.
In my own work I tend to only use mutable variants where I need to edit things directly. It's just a little backwards from the C/C++ style of everything mutable unless you need a const, everything is const unless you need mutability.
The reason for both classes is the same reason that you sometimes use a std::string and sometimes use a const std::string. However, unlike C++, Objective-C doesn't have const methods, so they instead separate const- from non-const- methods into two different classes. This is also seen in many of the core classes, such as NSArray (NSMutableArray), NSDictionary (NSMutableDictionary), etc.
I would say the general rule is "don't use a class whose purpose is to provide functionality you don't need". If you need to change the contents of a string directly, use NSMutableString. If not, use NSString. In terms of size and how much heap space they take up, the classes themselves should be pretty similar.
I think the usage of an immutable string is a hint for the compiler which can perform optimizations by knowning it won't change.

Is there a reason why I shouldn't just define #define NSFM [NSFileManager defaultManager] instead of writing it out each time?

There is a built-in shortcut NSApp, is there any reason that I shouldn't add one for NSFileManager?
#define NSFM [NSFileManager defaultManager]
I think omitted this will make my code cleaner and I can't see any benefit to keeping it in. (I plan on doing this in all my projects from now on, so it won't be obscure.)
NSFileManager *fm = [NSFileManager defaultManager]
Why don't you just use a local variable?
NSFileManager *fm = [NSFileManager defaultManager];
// use fm...
or better yet, inject the file manager as a method argument:
- (void)myMethod {
//using [NSFileManager defaultManager]
}
becomes
- (void)myMethodWithFileManager:(NSFileManager*)fm {
//usin fm
}
Since the defaultManager is a singleton (effectively a global), it makes testing really hard. Injecting the dependency saves you typing (as you want) within the method and makes it much easier to unit test—you can inject a test double instead of the defaultManager.
Finally, Cocoa and Objective-C generally come down on favoring explicit code over short code. The philosophy is basically that using more verbose names makes the code easier to read (and thus to maintain). This philosophy goes all the way to Objective-C's selector style with interleaved named arguments. Unless you really can't handle the extra typing (and Xcode's code completion won't work for you), stick with the existing names. When in Rome and all that...
If it makes your code cleaner, I'm all for it. Just keep in mind that any other developers who have to read your code will not immediately know what NSFM or fm represent.
I would suggest a slightly more descriptive name: NSFileMgr. To most Cocoa developers, this would make the purpose of the variable a lot clearer without having to look it up.
UPDATE: See Barry Wark's answer for some very good points in regards to testing.
I would use a local variable every time because using the defaultManager is not thread safe. If at any point you start using threads in your application you may end up with hard to find bugs and not know why until you run upon this bit of documentation.