travis-ci/travis-core — pull request #162 by drogus (2013-01-03 03:03:40+00:00)
Title: DB encryption (WIP)

This is first step towards data encryption in database.

More info from commit message:

```
AR allows to serlialize and deserialize any attribute with usage of any
arbitrary 'coder', which can be any object that responds to :load and
:dump. This commit introduces Travis::Model::EncryptedColumn, which
allows to pass an instance to serialize method and enable encryption for
given column.

Its usage is simple:

class MyModel < ActiveRecord::Base
serialize :secret_column, EncryptedColumn.new
end

The implementation allows us to migrate the database without worrying
about the time of migration. EncryptedColumn by default uses the 8 byte
prefix '--ENCR--' which is added to any encrypted string. This allows
us to distinguish between encrypted and decrypted data and as a
consequence we can handle both encrypted and unencrypted data.

When prefix is disabled, EncryptedColumn will not add the prefix after
encryption, but it will check for it while decrypting. Thanks to that,
we can disable the prefix after all the data is migrated and any new
data will be saved without prefix.

The encryption itself uses AES256 with CFB cipher, which works best with
randomized IV. IV should be regenerated for every encrypted value and
it should be fine to attach IV to the encrypted value before putting it
into DB.
```

Further steps would be to specify which columns should be encrypted and deploying it, which should go as follows:

1. We need to make sure that the code is deployed to every app that uses models - otherwise some apps may not be able to handle encrypted data
2. After that we can turn on the feature flip for using prefix and data encryption.
3. New data saved in encrypted columns should be now automatically encrypted
4. We can encrypt the old values incrementally
5. When we're sure that old data is migrated we can disable feature flip for using prefix and optionally remove prefix from encrypted columns (which is needed only if we don't want to waste 8 bytes for each encrypted value).

The other way to implement check if data is already encrypted is to save that info in additional columns, but I didn't want to do that mainly because of 2 reasons:

1. Serialize would not allow access to the model, which would make implementation more difficult
2. I didn't want to add migrations

Also, I would be really glad if someone that feels strong in cryptography confirms this approach is correct (especially the cipher that I chose and the fact that we will store IV in the column itself, from what I learned it should be fine, but I'm not security expert).