reversebias / mitosis

Firmware for nordic MCUs used in the Mitosis Keyboard
GNU General Public License v3.0
195 stars 125 forks source link

Transport Encryption for Mitosis #18

Open rossica opened 4 years ago

rossica commented 4 years ago

Abstract

These changes implement transport encryption between the keyboard halves and the receiver. Hard-coded encryption keys are used to protect randomly-generated keys which are used to encrypt the bulk of transfers. Periodically, new randomly-generated keys are created and used. Hardware features of the NRF51 SoC are utilized where possible to reduce impact to battery life as much as possible.

Encryption Implementation

Authenticated encryption with associated data (AEAD) is used to secure data sent between the keyboard halves and the receiver, using AES in Counter mode (AES-CTR) for confidentiality, and Cipher-based Message Authentication Code (AES-CMAC) for authenticity. It is implemented as Encrypt-then-MAC. AES was selected due to the presence of a hardware AES engine in the NRF51 SoC. CMAC was similarly selected over HMAC to take advantage of the hardware AES engine, and due to reduced memory footprint.

Key Generation

A single master seed value is used as input to Cipher-based Key Derivation Function (CKDF), along with per-device salt values, which generates the AES-128 key for AES-CTR encryption/decryption, the nonce value for AES-CTR, and the key for CMAC. The keys generated from the master seed are used to establish a root-of-trust for data sent to the keyboard halves from the receiver, and are used as the initial transport keys for data sent from the keyboard halves to the receiver, until session keys are ready. CKDF was selected over HKDF to take advantage of the hardware AES engine.

Over-the-Air Data Format

Data messages from the keyboard halves to the receiver use the following format:

|                     1                   2                   3
| 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|-----------------------------------------------------------------|
|               encrypted payload                |     key ID     | 
|-----------------------------------------------------------------|
|                           counter value                         |
|-----------------------------------------------------------------|
|                    message authentication code                  |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|_________________________________________________________________|

The encrypted payload is the key matrix bitmap that has been encrypted using the keyboard's encryption key, and the counter value. The key ID is used to distinguish which decryption key to use for a given keyboard half. The key ID is incremented for each rekeying the occurs. Key IDs are not unique between keyboard halves, and may be in use by both keyboard halves at the same time. Key IDs may also be reused by the same keyboard half, provided it is not the same as the current key ID. The message authentication code is calculated over the encrypted payload, key ID, and counter value.

Rekeying messages from the receiver to a keyboard half use the following format:

|                     1                   2                   3
| 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|-----------------------------------------------------------------|
|                         encrypted key seed                      |
|-----------------------------------------------------------------|
|                    encrypted key seed (contd.)                  |
|-----------------------------------------------------------------|
|                    encrypted key seed (contd.)                  |
|-----------------------------------------------------------------|
|          encrypted key seed (contd.)           |   new key ID   | 
|-----------------------------------------------------------------|
|                    message authentication code                  |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|-----------------------------------------------------------------|
|               message authentication code (contd.)              |
|_________________________________________________________________|

The encrypted seed is 15 randomly-generated bytes that have been encrypted using the receiver's root-of-trust key. The message authentication code is calculated over the encrypted seed and key ID.

Rekeying Process

As soon as the receiver powers on, the hardware random number generator (RNG) is enabled and begins generating seed values to be used to derive the transport session key, nonce, and CMAC key for each keyboard half. When the receiver receives a message from a keyboard half that is using the initial root-of-trust keys, the receiver responds with a randomly generated seed, encrypted using the receiver's root-of-trust key, and monotonically-incremented key ID. The encryption of the seed uses the new key ID as the counter value. The receiver must guarantee the key ID is not the same as the current key ID and is not zero (0). Key ID 0 is reserved for the initial key, and can never be used to identify any other encryption key. The receiver will also respond with a new encrypted seed after the keyboard half's counter value exceeds a chosen threshold. Upon receiving the encrypted seed, the keyboard half verifies the MAC, then decrypts the seed and generates a new nonce, encryption key, and CMAC key using CKDF with the same salt values as in the initial key generation. All subsequent messages sent by the keyboard half will use the new key and key ID to distinguish them from the previous encryption key.

Testing

All cryptographic algorithms were tested and verified with officially-published test vectors, where available, and executed on an AMD64 system. It is assumed the hardware AES engine in NRF51 is correct, and it was not tested itself. The tests can be found in the mitosis-crypto/test directory. End to end testing was manually performed with Mitosis keyboard hardware using the precompiled-crypto-* firmware in the precompiled directory. Testing covered: typical start up; resetting the receiver and not the keyboard halves; resetting the keyboard halves and not the receiver; and rekeying of a keyboard half once its counter exceeded a threshold. In all cases, the keyboard continued operation with no apparent loss of key presses or delay.

Other Changes

During development, it was discovered that the main loop on the receiver was very sensitive to timing disruptions and would de-sync with the UART, causing the SoC to reset. This was particularly frequent when generating the random seed values, and computing the new encryption keys for rekeying. Decryption of messages didn't seem to affect it, however. In order to solve this problem, the UART code was changed from a polling-based approach to a callback-based approach. The UART callback executes at the highest priority, so it supercedes any cryptographic work going on in the main loop, and can interrupt the Gazell callbacks. This removes most of the timing sensitivity from the UART code, because it always takes priority. Responsiveness is unaffected, and it simplifies the UART code.

Miscellaneous Future Improvements

Various thoughts and features I would like to have, but aren't necessary and I don't have time for:

Addresses #12

jcharnetsky commented 4 years ago

Are there plans to merge this pull request? My main concern about using the mitosis firmware is its lack of encryption.

rossica commented 4 years ago

@jcharnetsky I'd be happy to have it merged, but I haven't seen any interest here. It looks like this project is dead.

LucidityCrash commented 4 years ago

@rossica do you mind if we adapt your code for the Redox ?

rossica commented 4 years ago

@LucidityCrash Feel free to, with the caveat that I don't know about the Redox project, and I make no guarantees about the fitness of this code for that purpose, nor any guarantees about the security of the adapted code. I recommend you have a cryptography expert review your adapted code. Although I didn't include any copyright notices, I consider my contribution here to be the same license as mitosis uses.

rudism commented 2 years ago

@rossica thank you for all your work on this! Took care of the one nagging concern I had about my Mitosis.