Digital Rights Management (DRM) with CBFS Storage
CBFS Storage, having convenient file management features and built-in encryption, is often used for Digital Rights Management (DRM). In other words, developers use CBFS Storage to secure information and to prevent unauthorized access to this information. "Unauthorized" can mean access by third parties, but also by users themselves. It is a common requirement to allow users access to data via an application interface, but prevent them from exporting the data to external media (whether electronic, paper, etc.).
The problem with such a scenario is that a reliable DRM is hardly an achievable goal. To implement a solution, you need to employ more than just a library such as CBFS Storage.
To get access to the protected data, one would need to have the key and the keyhole. In other words, knowing the key won't help if you don't know where and how to use it. Brute force attacks on the encrypted data (when you have it) can be very time consuming. With CBFS Storage, the keyhole is available by default. The key (password) will protect your data from typical users, but not from an experienced hacker.
Protecting Information from Copying
The first level of security is the obfuscation of the file format. If an experienced hacker finds the CBFS Storage vault file, they'll easily discover that it was created using CBFS Storage. The hacker can then use the CBFS Storage Explorer and attempt to open the vault. To avoid this, you can apply some permutations on the vault's pages. When CBFS Storage is used in callback mode, it fires events handled by your application to read and write the vault's pages to and from the vault. You can read and write the pages as is, but you can also change them. Changes can be as simple as XORing the bytes with some constant known only to your application, and/or you can also employ an encryption algorithm. Callback mode is described in this article.
The next step is to protect the key. To use the built-in encryption features of CBFS Storage, you provide one or more passwords (passphrases), which CBFS Storage uses to encrypt files (when you encrypt files one by one), the whole vault (when the whole-vault encryption is used), or both. This is an attack vector for experienced hackers. No matter how you or CBFS Storage secure the password, there's one place where this password is passed in clear text: the route by which the password is transferred from your code to CBFS Storage code. Is it possible to transfer the password without using clear text? Of course. But, again, there will be some places where it will appear in clear text—either in your application or in the library.
The encryption and hashing callbacks of CBFS Storage enable you to use custom encryption to protect the key. The following section describes two encryption approaches. The first approach relies on code obfuscation. The second approach provides almost 100% protection, but requires hardware support. The differences between the approaches are discussed below.
Configuring Custom Encryption
Follow the steps below to configure CBFS Storage with a custom encryption scheme:
- Set the encryption mode for the vault and/or the files that you want to encrypt to one of Custom modes.
- Implement handlers for the DataEncrypt and DataDecrypt events. They will be used for the data encryption.
- Implement handlers for the KeyDerive and HashCalculate events (either one or both events should be handled depending on the custom encryption mode). These event handlers will be used for key derivation and hash calculation.
- Specify the encryption and the password.
For the first approach, the idea is that you construct the obfuscated encryption key and perform encryption and decryption in your code, and this code is obfuscated to hide the key and data permutations. The obfuscation of the executable code is done using special tools which are intentionally not mentioned here. The goal of obfuscating the code is to make it hard, if not impossible, for hackers to find out the password and the permutation algorithm.
The second approach requires that you use cryptographic hardware (USB crypto tokens, smart cards, etc.) to store the symmetric key used for the encryption/decryption of the vault data. Such cryptographic hardware will both store the secret key and perform the cryptographic operations (encryption/decryption) with this key; the secret key does not (or more accurately, cannot) physically leave the hardware, so the hacker won't be able to obtain the it. You can re-encrypt the data using another key if needed. Most hardware lets you generate a symmetric key and store it within the device.
The second approach has several notable advantages and disadvantages:
- You get a very high level of protection for your data.
- You get an additional tool for license control of your data or software. It's not possible to install and use unauthorized copies of your software or export the data to use it on other systems.
- Some cryptographic hardware can be quite slow when performing encryption/decryption operations. Consequently, the speed of vault operations will be affected.
- Cryptographic hardware costs money, and it has to be physically shipped to your clients.
Controlling User Access
Once you've ensured that your data is adequately protected (i.e., can't be easily extracted and copied to external media), you can start developing a solution for user rights control and enforcement. This section discusses several ways to enforce access control for your data in multi-user (or multi-device) scenarios.
When you ship some data, it may be in your best interest to make it available to a select list of users (or devices), while simultaneously preventing others from using your application and/or accessing the data. This can be accomplished using PKI ("Public Key Infrastructure"), a set of standards and protocols that utilize asymmetric cryptography (also known as public key cryptography) to sign and encrypt data in order to prove its authenticity and secure it from unauthorized access.
In our theoretical scenario, several layers of encryption are present: there's the key used to encrypt the CBFS Storage vault's data (which we'll call the Vault Key), a key used to secure access to the Vault Key (we'll call this the RKey), and finally the individual users' public keys used used to encrypt the RKey. As discussed above, the Vault Key itself can either be hidden in your code or data, or kept in cryptographic hardware. The manner in which the RKey is used to secure it differs depending on which approach is used.
If you're hiding your Vault Key in your code or data, you need to encrypt it using some random key (hence the "R" in RKey) known only to you. Rather than distributing this RKey to your authorized users/devices directly, you encrypt it using the public key of each user/device, and then distribute that encrypted RKey. The encrypted RKey can then be decrypted by your application so long as the correct private key (i.e., the one paired with the public key used to encrypt the RKey) is present, and then the decrypted RKey can be used to decrypt the Vault Key, and so on. This scheme therefore ensures that only authorized users/devices can access the CBFS Storage vault's data. Keep in mind that the RKey decryption and Vault Key decryption procedures must still be obfuscated.
If you are using cryptographic hardware, the strategy is slightly different. A smart card or USB token can be stolen, and while such hardware is usually protected using a PIN (password), an experience hacker will likely be able to determine that PIN via other means. So, we will need to remove the human from the equation by assigning a unique, cryptographically strong PIN to each USB token or smart card that you distribute (which contains the Vault Key). In this scenario, the PIN itself serves as the RKey, so it should not be distributed directly. Instead, it should be encrypted using the public key of an authorized user/device, and then the encrypted PIN should be distributed. The rest of the flow works the same was as described above, except that the decrypted RKey (that is, the PIN) will be used to access the cryptographic hardware using the PKCS#11 interface, which lets you provide the PIN programmatically to decrypt the data. This strategy means that the attacker would need to steal both the cryptographic hardware and the private key of the corresponding user/device in order to access the data stored in the CBFS Storage vault. Since the user/device doesn't know the actual PIN for the hardware, they can't use the hardware to store their private key, reducing the risk that the private key and hardware are stolen together.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at firstname.lastname@example.org.