Hello Genodians,
we are still working to add hardware-based encryption to CBE. To this end, we have implemented a custom trust anchor and crypto engine. Generating a key, encrypting this key on behalf of cbe_init and decrypting it again on behalf of the vfs_cbe plugin works fine.
But then the vfs_cbe requests to have a all zero key encrypted which due to the ICV added by hardware black key handling fails. We cannot seam to find out where the request originates or why vfs_cbe would ever encrypt any key, let alone a key of all zeros.
Any pointer or idea would by very welcome.
Kind regards Stefan
Ideas inline.
Gesendet: Dienstag, 23. November 2021 um 11:21 Uhr Von: "Stefan Thöni" stefan.thoeni@gapfruit.com An: "users" users@lists.genode.org Betreff: CBE key encryption
Hello Genodians,
we are still working to add hardware-based encryption to CBE. To this end, we have implemented a custom trust anchor and crypto engine. Generating a key, encrypting this key on behalf of cbe_init and decrypting it again on behalf of the vfs_cbe plugin works fine.
But then the vfs_cbe requests to have a all zero key encrypted which due to the ICV added by hardware black key handling fails. We cannot seam to
Why is an all zero key invalid? In my understanding of crypto such a key should be possible as well or the implementation is insecure.
find out where the request originates or why vfs_cbe would ever encrypt any key, let alone a key of all zeros.
Any pointer or idea would by very welcome.
You can compile vfs_cbe with profiling enabled and write a custom profile function, which uses /dev/log to mark entry and exit of functions. And in the encryption you check for an all zero key and log this event to /dev/log too. Then you can trace all calls in the log which led up to this event.
I hope you can make such a implementation (of logging profile and event marks) available as library because such debugging aid will be needed more universally.
Kind regards Stefan _______________________________________________ Genode users mailing list users@lists.genode.org https://lists.genode.org/listinfo/users
Hello Stefan,
But then the vfs_cbe requests to have a all zero key encrypted which due to the ICV added by hardware black key handling fails. We cannot seam to find out where the request originates or why vfs_cbe would ever encrypt any key, let alone a key of all zeros.
Whenever the CBE writes the current superblock back to the block device it first has to encrypt the current and the previous(!) key as both are stored within the superblock on the block-device. This is necessary because you may stop the CBE during rekeying and it needs the previous key to complete the operation as there are still blocks encypted with the old key around.
So I assume in your case the previous key was not yet used and therefor is initialized to a default value that, as it happens, is all zeros and the CBE wants to write the superblock back (it does so on every 'sync' request), which is why you encounter this unexpected request.
Regards Josef
Hi Stefan,
Sorry for the delayed response.
First of all I hope you don't mind me asking whether you use the newest state of the CBE (Genode version 21.11 is safe)? It might be important because during the recent development of the File Vault, there were several major improvements regarding the key management with CBE/TA.
Also, I'd like to be sure that we're not talking about different keys. There are normally two keys in use with the CBE, the "master" or "private" key that is stored (encrypted via a user passphrase) in the Trust Anchor and the block encryption key that is stored (encrypted via the master key) in the CBE superblock and that the CBE driver (vfs_cbe) decrypts in order to use it for accessing the block device. The master key is currently set only during initialization of the Trust Anchor while the block encryption key is set during the initialization of the CBE but can be changed later.
Let me provide some further background although you might already be aware of all this. On CBE driver startup, the driver reads out the encrypted block encryption key from the most recent superblock on the block device. It then asks the Trust Anchor to decrypt it using the master key. The Trust Anchor returns the plaintext block encryption key to the driver which is then able to decrypt the data blocks of the CBE.
In the course of certain user requests, the driver writes back updated Superblocks to the block device. When doing so it asks the Trust Anchor to encrypt the block encryption key again (the key might have changed in the meantime). At this point may reside a flaw in the driver implementation that we didn't notice so far because our software TA surely is not as strict as your hardware: A superblock has slots for storing not only one but two block encryption keys. The second slot is used as "buffer" for an old key while transitioning from one block encryption key to another. Therefore the second slot is only valid while changing the block encryption key.
Now, when writing back the superblock, the driver seems not to care and always encrypts both slots even if the second one is not in use. I'll prepare a fix but I don't have much time currently and so I don't know when it'll be ready. If you want to do it yourself, lookout for
! Job.State := Encrypt_Previous_Key_Pending;
in genode/contrib/cbe-*/cbe/src/lib/cbe/cbe-superblock_control.adb . This state is entered unconditionally but it should be entered only if 'SB.State /= Rekeying'. Otherwise it should be skipped in favor of the state that is set in the next
! when Encrypt_Previous_Key_Completed =>
block.
I hope this helped? Please don't hesitate to ask me further questions but be aware that it may take me some time to answer.
Cheers Martin
On 23.11.21 11:21, Stefan Thöni wrote:
Hello Genodians,
we are still working to add hardware-based encryption to CBE. To this end, we have implemented a custom trust anchor and crypto engine. Generating a key, encrypting this key on behalf of cbe_init and decrypting it again on behalf of the vfs_cbe plugin works fine.
But then the vfs_cbe requests to have a all zero key encrypted which due to the ICV added by hardware black key handling fails. We cannot seam to find out where the request originates or why vfs_cbe would ever encrypt any key, let alone a key of all zeros.
Any pointer or idea would by very welcome.
Kind regards Stefan
Genode users mailing list users@lists.genode.org https://lists.genode.org/listinfo/users
Hi Stefan,
I opened an issue that already contains a fix:
https://github.com/genodelabs/genode/issues/4355
However, the fix is tested yet against 'run/cbe_tester' only. The problems with the other tests seem to be not related to this fix. Therefore, I'd say you could give it a try. I would be interested in your findings ;)
Cheers, Martin
On 30.11.21 22:59, Martin Stein wrote:
Hi Stefan,
Sorry for the delayed response.
First of all I hope you don't mind me asking whether you use the newest state of the CBE (Genode version 21.11 is safe)? It might be important because during the recent development of the File Vault, there were several major improvements regarding the key management with CBE/TA.
Also, I'd like to be sure that we're not talking about different keys. There are normally two keys in use with the CBE, the "master" or "private" key that is stored (encrypted via a user passphrase) in the Trust Anchor and the block encryption key that is stored (encrypted via the master key) in the CBE superblock and that the CBE driver (vfs_cbe) decrypts in order to use it for accessing the block device. The master key is currently set only during initialization of the Trust Anchor while the block encryption key is set during the initialization of the CBE but can be changed later.
Let me provide some further background although you might already be aware of all this. On CBE driver startup, the driver reads out the encrypted block encryption key from the most recent superblock on the block device. It then asks the Trust Anchor to decrypt it using the master key. The Trust Anchor returns the plaintext block encryption key to the driver which is then able to decrypt the data blocks of the CBE.
In the course of certain user requests, the driver writes back updated Superblocks to the block device. When doing so it asks the Trust Anchor to encrypt the block encryption key again (the key might have changed in the meantime). At this point may reside a flaw in the driver implementation that we didn't notice so far because our software TA surely is not as strict as your hardware: A superblock has slots for storing not only one but two block encryption keys. The second slot is used as "buffer" for an old key while transitioning from one block encryption key to another. Therefore the second slot is only valid while changing the block encryption key.
Now, when writing back the superblock, the driver seems not to care and always encrypts both slots even if the second one is not in use. I'll prepare a fix but I don't have much time currently and so I don't know when it'll be ready. If you want to do it yourself, lookout for
! Job.State := Encrypt_Previous_Key_Pending;
in genode/contrib/cbe-*/cbe/src/lib/cbe/cbe-superblock_control.adb . This state is entered unconditionally but it should be entered only if 'SB.State /= Rekeying'. Otherwise it should be skipped in favor of the state that is set in the next
! when Encrypt_Previous_Key_Completed =>
block.
I hope this helped? Please don't hesitate to ask me further questions but be aware that it may take me some time to answer.
Cheers Martin