Split-key encryption- Securing the data at rest
When working with PII data (sensitive information that can directly identify a user), one needs to ensure that PII data is not stored as plain text in the database. The database can either be in the cloud or on-prem.
There are many ways to secure it either by Hashing or Encrypting.
Hashing comes with a downside that if we Hash the data we will not be able to un-hash it, therefore we won't be able to reuse the data if required to be used further as a part of the functionality, after retrieving the data from DB. Therefore encryption becomes the choice for such scenarios.
There are various basic techniques (Asymmetric or Symmetric encryption) with which we can encrypt the data using a key and store the data in the encrypted form in the database.
Asymmetric encryption → uses a pair of related keys — one public key and one private key to encrypt and decrypt the data.
Symmetric encryption → type of encryption where only one key (a secret key) is used to both encrypt and decrypt electronic data
However, the data is only secure till the time we have our key secured. :-)
Now the question arises how to secure these keys?
With symmetric encryption one of the ways to secure the key is → Split key encryption → As the name says splitting the keys and storing the keys at two different places, while if a hacker gets access to one of the keys, it won't be enough to decrypt the data, we need another key to be present, and combining both will form the complete secretKey that will be used to encrypt/decrypt the data.
I will show some snippets below to split the keys into two (can be multiple as well) components, and then we can easily store these components in different places.
For example, we can generate the Component1 using the random UUID string and store it at a Cloud location (Secret Manager or Cloud Vault) and generate another component2 using Component1 and Key and store it at an on-prem location (Vault or database). While only component1 will not be enough to use a key we need to have component2 as well to generate the key out of it.
Steps to generate two components:
- Start with the secretKey.
- Create a random string of the same length (component1).
- XOR both Component1 and Key1 and the result will be key component2.
- To generate the secretKey from component1 and component2, simply XOR component1 and component2.
Below is the sample snippet (off-course may not be a tuned one :-P ), but just gives a gist of it.
Now we can use the above function to get the secretKey from the two components. I am generating component1 using a simple generate using UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8) for component1 (which will be explained shortly).
The above was a simple key hardcoded as a String. However, we can generate one using the AES algorithm as well, which is shown below.
We can pass the cipher as AES and keySize as 128 (which is by default).
We can introduce a JCE patch for the JRE, to enable the use of crypto.policy=unlimited.
In the above, sample aesKeyBase64 can be split into two components and stored at two different locations (as mentioned at starting)
Pass the generated secret key and the Data to be encrypted to the below encrypt function.
With this, we only need to store the two components, rather than storing the single key at either place.
Thank you for staying with me, this was just a conceptual part which is one of many other ways that can also be explored further. Like using Asymmetric encryption and decryption, which also uses two sets of keys by default.