Version 3, last updated by Ján Raška at 19 Jan 19:18 UTC
Obscuring Sensitive Data
Disclaimer: The information below is not intended to be an exhaustive recommendation for securing your data. Instead it is merely supposed to illustrate how Lift can easily be used to obscure sensitive data in a DB such that it is non-trivial for an intruder to recreate the original data.
Due to security vulnerability, some encryption functions have been removed from Lift 2.3, so we’ll be using softwave-util library’s SecurityUtils object (available from scala-tools.org). As opposed to encryption functions from Lift 2.2, SecurityUtils uses random initialization vector (IV), thus removing that vulnerability.
An Example
Let’s say that you have a customer’s credit card number that you must store in your database. This is not recommended in the first place, but some use-cases require it.
The goal here is to (1) prevent an attacker from easily reconstructing the original credit card number, and also (2) make it non-obvious from the perspective of a database observer. By this, we mean that a simple “select ccNumber from CreditCards” will yield results that are useless to the average observer.
SecurityUtils will help us achieve that.
You can generate a separate blowfish key for each credit card:
import softwave.util.SecurityUtils
val key: Array[Byte] = SecurityUtils.makeBlowfishKey
// encrypt the card number
val (encCC: String, iv: String) = SecurityUtils.blowfishEncrypt(ccNumber, key)
val pairForDB: String = SecurityUtils.base64Encode(key)+";"+iv+";"+encCC
Note, that
SecurityUtils.blowfishEncrypt returns tuple (encrypted, iv). IV is generated by SecureRandom. We then store IV in plaintext (or send it to receiver, in case we are encrypting a communication). It’s safe to do so, because an attacker cannot determine what the encrypted IV looks like without knowing the key, so he actually has no way to know what has been XORed with the first block of plaintext.
To get the data out of the DB:
import softwave.util.SecurityUtils
import SecurityUtils._
dataFromDb.charSplit(';') match {
case key :: iv :: encCC :: _ => SecurityUtils.blowfishDecrypt(encCC, SecurityUtils.base64Decode(key), iv)
case _ => // yikes... it's not what I wanted
}
In order to decrypt a message, we use the key and the IV that have been used to encrypt a message.