Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use implicit IV for encryption #1487

Merged
merged 2 commits into from
Jul 8, 2020

Conversation

pan-apple
Copy link
Contributor

Problem

The encryption IV can be derived from other fields in message header. It'll save 8 bytes per message.

Summary of Changes

Use Message ID (monotonically increasing number per peer connection), and Source Node ID to derive the IV.

@gerickson
Copy link
Contributor

@emargolis, @dougsteed, @roydsouza

Copy link
Contributor

@andy31415 andy31415 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the baseline intent (in WML) for node id to be optional was:

  • connection-oriented connections (e.g. TCP or BLE) the node ID only needs to be sent once
  • can be implied and never sent if addressing scheme can deduce node id from ipv6 address

This does not invalidate this approach, however I am wondering: why do we include the node id at all? Do we expect the same encryption key to be shared among devices? or is this for any cases where a shared key is used (some multicast messages)?

Copy link
Contributor

@andy31415 andy31415 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding approval bit. Would like to understand at some point why we decided to also use an optional field for IV computation.

if (header.GetSourceNodeId().HasValue())
{
uint64_t nodeID = header.GetSourceNodeId().Value();
IV |= nodeID & 0xffffffff00000000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XOR may be better from a security perspecitve than OR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discussed it with @balducci-apple offline before pushing this PR. We didn't see a benefit of XOR over OR in this scenario.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my concrete attack proposal:

I sniff node ID, say it is 1 for simplicity

Then IV(MessgeeID 1, NodeId 1) is identical with IV(messageid 0x100000001, NodeID1)

So if I sniff a 'door unlock payload' with any message id for node one, I know that sending an identical payload with message id increased by 0x100000001 will get accepted and decrypted.

OR makes me reuse IVs which is bad.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case MessageID is a 32 bit value so 0x100000001 is invalid. As MessageID reaches 0xffffffff we'll need to perform a rekey operation (in practice we'll have rekeyed before this point). Once we rekey we can safely set MessageID to 0. In this case the top 4 bytes of the IV are exactly some transform of the source ID and the bottom 4 bytes are exactly the message ID.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporation of sourceNodeId in the IV value is symbolic and is not really required. We could simplify it to: IV = { 32'b0, messageId }.
But if we incorporate sourceNodeId then XOR operation would be more appropriate to use. OR operation will transform 32 most significant bits of IV to be mostly ones.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on using XOR over OR in the calculation.

Copy link
Contributor

@andy31415 andy31415 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking as changes requested: usage of OR and an unfortunate node ID weakens message id usage (although only for very large numbers).

Specific examples (made up large to force errors):

NodeId 0xFF

makes messageId 0x0000000100000000
be identical to messageid 0x0000000200000000 (or 0 for that matter).

We should not wrap 32 bit that frequently, but this should be XOR or not used at all. Even with XOR if keys are reused I worry that one node id inverts the id of another ... so why bother. Do we have anyone to consult about cryptography (not my domain)

@pan-apple
Copy link
Contributor Author

Marking as changes requested: usage of OR and an unfortunate node ID weakens message id usage (although only for very large numbers).

Specific examples (made up large to force errors):

NodeId 0xFF

makes messageId 0x0000000100000000
be identical to messageid 0x0000000200000000 (or 0 for that matter).

We should not wrap 32 bit that frequently, but this should be XOR or not used at all. Even with XOR if keys are reused I worry that one node id inverts the id of another ... so why bother. Do we have anyone to consult about cryptography (not my domain)

Won't it make the IV 0x000000FF00000000?

@dougsteed
Copy link

It is of course extremely important that the same IV not ever be repeated for a different message with the same key. Provided this can be guaranteed through the combination of message id/node id this will be fine. Need to be careful if there is any scenario where the message id space could somehow be reset with the same key being used.

@andy31415
Copy link
Contributor

Apparently my main misunderstanding was that messageid is 32-bit. This was not obvious from uint64_t iv = GetMessageId() which seemed like message id would be 64 bit,starting my whole dillema.

Discussed with @pan-apple to try to make it clearer (assert/comment/xor/anything that makes me read the code and claim it is obviously correct).

@pan-apple
Copy link
Contributor Author

It is of course extremely important that the same IV not ever be repeated for a different message with the same key. Provided this can be guaranteed through the combination of message id/node id this will be fine. Need to be careful if there is any scenario where the message id space could somehow be reset with the same key being used.

@dougsteed , I agree. @andy31415 and I talked offline, and main confusion was due to size of message ID. Currently it is 4 bytes, but uint64_t IV = header.GetMessageId(); made it look like it is 8 bytes long. I'll add a comment and update the code to make sure we are using 4 bytes of message ID here (by & it with 0xffffffff)

if (header.GetSourceNodeId().HasValue())
{
uint64_t nodeID = header.GetSourceNodeId().Value();
IV |= nodeID & 0xffffffff00000000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case MessageID is a 32 bit value so 0x100000001 is invalid. As MessageID reaches 0xffffffff we'll need to perform a rekey operation (in practice we'll have rekeyed before this point). Once we rekey we can safely set MessageID to 0. In this case the top 4 bytes of the IV are exactly some transform of the source ID and the bottom 4 bytes are exactly the message ID.

@CLAassistant
Copy link

CLAassistant commented Jul 7, 2020

CLA assistant check
All committers have signed the CLA.

@pan-apple pan-apple requested a review from andy31415 July 7, 2020 20:53
@BroderickCarlin BroderickCarlin merged commit a310bc4 into project-chip:master Jul 8, 2020
@pan-apple pan-apple deleted the implicit-IV branch July 8, 2020 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants