[RFC] mtd: ubi: UBI Encryption

Andrew Murray amurray at embedded-bits.co.uk
Mon Aug 10 12:56:50 PDT 2015


We've recently implemented support for encryption within UBI for one of our
customers and now wish to use this experience to provide a suitable solution
for the community.

Our current implementation works on real hardware and the latest linux-mtd
kernel - however there are many issues that in my opinion make it unsuitable
for the wider community. I'm keen to address these issues with feedback from
linux-mtd such that we can get this in good shape. I'm happy to share the
current implementation if it helps form the basis of a discussion that will
address the general issues of adding encryption to UBI. (The diffstat for the
current implementation is about 407 insertions).

In summary:

 - The approach I've taken is to intercept data between UBI and MTD (e.g.
   mtd_read, mtd_write etc) and encrypt/decrypt it with the kernel crypto
   framework (e.g. crypto_*). This is good because it de-couples encryption
   from the rest of UBI, reduces/isolates complexity and ensures that everything
   is indiscriminately encrypted. Though there may be a more obvious place to do
   this.

 - This approach is also bad because it breaks an assumption that UBI and UBIFS
   make (as well as any other UBI users) that data returned from the MTD layer
   containing 'all bits set' is erased flash. The same is also true for writing
   data - for example when filling space with 0xFFs. Where we intercept and
   encrypt/decrypt the 'all bits set' data we break the assumption because
   we've turned it to garbage.

 - My work around for this erased flash issue was to conditionally
   encrypt/decrypt only when the input data is not 'all bits set'. This had
   minimal impact on UBI/UBIFS/etc but it is possible (though very unlikely)
   that the output of an encryption algorithm is 'all bits set' - Thus when you
   later attempt to decrypt the 'all bits set' cipher text we incorrectly treat
   it as erased flash so return it verbatim and thus cause corruption. I've not
   seen this issue occur despite reading and writing more than 50GB of data.

 - A better solution may be to correctly fix up the callers to the
   'interception' layer such that they can choose to read raw or with
   encryption. An example of where this would be needed is in 'torture_peb' -
   after an erase the fuction reads back the flash to see if its 'all
bits set'. This
   seems like the right approach to me.

 - I have implemented the 'better solution' and it appears to work - however
   modifications are then needed to UBIFS in order for that to work. For example
   when mounting UBIFS on empty flash it will scan and fail to find
   UBIFS_NODE_MAGIC headers (as expected) - it will then determine that the
   start scan wasn't empty space (as the 0xFFs have been decrypted into garbage)
   and return an error. I believe this is the only issue I found with UBIFS.
   (Of course another way to solve this would be to encrypt empty space - but
   this would increase wear as the empty space (decrypted to 0xFFs) wouldn't
   actually be erased flash thus requiring an additional erase prior to writing
   data.).

 - The current implementation  encrypts with cbc(aes) across fixed sized
   units of hdrs_min_io_size - it also uses an IV based on the physcial offset
   of the block and user provided IV. The key/IV is read from a fixed location
   in flash. I'm not sure of the best way to manage/locate keys - this is
   clearly a hack.

 - Encryption in UBI was preferred as it removed the complexity from userspace,
   though I suppose there is no reason why this can't be done within the MTD
   layer rather than in UBI and thus benefit all MTD users.

I'm keen to hear any feedback regarding the approaches I've mentioned and to
hear if anyone else working in this area. I'm also keen to hear if
this is wanted
or if this is a bad idea. I accept this isn't trivial undertaking.

Thanks,

Andrew Murray



More information about the linux-mtd mailing list