Protecting resources in iPhone and iPad apps

by Robin Summerhill on July 20, 2010

UPDATE: The example project has been updated to work with iOS5.

If you are distributing an iPhone or iPad app you may be giving away more than you realize. Resources that you embed in your application bundle can be extracted very easily by anyone who has downloaded the app with iTunes or has the app on their iOS device. This is not such a problem if those resources are just parts of your UI or the odd NIB file, but once you realise that your high-value resources, such as embedded PDFs, audio files, proprietary datasets and high-resolution images are just as accessible then you might want to consider how to protect those resources from prying eyes or unauthorised use outside your application.

To see just how accessible your resources are, use a tool such as iPhone Explorer to connect to your device. This tool lets you browse all the app bundles on your device and copy any resource to your Mac or PC. Alternatively, just locate the ipa file that is downloaded when you purchase an app with iTunes, change the extension to ‘.zip’ then unzip it. All your resources are on display.

Protection through encryption

In this article I’m going to walk through one approach to protecting your resources from unauthorised use outside your application. During the build phase, your high-value resources will be encrypted before being embedded in the app bundle. These resources can then be decrypted on-the-fly when required in your app. I had a number of goals in mind when developing the solution presented in this article:

  • Adding new resources to be encrypted should be quick and easy.
  • The encryption process should be completely automatic during the build phase.
  • Encrypted PDFs or HTML files must be useable in an embedded UIWebView
  • Decryption must be in-memory and not create temporary unprotected files

I also did not want to complicate the submission process by introducing encryption that might be subject to export restrictions, so we are limiting ourselves to using the CommonCrypto API, which is already distributed as part of iOS. The usual caveats apply when using any sort of encryption approach – given enough time and determination someone will bypass any protection scheme you can come up with. However, make it difficult enough to crack the protection compared to the value of the protected resources and it becomes a question of economics. If you are working with client-supplied resources then it becomes even more important to use a scheme such as the one described here to protect yourself from charges of negligence should those resources turn up on some torrent site.

An encryption command-line tool

So, down to the details. We’re going to create a simple command-line tool that will be run as part of the build process to encrypt resources using the AES256 symmetric cipher. An Xcode project to build the tool can be found at the bottom of this article. The tool takes command-line arguments specifying a 256-bit key, the input file path and an output file path. We will use a custom build step to call the command-line tool for each of our resources that we want to be encrypted.

Setting up our project

XCode project showing EncryptedResources folder and custom build step

Now we have a tool to perform the encryption, we can turn to an example project that makes use of the encryption to protect embedded resources. You can find an example Xcode project at the end of this article. This sample simply displays a UIWebView when run and populates it with protected HTML and image files, which are embedded as encrypted resources in the app.

The first step is to create a sub-folder under the project folder to contain the original resources that we want to protect. In the example we have called this sub-folder ‘EncryptedResources’. One of our goals was to make adding new resources as quick and easy as possible and when we have finished setting up the project we will be able to add a new protected resource simply by dragging it into this folder within Finder. As a cosmetic convenience I also added the folder to the Xcode project as a folder reference (by checking the ‘Create Folder References for any added folders’ checkbox) but please remember to deselect any target membership on the ‘Targets’ tab of the Info dialog for this folder or the unencrypted resources will be added to the app bundle by the regular ‘Copy Bundle Resources’ build step.

Adding a custom build step

To process the files in the EncryptedResources folder, we add a custom build step by selecting the ‘Project > New Build Phase > New Run Script Build Phase’ menu item in Xcode. In the example we have moved this build step to the start of the project target (under the Targets > EncryptedResourceDemo item in the ‘Groups and Files’ list) so that it is run as the first step in the build process. The shell script associated with this step can be viewed by selecting the ‘File/Get Info’ menu item when the step is selected:

if [ ! -d "$OUTDIR" ]; then
  mkdir -p "$OUTDIR"
