views:

182

answers:

5

I'm trying to create a Trial part of my cocoa application. I have the licensing all set up (including keys) etc.

But I was wondering how I could store e.g the first the time the user ran the program in a secure place, where the user can't easily find it and/or edit it.

I was having a fiddle with NSUserDefaults standardUserDefaults, but the user can easily find and edit that data in Library > Preferences.

+2  A: 

Try storing a file that's name begins with a period in some folder and then setting the file's hidden flag.

a good place to put the hidden file would be an obscurely named file in the base of the users folder (~/), there are many obscure hidden files there so it is hard to know which one's you can and can't delete. example path: ~/.xdarwinprofile or something equally official sounding.

here is some code that should work to hide the file:

#include <assert.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <sys/attr.h>
#include <sys/errno.h>
#include <unistd.h>
#include <sys/vnode.h>

typedef struct attrlist attrlist_t;

struct FInfoAttrBuf {
    u_int32_t length;
    fsobj_type_t objType;

    union {
        char rawBytes[32];

        struct {
            FileInfo info;
            ExtendedFileInfo extInfo;
        } file;

        struct {
            FolderInfo info;
            ExtendedFolderInfo extInfo;
        } folder;
    } finderInfo;
};
typedef struct FInfoAttrBuf FInfoAttrBuf;


- (int)SetFileInvisibility:(NSString *)filePath state:(BOOL)isInvisible) {
    attrlist_t attrList;
    FInfoAttrBuf attrBuf;

    char *path = [filePath cStringUsingEncoding: NSUTF8StringEncoding];

    memset(&attrList, 0, sizeof(attrList));
    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
    attrList.commonattr  = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO;

    int err = getattrlist(path, &attrList, &attrBuf, sizeof(attrBuf), 0);
    if (err != 0)
        return errno;

    // attrBuf.objType = (VREG | VDIR), inconsequential for invisibility

    UInt16 flags = CFSwapInt16BigToHost(attrBuf.finderInfo.file.info.finderFlags);

    if (isInvisible)
        flags |= kIsInvisible;
    else
        flags &= (~kIsInvisible);

    attrBuf.finderInfo.file.info.finderFlags = CFSwapInt16HostToBig(flags);

    attrList.commonattr = ATTR_CMN_FNDRINFO;
    err = setattrlist(path, &attrList, attrBuf.finderInfo.rawBytes, sizeof(attrBuf.finderInfo.rawBytes), 0);

    return err;
}

I modified this code from the answer to this question, you may find more helpful information there: http://stackoverflow.com/questions/2958991/how-to-make-a-file-invisible-in-finder-using-objective-c

I have not tested this code but it should work. In fact, it is possible the code is unnecessary and just saving the file with a dot in front of the filename will work.

If you have administrator privileges you can execute a sudo chmod on the file and set it to read only if you want, but you shouldn't make your app ask the user for their password.

thume
+12  A: 

I'd argue against making it super-secure. We once had a server activation but completely went away from it. Here are some of the reasons:

  • Even the most "secure" storage method can be broken
  • Even for a niche product a crack might be developed, no way around, no matter how secure your method
  • There are few, very expensive, very secure methods. All others have been cracked
  • It goes against fair and honest users, making it harder for them to fix things causing problems
  • If a user does crack your software or circumvents your security, he'll probably also never have bought it
  • 80% of the users don't even know what a preference file is
  • 95% of all users don't think of the possibility to delete it in order to extend the trial
  • A simple way to reset trial periods massively eases your support for users you want to give a second trial for whatever reason
  • Trusting users is a good selling point
  • Power users tend to turn against software with too much protection

I'm pretty sure that there are some, but extremely few, exceptions from these thoughts. I'd say: don't waste your time on registration security but give

Max Seelemann
I agree, don't waste too many resources making your app super secure. Hackers will find a way to bypass it.
Brad Goss
http://www.aquaticmac.com/ is a good drop in solution to security. http://aquaticmac.com/cocoa.php also has nice extension on NSData to do encryption. If you want to cover %99 of users, I would recommend the hidden file approach with an obvious name ie ".<myApplicationNameData>"
Ben
+3  A: 

If you must, a simple and common way is to use a key that is embedded in the application which encrypts a file on the disk that contains the sensitive data. The challenge is how to make the key secure.

Look into the Common Crypto digest library.

This will protect from almost all casual users. Though hackers can, with enough motiviation, figure out a way to circumvent.

jojaba
+3  A: 

You can't use a file on the filesystem. Anyone who would be looking to fiddle/crack it will be smart enough to know how to track file access through basic, standard OSX features. So a file being added is out. Not only that but it is bad behavior to create files you don't remove when the app is uninstalled. People shouldn't have to have resources consumed after deleting your trial app.

As noted above, messing about in your bundle is a bad idea as well. This leaves you with three fundamental options.

1) Don't worry about it too much. Use a basic expiration system that uses the standard locations and methods. You can still use encryption in the data you store, but know that that too will be broken. Accept that copyright violation will occur unless your app is wholly unpopular.

2) Use a network call and do the validation on the server. This would require the app always be able to reach your service to be run. This is not a good idea in general. What if your servers are down? What if they are off-line? What if a network issue between you and them happens? All of those scenarios are going to happen. When they do you will likely lose customers unless your app requires a connection to your servers already to operate (like say Twitter or Facebook does).

3) Be a "bad citizen" by mucking around with the application bundle or leaving orphan files around. If you do this latter, at least make sure they are clearly named so that they relate to your application obviously.

Ultimately the key thing to remember is that you have no security on a user's machine. It is theirs. That means they have physical access which pretty much nullifies any attempt to prevent them from digging. You can also look at it this way: the more technically minded your market is, the less likely you are going to be smarter than all of us and your "security" will be cracked. If you are designing for a non-technical audience then you can figure that generally speaking they won't be bothering with cracking it, or looking for one.

You can spend your resources on making the app better, or giving yourself a better feeling about people not using it past the trial period. One of those can increase your sales, and one will not.

[edit] Also I should point out that one of the most common (if not the most common) means of cracking these things is to modify the binary. So by breaking code signing via bundle mucking you would actually open yourself to that method because you would have broken one of the better protections you have. Most cracks involve binaries being modified such that the routine that does the checks always returns a successful authentication.

The Real Bill
+2  A: 

Allan Odgaard has a pretty decent writeup on how to use OpenSSL to generate/store license keys for Cocoa software. Might be worth a read.

mipadi