Can developers use the RSA code included in Magic Cap?
The RSA code used in Magic Cap is licensed only for Magic Cap's use, and developers can not use it. (That's why the API is not exposed to developers.) If your package needs to do public-key encryption, you'll need to license the code from RSA Data Security, Inc. and include it in your package. Click here for more information about RSADSI.
I don't want users to send my package around. Is there a way I can "bind" my package to a particular device?
There are a couple of approaches. A package can "bind" itself to a device (via UnitID()) or to a user (via AssignedName(iCurrentUser)). Binding to a person is at least as good as binding to a device, and it's better for a couple of reasons. If a device is lost or stolen or broken, then restoring a backup to a different device will leave the authority intact and allow your software to keep working. Also, the desktop versions of Magic Cap on Mac and Windows may not have immutable unique unit IDs. Most desktop machines typically don't have that sort of thing.
Cold boots can be a problem, though, if the user does not have a backup they can restore from. They will end up re-personalizing, which will break their connection with the package. In this case it's okay to require them to reinstall your package from floppy via the link. You could even create a small package that you could mail to them that would re-bind the disconnected package to the new authority. (This "back door" package could kill itself after doing its job, reducing the chance that someone will mail it to other people).
The binding process isn't affected by deleting changes, because it changes some data in the source cluster of the package directly by writing to memory. The "delete changes" command throws away the changes clusters but leaves the source cluster alone.
Here are some snippets that show one way for a package to bind itself to a person. As with all security measures, whether real or virtual, this will stop casual criminals but will fail to deter career felons.
These snippets modify parts of the Puzzle sample slightly to add copy protection. The first time the package is unpacked it binds itself to the personalized authority of iCurrentUser. If the package has been bound before, it compares itself against iCurrentUser. If there is a difference then it puts up an announcement and fails to unpack. There are other ways for the InstallInto to fail and perhaps they should put up announcements also. If you want to use the ID of the device instead of the personalized identity of the current user, you could easily substitue UnitID(someNewOctetString) for Authority(AssignedName(iCurrentUser)) and change the data copying code to copy 6 bytes instead of 17 bytes.
It's very important that the object that checks the binding (PuzzleBox 48 in the following snippets) is the first entry in your installer and receiver lists. This ensures that none of your other objects will be installed if your binding check fails.
This way of doing things has a slight downside or two (doesn't everything?). Inserting a RAM card containg the package into the "wrong" device will cause the copy protection window to appear somewhere along the way. It can be pretty annoying.
. . autoActivate: false; . entry28: (Announcement 12); . . Instance OctetString 11; data: $ 0000 0000 0000 0000 0000 0000 0000 0000 0000; End Instance; Instance Announcement 12; //ipIWantMyMommy! flags: 0x0000008B; // isError, noStamp, urgent, displayOnce info: (Text 13); stamp: nilObject; sound: nilObject; publicAddress: iSystemWarnings; End Instance; Instance Text 13; info: 'You're not my mommy! I want my mommy!'; End Instance; Instance ObjectList 'Install' 43; length: 2; entry: (PuzzleBox 'PuzzleBox' 48); entry: (Icon 'PuzzleIcon' 55); // put our nice icon in the desk drawer End Instance; Instance ObjectList 'Receiver' 44; length: 2; entry: (PuzzleBox 'PuzzleBox' 48); entry: iGameRoomShelf; // ...into the gameroom we go! End Instance; ...added to Instance ObjectList 'Text' 26... entry5 : (OctetString 11);
overrides InstallInto; // to do copy protection
#define ipProtection MakePackageIndexical(26,5) #define ipCopyWarning MakePackageFlatIndexical(28) Method void PuzzleBox_InstallInto(ObjectID self, ObjectID other, ulong flags, ObjectID parameter, ObjectID packageInstallList) { #pragma unused (other,flags,parameter,packageInstallList) ObjectID currentUser, savedUser; char *dataPtr; Boolean idMatches = true; ObjectID device; // don't bother looking if running off of ROM card device = ObjectContainer(PackagePersistentSource(Context(self))); if (!Writeable(device)) { // Must not be run from read only media (since we intend to write to memory) Fail( packageMustNotInstall ); } // should announce something here if (WriteProtected(device)) { // Must not be run from write-protected media (since we intend to write to // memory) Fail( packageMustNotInstall ); } // get the current and saved values of the user's id savedUser = DirectID(ipProtection); currentUser = AssignedName(iCurrentUser); if (currentUser == nilObject) { // Must be run from personalized device Fail(packageMustNotInstall); } currentUser = Authority(currentUser); dataPtr = BeginReadExtra(savedUser); if (dataPtr[0] == 0) { *dataPtr = 'P'; CopyBytes(BeginReadExtra(currentUser), dataPtr + 1, 17); } else idMatches = EqualMem(dataPtr + 1, BeginReadExtra(currentUser), 17); EndReadExtra(savedUser); EndReadExtra(currentUser); if (!idMatches) { Announce(ipCopyWarning); // You're not my mommy! I want my mommy! Fail(packageMustNotInstall); } }