What is the best way to encrypt NSURLCache?

I want to encrypt / decrypt all cached data from NSURLSession using AES256. I am new to working with Alamofire, but I think that it is possible to do this without the participation of the library itself.

I do not know exactly what is the easiest way to encrypt data before caching and decrypt it after retrieving from the cache.

I see that I can use the Alamofire SessionDelegate and the dataTaskWillCacheResponse and dataTaskWillCacheResponseWithCompletion for encryption, but I do not see anything related to the extracted data from the cache to do the decryption.

On the other hand, I was thinking of custom NSURLProtocol to override cachedResponse , but I don't see anything related to caching this answer, only with the extracted data.

In general, I donโ€™t know if this can be done, or I need to use a combination between NSURLSessionDelegate/SessionDelegate and NSURLProtocol or perhaps a subclass of NSURLCache to complete the task and pass it the Alamofire session, or is there something simpler, or I'm terrible wrong: P

Any help would be really appreciated.


EDIT

I am trying to achieve this with the following implementation. First of all, a very simple cache subclass:

 class EncryptedURLCache: URLCache { let encryptionKey: String init(memoryCapacity: Int, diskCapacity: Int, diskPath path: String? = nil, encryptionKey: String) { guard !encryptionKey.isEmpty else { fatalError("No encryption key provided") } self.encryptionKey = encryptionKey super.init(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: path) } override func cachedResponse(for request: URLRequest) -> CachedURLResponse? { objc_sync_enter(self) defer { objc_sync_exit(self) } return super.cachedResponse(for: request)?.cloneDecryptingData(withKey: encryptionKey) } override func storeCachedResponse(_ cachedResponse: CachedURLResponse, for request: URLRequest) { objc_sync_enter(self) defer { objc_sync_exit(self) } super.storeCachedResponse(cachedResponse.cloneEncryptingData(withKey: encryptionKey), for: request) } } 

And a cached response extension to return encrypted / decrypted data

 extension CachedURLResponse { func cloneEncryptingData(withKey key: String) -> CachedURLResponse { return clone(withData: data.aes256Encrypted(withKey: key)) } func cloneDecryptingData(withKey key: String) -> CachedURLResponse { return clone(withData: data.aes256Decrypted(withKey: key) ?? data) } private func clone(withData data: Data) -> CachedURLResponse { return CachedURLResponse( response: response, data: data, userInfo: userInfo, storagePolicy: storagePolicy ) } } 

It works , but only for mockable.io, which I set with the Cache-Control: max-age=60 header Cache-Control: max-age=60 . I also test SWAPI http://swapi.co/api/people/1/ and Google Books https://www.googleapis.com/books/v1/volumes?q=swift+programming .

In all three cases, the responses are correctly encrypted and cached. I do my testing by disconnecting the Internet connection and setting the session configuration requestCachePolicy = .returnCacheDataDontLoad .

In this case, the request made in mockable.io is correctly decrypted and returned from the cache, and the rest say NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." . This is VERY weird because with this policy it should say NSURLErrorDomain Code=-1008 "resource unavailable" if there is no way to return the cached data. If there is a decryption of the error, then it says that it was an error serialized for the JSON object.

I also tested the general shared cache and works as expected, data is returned with this policy. I thought this could be due to the lack of cache headers in the SWAPI and GBooks responses, but this test works, it returns cached data.

Then I did another test: using my cache, but without encrypting / decrypting the data, I just cloned the returned cached answer with the data as is, without any results. Then I tried the last and very stupid test: to avoid cloning the response, just return cachedResponse and then IT WORKED. How is this possible? If I clone cachedResponse to enter my encrypted / decrypted data, this will not work! Even in Apple examples, they create new cached responses without fear.

I donโ€™t know where the error is, but in a minute or two I will jump through the window.

Any help please? Thank you very much.


EDIT 2

I changed the emails with the DTS engineer from Apple, and the conclusion is that this cannot be achieved because the supporting CF type does more logic than the Foundation object, in this case it performs validation against the URLRequest which is passed to it when the system caches the response but I cannot pass it when I do a clone with regular NSCachedURLResponse.

When the system checks the request for the request, it is not.

+5
source share
1 answer

It is not possible to intercept the caching retrieval calls from the delegate that I know of, and I donโ€™t think the user protocol will even be asked to process the request if it goes out of the cache, but I could be wrong. Your options are probably:

  • I will explicitly ask for the data cache before you request the URL.
  • Add code to code that actually processes the response so that it recognizes that the data is encrypted and decrypted.

    For example, you can insert an extra header in the headers when you store it in the cache to indicate that the cached data is encrypted. Then, when you see the value of the magic title on the way back, decode it.

  • Create a subclass of NSURLCache and process the decryption there (and, ideally, save the data to disk in another file so as not to violate any requests in the application using the normal cache).
+3
source

Source: https://habr.com/ru/post/1264738/


All Articles