for file in "$INDIR"/*
  echo "Encrypting $file"
  "$PROJECT_DIR/crypt" -e -k $ENC_KEY -i "$file" -o "$OUTDIR/`basename "$file"`"

The shell script iterates over every file in the ‘EncryptedResources’ folder and calls our ‘crypt’ tool for each file, placing the encrypted output in the application bundle. Note that the script expects the ‘crypt’ tool to be present in the base of the project directory. As an alternative, you could place the ‘crypt’ tool somewhere on your path and modify the script accordingly. Note also, that it is in the build script where we specify the key to use for encryption. The 256-bit key is specified as 32 x 8-bit characters – you should change it from the default given here.

Using protected resources in applications

So now we have a built app bundle containing our protected resources. The resources can still be viewed with tools such as iPhone Explorer or extracted from an iTunes ipa file but are useless without the correct decryption key. We now turn to how these resources can be used legitimately by your app. In creating a decryption framework, I wanted a scheme that would be as flexible as possible and not place an unnecessary burden on the developer every time she wanted to use a protected resource. I also needed a scheme that decrypted in memory and did not create temporary files (which could be viewed with iTunes Explorer while an app was running). I chose to create a custom URL protocol and extend the URL loading system. This allows us to use encrypted resources anywhere that a URL can be specified and, thanks to the widespread use of URLs in the iOS frameworks, we get a lot of bang for our buck with relatively little new code including:

  • Loading encrypted resources into memory with [NSData dataWithContentsOfURL:]
  • Viewing encrypted HTML files and images in UIWebView

Custom URL protocols

If you haven’t come across implementing custom URL protocols before and you are interested in finding out more then check out the iPhone Reference Library. By subclassing NSURLProtocol and implementing a few required methods we can grant the URL loading system the ability to load other types of resources beyond the standard built-in schemes (http:, https:, ftp: and file:).

Our NSURLProtocol subclass is called EncryptedFileURLProtocol and the implementation can be found under the EncryptedFileURLProtocol group in the example project. It implements a new URL scheme (encrypted-file:) that works like the standard file: scheme. A URL using this scheme specifies a file on the local system just like file:, however, the files will be decrypted on-the-fly when the resource is loaded.

A custom NSURLProtocol subclass must override the canInitWithRequest:. The URL loading system uses this method to determine which protocol can handle a particular request. The loading system asks each registered protocol in turn whether it can handle the specified request. The first protocol to return YES gets to handle the request. The implementation of our canInitWithRequest: method is shown below and will return YES if the requested URL scheme is ‘encrypted-file:’.

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
    return ([[[request URL] scheme] isEqualToString:ENCRYPTED_FILE_SCHEME_NAME]);

A custom NSURLProtocol must also override two additional methods, startLoading and stopLoading. These are called by the URL loading system at appropriate points when handling a request. Our startLoading method initializes the cryptographic engine and opens an NSInputStream to load the resource. The decryption key is also specified at this point. It is shared between all instances of our custom NSURLProtocol and needs to match the key used for encryption during the build process. The default key value is specified on line 20 of EncryptedFileURLProtocol.m and can be modfied using the class-level key property.

- (void)startLoading
    inBuffer = malloc(BUFFER_LENGTH);
    outBuffer = malloc(BUFFER_LENGTH);
    CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, [sharedKey cStringUsingEncoding:NSISOLatin1StringEncoding], kCCKeySizeAES256, NULL, &cryptoRef);
    inStream = [[NSInputStream alloc] initWithFileAtPath:[[self.request URL] path]];
    [inStream setDelegate:self];
    [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inStream open];

The stopLoading method is called when the request ends, either due to normal completion or an error condition. In our implementation we clean up the input stream, cryptographic engine and buffers:

- (void)stopLoading
    [inStream close];
    [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inStream release];
    inStream = nil;

Because we have scheduled our input stream on the current run loop and specified our custom instance of NSURLProtocol as the stream delegate, we will be called periodically with chunks of data to process. Below is an extract from the stream event handler where a chunk of data read from the input stream is decrypted and passed on to the URL loading system:

  switch(streamEvent) {
        case NSStreamEventHasBytesAvailable:
            size_t len = 0;
            len = [(NSInputStream *)inStream read:inBuffer maxLength:BUFFER_LENGTH];
            if (len)
                // Decrypt read bytes
                if (kCCSuccess != CCCryptorUpdate(cryptoRef, inBuffer, len, outBuffer, BUFFER_LENGTH, &len))
                    [self.client URLProtocol:self didFailWithError:[NSError errorWithDomain:ERROR_DOMAIN code:DECRYPTION_ERROR_CODE userInfo:nil]];
                // Pass decrypted bytes on to URL loading system
                NSData *data = [NSData dataWithBytesNoCopy:outBuffer length:len freeWhenDone:NO];
                [self.client URLProtocol:self didLoadData:data];

Implementing these four methods is nearly all we need to do to leverage the power of the URL loading system. The final piece of the puzzle is to register our custom NSURLProtocol subclass with the system. This is done in the application:didFinishLaunchingWithOptions: method of our application delegate (in EncryptedResourceDemoAppDelegate.m):

    // Register the custom URL protocol with the URL loading system
    [NSURLProtocol registerClass:[EncryptedFileURLProtocol class]];

Using the encrypted-file: URL scheme

Now that we have implemented our custom NSURLProtocol subclass and registered it with the URL loading system we can start using URLs that use the encrypted-file: scheme. The example application demonstrates one way to do this – that is to use the scheme to load protected resources into a UIWebView instance. This is actually not very different from using a regular file: URL to load and view an embedded HTML resource. The code from the viewDidLoad method of our main view controller is shown below (from EncryptedResourceDemoViewController.m):

- (void)viewDidLoad {
    [super viewDidLoad];
    webView.scalesPageToFit = YES;
    NSString *indexPath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"EncryptedResources"];
    NSURL *url = [NSURL encryptedFileURLWithPath:indexPath];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [webView loadRequest:request];

The app bundle is queried for the path to ‘index.html’ in the EncryptedResources sub-folder. This is then used to construct an NSURL. An NSURLRequest is created from the URL and a loadRequest: message is sent to the web view. If you are familiar with NSURL and its class methods then you may have spotted the unfamiliar encryptedFileURLWithPath: method. I have extended NSURL using a category to add this method as a convenience. It works just like fileURLWithPath: but creates a URL using the encrypted-file: scheme rather than the regular file: scheme. One cool benefit of extending the URL loading system is that any relative URLs referenced in the HTML, such as the src parameter of IMG elements, will also use the encrypted-file: protocol and will be decrypted on-the-fly.

As mentioned above, URLs are used in many places in the iOS frameworks. To load an encrypted resource into memory you can do the following:

    NSString *indexPath = [[NSBundle mainBundle] pathForResource:@"..." ofType:@"..." inDirectory:@"EncryptedResources"];
    NSURL *url = [NSURL encryptedFileURLWithPath:indexPath];
    NSData *data = [NSData dataWithContentsOfURL:url];

This could used to create a UIImage from an encrypted image file using [UIImage initWithData:] or you could go one step further by extending UIImage using categories to implement a initWithContentsOfEncryptedFile: method.

Next steps

In this article I have presented a scheme for protecting the resources that you embed in your iPhone and iPad applications. Along the way we have also learned about how to use the CommonCrypto API and how to implement a custom URL protocol. The example project demonstrates how to use the scheme and you are free to use the ‘crypt’ command-line tool and EncryptedFileURLProtocol source in your own projects. Something you might want to think about (depending on the value of the resources you are trying to protect and your level of paranoia) is a mechanism for obfuscating the decryption key. With the current scheme the key is compiled into the application binary as a plain string and could be extracted by anyone with a hex editor, a little patience and a little knowledge. Of course, this assumes that they have worked out that the resources are encrypted using AES256.

We’d love to hear if you have found this article useful or even used it in your own projects.

Robin Summerhill is a tech blogger, developer and architect. He is co-founder of Emu Analytics where he is currently working as Head of Technology.

Share and Enjoy:
  • Print
  • email
  • Digg
  • Facebook
  • Google Bookmarks
  • Reddit
  • Twitter


Stephan Burlot July 29, 2010 at 7:33 am

Your article is very interesting, but are you sure you don’t need all the paperwork asked by Apple when using encryption?

Robin Summerhill July 29, 2010 at 8:23 am

This question comes up weekly on None of the Apple representatives are prepared to give legal advice on the forum but the general consensus is that you only need to answer ‘yes’ to the first question ‘Does your product contain encryption?’ if you are implementing new encryption functionality.
If you link to the encryption routines contained in the CommonCrypto library then you are making use of encryption provided by Apple, which should be already covered by a CCATS.

Stephan Burlot July 29, 2010 at 8:35 am

Ah, thanks, I will try to see what happens.

Ricardo Palma August 9, 2010 at 12:46 pm

Hello Stephan,

I would be very much interested on knowing what the response from Apple was when you attempted registering your applicaction.


Dan August 28, 2010 at 12:08 pm

Great writeup, thanks a lot! I’m not familiar with shell scripting and I’m getting errors when I try to build my app. I think they are related to spaces in my project’s path. Other than renaming my folders is there a simple fix for this?

/Volumes/Macintosh HD/Documents/iPhone Apps/App Name/AppName/AppName Files/AppName 2_0/build/ line 9: [: too many arguments

Encrypting /Volumes/Macintosh

/Volumes/Macintosh HD/Documents/iPhone Apps/App Name/AppName/AppName Files/AppName 2_0/build/ line 16: /Volumes/Macintosh: No such file or directory

Robin Summerhill August 28, 2010 at 8:57 pm

Hi Dan,

Glad you liked the article. You were right with your guess about spaces in your project’s path. I’ve updated the shell script in the article and the zip file to add quotes around all the filenames to solve this issue. Thanks for pointing it out to me.

Dan September 3, 2010 at 10:26 am

Thanks for the reply. One more thing – I’m getting a bunch of “Synchronous client exited with no response and no error!” messages in the debugger console when I load files that have been encrypted. Any idea what that’s about?

Robin Summerhill September 7, 2010 at 8:30 am

Not sure what that message means. I’m not seeing it when running on the simulator or the device. Google has a few hits for that message but no-one seems to know what it means. Are you seeing this in your own code or the example project? Simulator or device? Are the files loaded correctly despite the message?

Sarah Clough March 30, 2011 at 9:27 am

I just had this and it was because I had changed the key in the script but not in the URL class.

Blake September 26, 2012 at 3:35 am

I am now getting this on ios 6…no clue why

Alan August 30, 2010 at 12:41 pm

Hi Robin,

I try to work with your code. But decryption method with NSData don’t working.

NSData *data = [NSData dataWithContentsOfURL:url];

Result of the above statement is NULL. Encypting data isn’t decrypted. All function in your NSURLProtocol class isn’t called.

So, what is problem in this case?

Robin Summerhill August 30, 2010 at 12:53 pm

Have you registered the custom protocol by calling:
[NSURLProtocol registerClass:[EncryptedFileURLProtocol class]];

If you have done this correctly then you should be able to put a breakpoint on the canInitWithRequest: method and see it return ‘YES’ when you request the system to load an ‘encrypted-file:’ URL.

Athrun August 27, 2012 at 11:45 pm

Hi robin, many thanks for your great post.

I have the same issue with Alan, I’m sure that i have [NSURLProtocol registerClass:[EncryptedFileURLProtocol class]]; in my code.

Project works with load index.html in web view, but not works with [NSData dataWithContentsURL]. in NSData case ,all functions in NSURLProtocol class isn’t be called.

Do you have any idea on that? Thanks

John Kelley September 2, 2010 at 2:16 pm

Great post. This is one of the better solutions I have seen on the subject. Curious, though. Is this a iOS 4.0 only solution? I think the apple docs list NSStreamDelegate Protocol (used in EncryptedFileURLProtocol.h) as making its debut in 4.0.

Thanks for sharing.

Robin Summerhill September 2, 2010 at 3:16 pm

Glad you found the article interesting. The delegate method stream:handleEvent: has been around as part of an informal protocol since OS2.0, which was formalized as the NSStreamDelegate protocol in OS4.0. To compile prior to OS4.0 just remove the reference to NSStreamDelegate in EncryptedFileURLProtocol.h. I may get around to adding conditional compilation for this at some point.

Francesc November 23, 2010 at 6:58 am

Your solution looks really good. I’ve tryed your example in iOS 4 devices and simulator and works great, but I can’t make it work with a 3.1.3 iOS device. I’ve removed the NSStreamDelegate reference you mentioned, but it looks like when EncryptedFileURLProtocol is finished something goes wrong loading the webview.

These are the last thread-trace printed:
#0 0x33ad1d0c in WTF::HashTable<WebCore::String, std::pair<WebCore::String, WTF::PassRefPtr (*)(WebCore::SharedBuffer*)>, WTF::PairFirstExtractor<std::pair<WebCore::String, WTF::PassRefPtr (*)(WebCore::SharedBuffer*)> >, WebCore::CaseFoldingHash, WTF::PairHashTraits<WTF::HashTraits, WTF::HashTraits<WTF::PassRefPtr (*)(WebCore::SharedBuffer*)> >, WTF::HashTraits >::contains<WebCore::String, WTF::IdentityHashTranslator<WebCore::String, std::pair<WebCore::String, WTF::PassRefPtr (*)(WebCore::SharedBuffer*)>, WebCore::CaseFoldingHash> >
#1 0x33ad1cd0 in WebCore::ArchiveFactory::isArchiveMimeType
#2 0x33ba20ec in WebCore::FrameLoader::committedLoad
#3 0x33ba2020 in WebCore::DocumentLoader::commitLoad

Any suggestions?


Zaygraveyard July 6, 2011 at 4:25 am

it hapened to me too and this is what i did:

if (kCFCoreFoundationVersionNumber_iPhoneOS_3_2 kKeySize ? kKeySize : keyLength);

size_t bufferSize = [self length] + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);

size_t dataUsed;

CCCryptorStatus status = CCCrypt(decrypt ? kCCDecrypt : kCCEncrypt,
key, kKeySize,
[self bytes], [self length],
buffer, bufferSize,

switch(status) {
case kCCSuccess:
return [NSData dataWithBytesNoCopy:buffer length:dataUsed];
case kCCParamError:
NSLog(@”Error: NSData+AES256: Could not %s data: Param error”, decrypt ? “decrypt” : “encrypt”);
case kCCBufferTooSmall:
NSLog(@”Error: NSData+AES256: Could not %s data: Buffer too small”, decrypt ? “decrypt” : “encrypt”);
case kCCMemoryFailure:
NSLog(@”Error: NSData+AES256: Could not %s data: Memory failure”, decrypt ? “decrypt” : “encrypt”);
case kCCAlignmentError:
NSLog(@”Error: NSData+AES256: Could not %s data: Alignment error”, decrypt ? “decrypt” : “encrypt”);
case kCCDecodeError:
NSLog(@”Error: NSData+AES256: Could not %s data: Decode error”, decrypt ? “decrypt” : “encrypt”);
case kCCUnimplemented:
NSLog(@”Error: NSData+AES256: Could not %s data: Unimplemented”, decrypt ? “decrypt” : “encrypt”);
NSLog(@”Error: NSData+AES256: Could not %s data: Unknown error”, decrypt ? “decrypt” : “encrypt”);

return nil;

- (NSData*)decryptedWithKey:(NSData*)key {
return [self makeCryptedVersionWithKeyData:[key bytes] ofLength:[key length] decrypt:YES];

- (id)initWithContentsOfEncryptedFile:(NSString *)path withKey:(NSData *)key {
[self release];
NSData *encryptedData = [[NSData alloc] initWithContentsOfFile:path];
if (!encryptedData) return nil;
self = [[encryptedData decryptedWithKey:key] retain];
[encryptedData release];
return self;

i hope it helps and if you need any info plz ask :)

Zaygraveyard July 6, 2011 at 4:40 am

I realized that I didn’t thank you Robin for this great post so thanks and I found that I forgot to put important code in the last comment so here’s the link to my project which is an updated version of yours “”
and if you find any thing I did wrong plz let me know.
Thx again Robin for this.

mike p September 13, 2010 at 3:11 pm

Any ideas on weather this would work for the MPMoviePlayer(View)Controller? I’m using the automatic view controller, the view controller seems to load but doesn’t play the video. I’ve gotten the code to work without encryption to make sure everything is set up right, second snippet of code, and it does.

code that doesn’t work with sample code

NSString *indexPath = [[NSBundle mainBundle] pathForResource:@”VideoFull” ofType:@”mov” inDirectory:@”EncryptedResources”];
NSURL *url = [NSURL encryptedFileURLWithPath:indexPath];
moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self presentModalViewController:self.moviePlayer animated:YES];

code that works using sample code

NSString *url = [[NSBundle mainBundle] pathForResource:@”VideoFull” ofType:@”mov”];
NSURL *videoURL = [NSURL fileURLWithPath:url];
moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
[self presentModalViewController:self.moviePlayer animated:NO];

thanks ahead of time!!!

Robin Summerhill September 15, 2010 at 9:24 am

Hi Mike,

It looks like MPMoviePlayerViewController is bypassing the URL loading system by using lower-level Core Foundation APIs. The canInitWithRequest: method of the custom URL protocol is not being called at all.

An alternative approach here would be to include a minimal web server in your app that decrypts resources on-the-fly and serves them up to local requests. I may add an article on how to do this in the near future.

mike p September 15, 2010 at 10:58 pm

Ok thanks for looking into it. I’m avoiding hosting anything on a server, so will probably look into not using the ready built movie view controller. Will let you know if I come across anything.

Arnold G March 3, 2011 at 10:36 pm

Good article. I would be interested in reading an article on using an intermediate web server for on-the-fly decryption if you ever write it. I suspect Netflix is doing something similar in their app to map between streaming protocols.

Brian Chung March 15, 2011 at 5:05 am

Hi Robin,

Are there anyway to decrypt mp4 files and load it into MPMoviePlayerViewController without using web server? In my case, all mp4 files will be encrypted and stored in the bundle.

Brian Chung

stefan e April 14, 2011 at 10:43 am

hi, a tutorial about this would be greatly appreciated. we are facing the same problems are currently trying to get cocoahttpserver to run in our app to be able to decode the video and stream it locally, not funny :)



thomas May 17, 2011 at 12:46 pm

Have you had time yet to look into the issue in more detail?

I tried it myself with a MPMoviePlayerController and have the same problem. In my case, canInitWithRequest is called though. Also, startLoading, stopLoading and stream methods are called, so there seems to be happening something. Unfortunately, the media player doesn’t play anything.

Lars February 10, 2012 at 10:30 am

Robin, great post!
Has anybody got this working with video files?
I am very interested!

Nathan B. January 25, 2013 at 12:03 am

I realize this post is old but it is still very much relevant and I wanted to share a solution. While efficiency can be questioned it satisfied the immediate need; and performing steps 1-3 via Grand Central Dispatch I did not find a massive performance hit.

Using the project posted by Akhil P.K December 13, 2012 at 1:29 am, here are the steps I used to leverage the hard work of the author (Robin) and bypass some of the limitations of MPMoviePlayerViewController:

1. Obtain the file URL for the encrypted movie:

NSURL *url = [NSURL encryptedFileURLWithPath:[[NSBundle mainBundle] pathForResource:@”video” ofType:@”mov” inDirectory:@”EncryptedResources”]];

2. Using the URL load the video into an NSData Object:

NSData *movideData = [NSData dataWithContentsOfURL:url];

3. At this point due to the custom protocol the content is decrypted therefore we now store the NSData blob to a file within the our apps /tmp directory:

NSString *destinationPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@""];
BOOL isFileSaved = [movideData writeToFile:destinationPath atomically:YES];

4. If the file saved properly we can use the destination path and make a NSURL for the MPMoviePlayerViewController:

NSURL *url_ = [NSURL fileURLWithPath:destinationPath];

5. Once the URL is created we can load the decrypted file with MPMoviePlayerViewController, setup prefs, and play the video:

MPMoviePlayerViewController *player_ = [[MPMoviePlayerViewController alloc]initWithContentURL:url_];
player_.moviePlayer.allowsAirPlay = YES;
player_.moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
player_.moviePlayer.fullscreen = YES;
player_.moviePlayer.shouldAutoplay = YES;

Silvia August 6, 2012 at 6:27 pm

Hi Robin,
Did you post any article about this later? I couldn’t find that…

Stephen Prance February 28, 2011 at 8:21 pm

Hello Robin,

I am writing an app which essentially has a navigation controller (based on the Elements by Apple) pushing selected pages of a pdf (based on the Zooming PDF Viewer by Apple). Your solution looked just the trick to secure the pdf.

I am pretty sure my file NSW_CAG_EDITION_14_JUL_09 is encrypting OK on build. However crashing when I try to decrypt and view.

I put your code in pdfscrollview.m (where CGPDFDocumentCreateWithURL is called)

NSString *indexPath = [[NSBundle mainBundle] pathForResource:@”NSW_CAG_EDITION_14_JUL_09″ ofType:@”pdf” inDirectory:@”EncryptedResources”];

NSURL *url = [NSURL encryptedFileURLWithPath:indexPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
pdf = CGPDFDocumentCreateWithURL((CFURLRef) request); //crashes here

Will your code work with CGPDFDocumentCreateWithURL? Any help would be greatly appreciated.



Robin Summerhill March 4, 2011 at 7:37 am

Hi Steve,

Since originally writing the article it has come to my attention that certain APIs bypass the URL loading system and access the file system at a lower level. This includes the C-based PDF API. The method presented in the article works for displaying PDFs in an embedded UIWebView but the C API calls will fail, as you have found. Luckily for you, PDFs support encryption natively. You can encrypt your PDF in the application you used to author it, or encrypt it later in Acrobat Pro. Then open the PDF with CGPDFDocumentCreateWithURL and supply the password with CGPDFDocumentUnlockWithPassword.

I plan to update the article soon with some extra enhancements and to cover issues such as this.

Wilson March 24, 2011 at 10:32 am

Hi Steve,

great post.
When do you plan to update the article?
Right now i need to use encrypted PDFs. The problem is, that i need to encrypt them on device (no authoring software) and because of customer restrictions i cannot decrypt them to filesystem for reading. So i have to use the URL loading system. Is there any way to force CGPDF* to use the URL loading system?


JD March 1, 2011 at 5:28 pm

Great work! I try it on png files with UIImage initWithData, works well.
But what I want to do exactly the same for sqlite file, I try it and don’t work.
I do something like that:

NSString *indexPath = [[NSBundle mainBundle] pathForResource:@”MyDBFile” ofType:@”sqlite” inDirectory:@”encrypted”];
NSURL *storeURL = [NSURL encryptedFileURLWithPath:indexPath];
[persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error];

Any ideas ?

Robin Summerhill March 4, 2011 at 7:46 am

Hi JD,

Since originally writing the article it has come to my attention that certain APIs bypass the URL loading system and access the file system at a lower level. This includes the C-based SQLite API, which underlies the Core Data storage that you are using. Working with SQLite is also a slightly more complicated proposition than just loading a resource file because random access is used rather than bringing the whole database into memory. I’m sure it would be possible to intercept the data flow somewhere in the chain from database, through Core Data to the application level to perform automatic decryption. It’s something we might look into in future.


Arpit April 5, 2011 at 1:29 pm

Hi Robin,
Thanks for the awesome solution. But we are having problems with loading of ajax files. We are using jquery to load the files lazily in the app using ajax. However $.ajax is always resulting in Error. Have you tried this with Ajax ?

Arpit April 6, 2011 at 9:12 am

Figure out a solution for Ajax requests. Safari has issue with cross domain requests if you use encrypted-file:// So Just changed encrypted-file to “file” and all ajax requests works seamlessly.

Robin Summerhill April 6, 2011 at 10:12 am

OK. Sounds like XMLHttpRequest is looking at the protocol and switching behaviour based on ‘http’ or ‘file’. It doesn’t recognise ‘encrypted-file’ as a valid protocol so is barfing. Good to know.

Marc A. April 29, 2011 at 4:43 am

Great work! I tried the code below but it doesn’t work.
Any idea of what’s wrong with my code?

-(IBAction)OpenIN:(id)sender {

NSString *fileToOpen = [[NSBundle mainBundle] pathForResource:@”…” ofType:@”…” inDirectory:@”EncryptedResources”];
self.controller = [UIDocumentInteractionController interactionControllerWithURL:[NSURL encryptedFileURLWithPath:fileToOpen]];
self.controller.delegate = self;

CGRect navRect = self.navigationController.navigationBar.frame;
navRect = CGRectMake(348.0f, 870.0f, 0.0f, 0.0f);
[self.controller presentOptionsMenuFromRect:navRect inView:self.view animated:YES];

Thanks for your help!

Rodrigo May 6, 2011 at 4:15 pm

It’s possible to change the name of the folder “EncryptedResources”? If so, how can I change that?
Tks a lot.

Robin Summerhill May 6, 2011 at 6:11 pm

Yes, it’s easy.

1. Change the name of the directory where you place your resources to be encrypted from ‘EncryptedResources’ to whatever you want.
2. Change the first line of the encryption script attached to the ‘Encrypt Resources’ custom build step:
DIRNAME=[the directory you chose in step 1]
3. Change the directory name wherever you load an encrypted resource in your app:
e.g. NSString *indexPath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"EncryptedResources"];

Rodrigo May 6, 2011 at 7:35 pm


But I’m still having problems with the last step (Using the encrypted-file: URL scheme). I have an xml file and I couldn’t show the data because the file is empty and don’t even starts the process of parse. Do you have any suggest?

Tks a lot again

Rodrigo May 6, 2011 at 7:46 pm

Sorry, I forgot one detail. Appears this text in console: Synchronous client exited with no response and no error!

Robin Summerhill May 7, 2011 at 8:51 am

This may be a separate issue. See the comments up above. Have you changed the encryption key in the script but not at the top of EncryptedFileURLProtocol.m? They need to match.

Otherwise you will need to work out which step is failing – is it not locating the file correctly or is it not decrypting it? Try changing ‘encrypted-file:….’ to just a plain ‘file:….’ and see if the encrypted file is loaded – view the encrypted contents in the debugger.

Daoxin July 2, 2012 at 9:14 am

Hi, Excellent article!
I want to use this technology to my project.
I have one html and one mp3 file, but I can not play mp3 file.
Here is index.html source.

If you are reading this, it is because your browser does not support the audio element.

Looking forward to your answer.

John May 11, 2011 at 2:33 pm

Are there any news about sending an app with this encprytion? Do I have to specify? Apple is accepting with no problems?
Tks and congratulations for this article

Mario May 23, 2011 at 9:14 am

Hello, I am getting the same error on the console…any other things we need to look into which might be incorrect?

Mario May 23, 2011 at 9:21 am

The file is encrypted in the EncryptedResources folder of the file. Although the original file still exists in the root directory of the file. I have removed it from the “copy bundle resources” in the build phases.

Thanks for help

shri September 16, 2011 at 6:30 am

i m able to play 1 song using mediaplayer framework but next song not play
plaza give me some step to play.

thanks in advance

shri September 22, 2011 at 1:03 am

very great demo apps for encription. lastly my my encription is done from this demo but i m not able play more then one song at a time. if i copy more song into the encryptedResource folder that can not be played. why?
plz. give me some steps for playing these audios.

Sapana September 30, 2011 at 8:30 am

Hello ,
This is the best way to hide the images and song of application . But i have one major problem , I have added some song in the EncryptedResources folder and play this song on simulator it was play . Same application i have tested on iPhone device at that song was not play. Please help its very urgent for me.
Thank you so much

Arpit Jain October 5, 2011 at 2:02 pm

Any update for iOS5. Our application is working on 4.3.2 but has errors for iOS 5 GM release. I am trying to debug the issue, but if you have already worked on it, it will save me time :-)

Will update here if I find the solution or at least the issue.

Andrew Jackman October 5, 2011 at 5:23 pm

Yep same here Arpit. Doesn’t work for iOS 5. Major issue for me, as I have an app in the field with encrypted resources that I need to fix.

Here are the kinds of errors I get:

ImageIO: PNG Extra compressed data
ImageIO: PNG invalid stored block lengths
ImageIO: PNG incorrect data check
ImageIO: PNG PNG unsigned integer out of range

Any suggestions would be greatly appreciated.


Robin Summerhill October 5, 2011 at 7:30 pm

We’re pretty busy at the moment fixing some iOS5 issues with our apps but I’ll take a look at the problem here.

Did you see the problem with the early betas or has it just appeared in the GM release?

Robin Summerhill October 5, 2011 at 11:23 pm

I’ve fixed the problem on iOS5. The example project has been updated. The single change is line 99 of EncryptedFileURLProtocol.m. It should read:

NSData *data = [NSData dataWithBytes:outBuffer length:len];

Andrew Jackman October 6, 2011 at 2:04 am

Thanks for the prompt response. Really appreciated. Unfortunately when I make the change I get the following:

malloc: *** error for object 0xb5fe00: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

Andrew Jackman October 6, 2011 at 3:32 am

Sorry – my mistake. All looking good now. Thanks very much!

Arpit Jain October 6, 2011 at 4:53 am

Thanks for the prompt response Robin. This is working perfectly.
Although, we again are facing problems with Ajax requests and files requested through ajax are not getting loaded. We are working on it.

If you have any suggestion for this, it will be greatly appreciated.

Arpit Jain October 6, 2011 at 5:02 am

Just FYI, its working in iOS 4.3.

It is just not working in iOS5. After [inStream open] is called, control is not reaching the “stream” method. Any suggestions?

shridhar October 10, 2011 at 1:16 am

its great ………
i have some song in EncryptedResource folder , encryption done successfully but not played into AVAudioPlayer. its show me right song path of EncryptedResources but not play.
please give me the right way

thanks in advance.
shridhar mali.

Daniel Shaw October 14, 2011 at 8:26 pm

Hi Robin,
I realize the original post is over a year old, but this is fantastic!. A friend and I are working on a Universal app and need this mechanism to protect a licensed font we will be placing it it. I had to do a little bit of extra work from the default, in order to make the custom font available to UIFont, so I thought I would post this message if anyone else needs to do something similar
In addition to the NSURL, you will need to manually read the font data into an NSData object, then use CoreGraphics and CoreText to load the font (or fonts) into the lower level font manager. Once this is complete, you can initialize a UIFont with the font name e.g.:
NSURL *fontsURL = [NSURL encryptedFileURLWithPath:indexPath];
CFErrorRef error; //used my the CoreText font manager to record any errors.
NSData * fData = [NSData dataWithContentsOfURL:fontsURL];

CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)fData);
CGFontRef fr = CGFontCreateWithDataProvider(provider);
UIFont * calendar = [[UIFont fontWithName:@"calendar" size:25] retain];

These are iOS documented API calls and should not cause any app rejection.

Robin Summerhill October 19, 2011 at 8:08 am

Thanks for the great tip about fonts. Glad you liked the article too.

Jaanus May 13, 2012 at 8:01 pm

Thanks so much for both the original article, and for this extra info about fonts! Very useful and works great. I thought I could simplify this by using CTFontManagerRegisterFontsForURL, but sadly, this again bypasses the custom URL business, so it has to be done exactly as shown in this comment.

I’m also getting the “Synchronous client exited with no response and no error!” indicated by others when I load each font. Seems to be just a warning in the output and doesn’t affect anything.

Sam Becker June 22, 2012 at 9:00 pm

Hi Daniel/Robin,

I just tried to do what you did and I keep getting OT Font Face Error: 2 messages. I was able to load the fonts fine using CGFontRef before encryption but not after. ALSO I had to change the file naming scheme from encrypted_file l_something_or_other to ‘file’ just to get as far as the OT error. Any ideas? If I didn’t change the name scheme CGFontRef would say it was an unrecognized file type/scheme.



Sam Becker June 25, 2012 at 11:21 am

I figured out what I was doing wrong. I had forgotten to uncheck the ‘Targets’ tab for encrypted resources folder. For some reason this caused the font to fail to load ONCE after each build > clean. After that, every compile worked. Same for simulator AND device. Anyway, this made it impossible to debug. Unchecking the ‘Target’ tab was a lifesaver. Sam

John Grøtting August 9, 2012 at 10:24 am

We are trying to do something similar, but so far without success. Rather than rendering text using CoreText, we are using UIWebView and rending all text using @fontface in HTML5. Any thoughts?

Adi November 11, 2011 at 7:10 am

I know that this is an old post, but I’ve used your method recently and had some problems using it on iOS 3.1.3
The easy fix (if anyone is interested) is to call the
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
also when all response is received in your NSURLProtocol subclass. The response can be some bogus NSURLResponse instance, and it will work .

Thanks for the great idea, btw !

Mudireddy Suresh December 27, 2011 at 6:14 am

Hi Robin Summerhill,
Great solution. It helps me a lot.

I observed one issue with the sample app as well as my application where if requested for a encrypted image
URL in NSURLRequest with UIWebView then all the decrypted 512 byte chunks were provided to UIWebView in NSStreamDelegate but finally the raw image buffer shown in the UIWebView.

What is the issue ? Please let me know if anything need to be handled.
This is the case for image, PPT ..etc (Direct URL without any HTML file reference to them).

Mudireddy Suresh December 28, 2011 at 6:00 am

Hi Robin,
Thanks for the nice stuff.

My previous issue which I was posted here was solved with
[self.client URLProtocol:self didReceiveResponse:response ] with proper MIME type & encoding type.

Now the new issue I am facing is with the same code, playing encrypted MP4 video file (locally stored) using UIWebView is failing with the following error.

Error Domain=WebKitErrorDomain Code=204 “Plug-in handled load” UserInfo=0x3c0b60 {NSErrorFailingURLStringKey=myapp:///private/var/mobile/Applications/00109035-7155-4FF6-B247-DF5F26A87024/tmp//Docs/34199c68fcfbc45492550c5298272117502b0149.mp4, WebKitErrorMIMETypeKey=video/mp4, NSErrorFailingURLKey=myapp:///private/var/mobile/Applications/00109035-7155-4FF6-B247-DF5F26A87024/tmp//Docs/34199c68fcfbc45492550c5298272117502b0149.mp4, NSLocalizedDescription=Plug-in handled load}

Please help me to overcome this issue with your comments.

Thanks & Regards,

Jens Beyer January 6, 2012 at 7:20 am

I try your code on lion, but in – (void)startLoading the [[self.request URL] path] is always nil.
So the inStream init raises an error.
The URLstring is:

Any idea what is going wrong here?

Tapan Desai January 12, 2012 at 4:59 pm


Thanks for the awesome solution. I have one questions though, i am building app that allow users to download files into local device and view it in UIWebView. I want to encrypt file after its downloaded on device and decrypt while trying to view in UIWebView so if anyone jail brake iPad or use any other tool, they can’t view local files.

I would appreciate your input on this.

Thanks in advance,
Tapan Desai

Berik Visschers January 13, 2012 at 10:53 am

Keep in mind though, that with a jailbroken device, any (https) communications can be hijacked by a proxy.

Berik Visschers January 13, 2012 at 10:42 am

Hi Robin,

Although the resources are indeed encrypted. The security added is not very high.
To show that this security is easily broken, I’ve build & run the project. Then went to the app:
$ cd /Users/myName/Library/Application Support/iPhone Simulator/5.0/Applications/0928889D-296D-4D1C-BC46-247BEDD7DD24/

then tried to read the encrypted resources:
$ cat EncryptedResources/index.html

Berik Visschers January 13, 2012 at 10:43 am

Oke, it’s encrypted. But how about a password? I ran:
$ strings EncryptedResourceDemo

There it is, the password is plain-text (hidden inside the binary) ‘abcdefghijklmnopqrstuvwxyz123456′.

I suggest hiding the password for the encryption a little better. Transforming it into an MD5 hash in binary format during compile time will add some security (will be harder to find). More secure strategies can be thought of.

Is this code open sourced? Is this code already on github?

Thanks for sharing this code!


Berik Visschers January 13, 2012 at 11:04 am

This looks like a good example of how to hide a password in a binary:

Robin Summerhill February 10, 2012 at 10:34 am

Hi Berik,

As mentioned in the article: ‘Something you might want to think about (depending on the value of the resources you are trying to protect and your level of paranoia) is a mechanism for obfuscating the decryption key. With the current scheme the key is compiled into the application binary as a plain string and could be extracted by anyone with a hex editor, a little patience and a little knowledge.’

chandrika bhat February 21, 2012 at 8:31 am

Really helped a lot.. and saved our time.

Chiemeka March 16, 2012 at 7:06 am

Great Roberts,
I will test this out and try to use the output data with a uidocument object.
Also, obfuscating the decryption key…? Sure necessity. I’ll try to report what I can come up with.

Sam Becker July 26, 2012 at 11:24 am

Any luck?

Sarah Clough March 21, 2012 at 1:11 pm

Thanks for the ios 5.0 update, I’ve been puzzling over why it was only reading in half the file to no avail!

Netshark March 27, 2012 at 4:26 am

It would be great if your code could be used to encrypt files to. I load pdf-files, which must be protected, from a webservice and want to put them unreadable for others on the device. The apple security is not enough, because some customers don’t use a device code.

Saranya krishnan March 28, 2012 at 8:35 am

Thanks for the excellent tutorial . I have one question , When i am trying to retrieve the data from the URL , i am getting output as “0 bytes” . I have pasted the following code

NSString *indexPath1 = [[NSBundle mainBundle] pathForResource:@”aptogo” ofType:@”png” inDirectory:@”EncryptedResources”];
NSURL *url1 = [NSURL encryptedFileURLWithPath:indexPath1];
NSData *data = [NSData dataWithContentsOfURL:url1];
NSLog(@”data length:%d”,[data length]);
UIImage *imagename=[[UIImage alloc] initWithData:data];
[image setImage:imagename];

Please help me out in this.

Athrun August 27, 2012 at 11:17 pm

I have the same issue, have you found the solution? Thank you

viv April 15, 2012 at 5:55 pm

Thanks for the awesome article and code Robin.
I have observed that the NSURL pathway misses calling the decryption functions when using the following function:-
[NSFileManager copyItemAtURL:

Any ideas how to make this pathway use the decryption? The error I see is the following:-
Error Domain=NSCocoaErrorDomain Code=262 “The operation couldn’t be completed. (Cocoa error 262.)

I’ve experimented by trying to use the aptogo.png file as source.

peryll May 22, 2012 at 3:57 am

Thanks Robin for the article.

I’m back to the problem with the “Synchronous client exited with no response and no error!” output.
I have found out that the encryption works in simulator and almost all devices. But in some cases it does not work. It is in the [NSData dataWithContentsOfURL] where the problem is. I havn’t found out yet why this occurs. The encryption key is the same in the script and in the encryption class.

peryll May 22, 2012 at 4:02 am

Sorry I put my comment in the wrong thread!

Thanks Robin for the article.

I’m back to the problem with the “Synchronous client exited with no response and no error!” output.
I have found out that the encryption works in simulator and almost all devices. But in some cases it does not work. It is in the [NSData dataWithContentsOfURL] where the problem is. I havn’t found out yet why this occurs. The encryption key is the same in the script and in the encryption class.

Mritunjay June 13, 2012 at 9:29 am

Really, its Good Articles……!

Steve July 4, 2012 at 4:06 am

Thanks for a great article! I also attempted to get this technique to work with video playback using AVFoundation. Unlike the experiences that some other folks have had, everything is being called correctly. My issue is running out of memory, with Instruments telling me that CFData (bridged from NSData I suppose) is the responsible party. These videos are fairly large, up to 10gb for some. It looks like AVFoundation is retaining all of the NSData instances that are being sent to it via [self.client URLProtocol:self didLoadData:data]. What I think may be happening is that iOS is trying to look up video metadata information in the file, such as duration and as such is ending up trying to load the entire file into memory. It makes me wonder if the normal file based playback just maps the entire thing and just goes about its business that way. Has anyone ever had any success in pulling this off with video files?

Blake August 8, 2012 at 5:57 am


My App crashes with this when I try to use encrypted resources.

*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[__NSPlaceholderArray initWithContentsOfFile:]: string argument is not an NSString’

I get the resources with this line:

NSArray *array = [[[NSMutableArray alloc] initWithContentsOfURL:[NSURL encryptedFileURLWithPath:tablePath]] objectAtIndex:[unit intValue]-1];

tablePath is the path to the file. Does anyone see what is wrong? thanks!

MarionMck August 27, 2012 at 6:31 am

Sorry, I seem to be missing something here. I had problems getting this working in my app so I added an image to the example project. canInitWithRequest is called as expected for the existing example files of index.html and aptogo.png but doesn’t get called for my new image file. The URL looks ok, but the NSData comes up as nil. This is how I’m loading the image:

NSString *imgPath2 = [[NSBundle mainBundle]
NSURL *imgurl2 = [NSURL encryptedFileURLWithPath:imgPath2];
NSLog(@”url scheme %@”, [imgurl2 scheme]);
NSLog(@”url relpath %@”, [imgurl2 relativePath]);
NSData *data2 = [NSData dataWithContentsOfURL:imgurl2];
UIImage *img2 = [[UIImage alloc] initWithData:data2];

I can see the file in the EncryptedResources folder so it should be finding the file from the relative path ok. I get the same result in the simulator or on a device. I am running Xcode 4.3.3 for iOS 5.1.
This seems a really stupid question after all the responses above show that it works fine, but I just can not see what I’m doing wrong!

MarionMck August 29, 2012 at 4:33 pm

I’ve tried forcing the use of NSURLConnection by using the following

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:imgurl2];
NSData *urlData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&myerr];

but still canInitWithRequest is not called and I get an ‘unsupported URL’ error.

Shahid September 11, 2012 at 5:11 pm

Can anybody please help me with the shell script to recursively iterate through all sub folders and encrypt them as well? Currently it hangs if there is subfolder.

Jason September 25, 2012 at 9:55 pm

Hi Robin,

Thanks for this great post, I have been using this in my app for quite some time and it’s working great for me.

However, with iOS6 this code actually leaks memory spectacularly when you use it. The official reply I got from Apple as to why was this:

Below is a log that’s new in iOS 6:

coreAssert(ISBOOLEANTRUE(fScheduledCallbackFlags, didReceiveResponse), “NSURLConnection/CFURLConnection ordering violation: didReceiveData to be scheduled before didReceiveResponse”);

It logs when a custom NSURLProtocol, wants to trigger NSURLConnection to issue didReceiveData before didReceiveResponse.

So if you are using this code in iOS6, this is what I added to the – (void)startLoading method to fix this leak

[self.client URLProtocol:self didReceiveResponse:[[[NSURLResponse alloc] init] autorelease] cacheStoragePolicy:NSURLCacheStorageNotAllowed];

Hope this helps somebody! :)

Fatemeh September 26, 2012 at 11:10 am

Hi It’s great tutorial, Thanks Robin Summerhill…

I have a problem and hope you help me…
I have number of xml files that I don’t want be accessible… I encrypted them and also decrypted and webview shows the content of these files. but I need the string content of these files, or data type of them.
I have tried to use data by NSData* data = [[NSData alloc]initWithContentsOfFile:url]; but these line don’t call the EncryptedFileURLProtocol methods and I get null. The methods in that class only call when I use this line: [webView loadRequest:request];
I tried with other files format but this don’t work. Could you help me?
Thanks for your attention…

Jason September 26, 2012 at 8:29 pm

Fatemeh you should probably show all of your code leading up to before and after your call to NSData so we can see what your doing better

Fatemeh September 27, 2012 at 2:36 pm

On the sample code of “”, I only commented this line: [webView loadRequest:request];
and then put NSData* data = [[NSData alloc]initWithContentsOfFile:url] to load data on NSData object.
The data is null …

Jason September 27, 2012 at 9:06 pm

I’m assuming it’s null because you are not actually starting an actual stream for the file to be decrypted. Essentially what you are doing is just loading an encrypted file which isn’t actually decrypted.

If you create a NSURLConnection which loads the URL and then put in delegate methods for didReceiveData to compile the bits of the stream together into one big NSData object then conversely turn it into an NSString in didFinishLoading or whatever representation you want out of your data that it will work for you

Fatemeh September 28, 2012 at 5:00 pm

Thanks Jason, I followed the way you mentioned before, and I did not get the correct data. After your comment I tried this again and this return data. I think I made a mistake before.
Thanks very much Jason for your help and Thank you, Robbin for your useful topic…

Jason October 1, 2012 at 10:29 pm

No worries, glad you got it all working :)

Jeroen October 4, 2012 at 10:25 am

I really loved this way of encryption. I got it semi-working pretty fast. Sadly I was not able to get it working flawlessly. For some reason it sometimes fails to decrypt the last few characters of an encrypted file. This happens with both my application and the provided demo application. I use IOS SDK 5.1.

For instance:
index.html contains “abcdefghijklmnopqrstuvwxyz1234567890″
it occasionally shows “abcdefghijklmnopqrstuvwxyz123456″, sometimes it does it correctly.

In my main application (Cordova) this causes odd behavior when a closing tag is corrupt. I would love to know if other people faced the same problem. Any insight would be great!

On a side note: Does anyone know if you can disable the xcode warning “A signed resource has been added, modified, or deleted.”. It keeps showing the warning at “Verifying application”. I can get it running by revalidating the shell bash script though. For your info, I test on a device.

Jeroen October 4, 2012 at 10:28 am

I am pretty sure that it’s related to decrypting it. I have inspected the output files and at both cases (failure & success) it had the same content.

Jeroen November 6, 2012 at 11:26 am

I solved this by changing this line:
// NSData *data = [NSData dataWithBytesNoCopy:outBuffer length:len freeWhenDone:NO];
NSData *data = [NSData dataWithBytes:outBuffer length:len];

I suspect it has to do with Automatic Reference Counting.

Sam Becker November 7, 2012 at 2:02 pm

Does anyone else get this error:

CFNetwork internal error (0xc01a:/SourceCache/CFNetwork_Sim/CFNetwork-609/Connection/URLConnectionClient.cpp:2216)

When running on iOS 6?

Wilmar November 8, 2012 at 4:21 am

Tons of it, as does numerous other people in the comments. It ends with the error: Synchronous client exited with no response and no error!

No idea how to fix it yet.

Wilmar November 8, 2012 at 4:28 am

Haven’t tested completely yet, but I changed the following and the [code]Synchronous client exited with no response and no error![/code] error disappeared.

1) Changed [code]NSData *data = [NSData dataWithBytesNoCopy:outBuffer length:len freeWhenDone:NO];[/code] to [code]NSData *data = [NSData dataWithBytes:outBuffer length:len];[/code]

2) Added [code][self.client URLProtocol:self didReceiveResponse:[[[NSURLResponse alloc] init] autorelease] cacheStoragePolicy:NSURLCacheStorageNotAllowed];[/code] at the beginning of the -startLoading method in EncryptedFileURLProtocol.m

Thanks to the previous two commenters who posted these fixes.

Wilmar November 8, 2012 at 4:30 am

I see my [code] tags don't work. Here is a clean version:

Haven't tested completely yet, but I changed the following and the Synchronous client exited with no response and no error! error disappeared.

1) Changed NSData *data = [NSData dataWithBytesNoCopy:outBuffer length:len freeWhenDone:NO]; to NSData *data = [NSData dataWithBytes:outBuffer length:len];

2) Added [self.client URLProtocol:self didReceiveResponse:[[[NSURLResponse alloc] init] autorelease] cacheStoragePolicy:NSURLCacheStorageNotAllowed]; at the beginning of the -startLoading method in EncryptedFileURLProtocol.m

Thanks to the previous two commenters who posted these fixes.

Sam Becker November 8, 2012 at 8:50 pm

Thanks Wilmar (+ Jeroen)! You’re my hero(s)! I had added the didReceiveResponse: method but to the wrong part and I was getting some nasty crashes. Now I have no more errant console warnings and I can actually see what the hell is going on! Thanks SO much.

Akhil P.K December 13, 2012 at 1:29 am

Zaygraveyard has done great job and the final project can be downloaded from the below link. The issues relating to NSData, UIImage etc are solved and the application is working fine. Thanks to Robin Summerhill also. It is working fine in IOS 6.0 also. Please download the sample project from


{ 18 trackbacks }

Previous post:

Next post: