Encrypting CoreML

ML models, like many other forms of intellectual property, are at risk of being stolen and used without the author’s knowledge. In the case of CoreML, most of the models are hardcoded within the application. It is enough to take a Jailbreak device, read the contents of the bundle and pull out the model. Selecting the input of the model is already a matter of technology and a certain amount of time. At one time in practice, I used a similar approach to compare the quality of our ML model with competitors’ models. In this article, I would like to share the possible ways to encrypt CoreML models.

my face when i found the unencrypted model
my face when i found the unencrypted model

In 2020, Apple introduced a convenient way to deploy and encrypt CoreML models using the Apple Cloud. This is a fairly powerful tool that gives us the following features:

  • Model collections. The ability to combine models into collections and ensure their consistent updates. Convenient for the case when several models are used for one feature.

Apple Encryption

Let’s take a closer look at the last point. Let’s look at the steps for encrypting the ML model that we will ship with the application bundle.

  1. First we need to generate a key for our model and store it on disk. For in the Project Navigator, select our model. Open the Utilities tab and click Create Encryption Key. In the window that appears, you need to select exactly the command under which we will release the application. Click Continue. The key will be generated and stored on disk.

  1. Next, we need to tell Xcode that we want to encrypt the model with our key during the build of our application when compiling the model. To do this, select the target of our application, go to Build Phases -> Compile Sources and add for our model to the Compiler Flags: --encrypt $KeyPathOnDisk.

  1. Ready. The model is encrypted. Now it remains to refer to it in the code in such a way that we can decrypt it. For this, instead of init method to create MLModel need to use asynchronous method load, which was introduced in iOS 14. The key that we used for encryption is stored in the Apple Cloud at the time of creation. At the time of the first call to load it is downloaded and saved locally on the device. Therefore, it is very important that at the time of the first call there is access to the network. When called load the model is decrypted and loaded into memory. The encrypted ML model still remains on the disk.

MLModel.load(contentsOf: modelURL) { result in   
  switch result {   
  case .success(let loadedModel):       
    print("Successfully loaded model \(loadedModel).")       

    // Use the loaded model for predictions.       
    // ...   
  
  case .failure(let error):       
    print("Error loading model: (error).")   
  }
}

In case we plan to use the Apple Cloud to deliver the model, we need to follow the same steps, except for step 2. We don’t need to encrypt the model during its compilation, but we do when creating the archive. To do this, in the archive creation dialog, we need to select Encrypt Model and specify the path to our key

Custom Encryption

For most cases, Apple’s solution works great, but there are exceptions when you have to think about a custom solution. The main reason for this is the custom deployment of ML models, when we need to supply ML models from our servers. Several possible reasons for this:

  1. The need for finer tuning of model targeting

  2. The company has a centralized process for storing and updating application resources, as well as a requirement to follow it.

  3. A/B testing of models.

  4. Company internal security policies that do not allow content of intellectual value to be stored on Apple servers.

  5. Support for iOS 13 and below.

Technically, you can go the way when we encrypt the model in order to bundle it, but in fact not band it, but get the encrypted, compiled model and upload it to our servers. However, with this solution, in addition to the inability to automate the process of deploying the ML model, the risk of error increases significantly, due to the fact that we will store the key in the Apple Cloud, and the model itself on our servers.

Let’s look at a possible solution if we are faced with the task of custom encryption.

  1. Since the model is a folder, so the first step is to zip it and get 1 file. To do this, you can use zip, tar or any other archiver.

  2. Next, we need to encrypt our file. To do this, you can use the popular sha256 or any other algorithm.

  3. The key and the resulting encrypted file are uploaded to our backend.

  4. Next, we need to prepare a request for the backend, with which we can get the key and a link to the encrypted model.

  5. While the application is running, at the right time, we send a request, download and cache the encrypted model on disk.

  6. At the time of the first call to the model for the application session, we decrypt it using the received key, unzip it and save it to a temporary folder, for example: NSTemporaryDirectory()/YourFolder/

  7. We initialize the model and load it into memory using init method MLModel

  8. Delete temporary folder.

Of course, this is not 100% protection, and a small part of the time during the operation of the application we have an unencrypted model on the disk. But it’s still much better than not encrypting the model at all, and makes life harder for those who want to use your model.

Total

We have considered two approaches to encrypting CoreML models. Which method to choose and whether it is worth spending time on encryption, as usual, everyone decides for himself based on the tasks. All good.

Links

Screenshots taken from Apple presentations

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *