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

Change Packet Number Gap to Packet Number Offset #1307

Closed
wants to merge 1 commit into from
Closed

Change Packet Number Gap to Packet Number Offset #1307

wants to merge 1 commit into from

Conversation

nibanks
Copy link
Member

@nibanks nibanks commented Apr 19, 2018

This is a proposed solution to the privacy/linkability problem by slightly modifying the existing packet number gap solution to make it a per connection ID packet number offset. The offset is used to transform the wire encoding of the packet number, but the connection still uses the same monotonically increasing packet number space (no gaps).

This solution requires very little per packet CPU overhead, compared to PNE.

Unlike the PNE proposal (#1079), this doesn't fix the ossification/greasing problem as well. Instead, I'd like to treat that as a separate problem (and a separate PR) and attempt to solve that with a non-cryptographic solution (shuffle for instance).

Closes:


Packets with with new connection IDs have special rules for encoding the packet
number in the headers. They use an offset (see {{packet-number-offset}}) to
transform the packet number via the following:
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this only apply to new connection IDs? Wouldn't it be easier to apply this transformation to every packet number?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was just following the existing model that gaps used. I don't have a strong opinion either way.

Copy link
Contributor

Choose a reason for hiding this comment

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

The gap in the actual packet number was introduced at the point you sent the first packet with a new CID. This proposal is a transformation of the actual packet number for wire presentation, so it needs to occur every time.

Copy link
Contributor

@ad-l ad-l Apr 23, 2018

Choose a reason for hiding this comment

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

I think that's a clear mistake, the transformation should apply to all packet numbers on the network

@huitema
Copy link
Contributor

huitema commented Apr 20, 2018

I think that's a terrible idea. It perpetuates the fallacy that offsetting packet numbers provides privacy. We have established that it doesn't in an important case, when there is overlap between two connections. The matching pattern of holes and sequence number increment is more that sufficient to establish correlation in these cases.

We would be much better off just getting rid of the gaps altogether. They force complex synchronization between sender and receiver, effectively the same management cost as managing encryption keys, but they do not provide nearly as much benefit as encryption.

@nibanks
Copy link
Member Author

nibanks commented Apr 20, 2018

@huitema would adding the shuffle (or some other non-cryptographic greasing) alleviate your concerns here? Matching patterns between overlap would be more difficult then.

As for this design being a complex synchronization between sender and receiver, I disagree with you. Each side needs only generate the offset once, per connection ID and just store that offset. When sending, it's just an additional add and modulo operation. The receiver just needs to do an add and subtraction operation.

Obviously adding whatever greasing algorithm will add additional complexity, but the CPU cost per packet should still be quite low, and easily implemented in hardware.

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 20, 2018

@nibanks this looks a bit like my segmented packet numbers proposal but not that this proposal has a fixed offset per connection ID and that a connection ID is replaced before that offset is exhausted.

This avoids any linkage other than NAT rebinding.

#1105

You can further mutilate the clean packet number sequence with a reversible permutation

http://stackoverflow.com/a/12996028

   uint32_t x;

    x = ((uint32_t)(size_t)PN) ^ (uint32_t)(MY_SEED);

    x = ((x >> 16) ^ x) * 0x45d9f3bUL;
    x = ((x >> 16) ^ x) * 0x45d9f3bUL;
    x = ((x >> 16) ^ x);
    return x;

And you can further encrypt that permutation using simple XOR magic - apparently IPSec style.

@mikkelfj
Copy link
Contributor

Just using a random seed might be sufficient to deter the average middle box and with CID update there is no privacy leak.
The resulting PN can be used as AEAD IV since it is a permutation of a unique non-repeating sequence. After CID update the AEAD keys must change, but then it is about time anyway.

@mikkelfj
Copy link
Contributor

I suppose a more elaborate encryption would go like

uint32_t key[4];
hkdf(key, context);

uint32_t x;

    x = ((uint32_t)(size_t)PN) ^ key[0];
    x = ((x >> 16) ^ x) * UINT32_C(0x45d9f3b) ^ key[1];
    x = ((x >> 16) ^ x) * UINT32_C(0x45d9f3b) ^ key[2] ;
    x = ((x >> 16) ^ x) * UINT32_C(0x45d9f3b) ^ key[3];
    x = ((x >> 16) ^ x);
    return x;

Due to brute force the encryption is not strong, but combined with per path CID and update before 2^32 PN's it should be robust since the PN encryption is not privacy.

To speed things up, one or two multiplication rounds can be taken out.

See also
http://stackoverflow.com/a/12996028

@mikkelfj
Copy link
Contributor

The above cannot be used directly as IV because the permuation is no longer a 1 to 1 mapping but a key guided mapping, so the encrypted PN will not work as an IV. The same issue should not be the case with the initial seeded value.

@MikeBishop
Copy link
Contributor

After CID update the AEAD keys must change, but then it is about time anyway.

Given how frequently CID rotation might occur (path validation, quiescence, shifts in wind direction), I am dubious that it's wise to rotate 1-RTT keys every time a new CID is used, which I believe is what you're saying here. This also falls prey to the same problem as #1174 -- if you switched keys because you used a new CID to probe, what key do you use back on the original path while you wait for the probe to complete? Key rotation is supposed to be a ratchet forward, and you can't have two key rotations going on at once in the current design, so you also can't take the answer of doing a second rotation on the original path.

Copy link
Contributor

@MikeBishop MikeBishop left a comment

Choose a reason for hiding this comment

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

I think @marten-seemann is correct -- this solution only makes sense as a transform on every packet, not just as something to do on particular packets with a new CID. That's my key feedback on fixing the PR.

On the proposal itself, however, I share @huitema's concerns that correlation of gaps between flows is still possible. A future PR for a shuffle can make that harder for an observer, but only so much (observing over the shuffle window, you can perform the same analysis).


Packets with with new connection IDs have special rules for encoding the packet
number in the headers. They use an offset (see {{packet-number-offset}}) to
transform the packet number via the following:
Copy link
Contributor

Choose a reason for hiding this comment

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

The gap in the actual packet number was introduced at the point you sent the first packet with a new CID. This proposal is a transformation of the actual packet number for wire presentation, so it needs to occur every time.

transform the packet number via the following:

~~~
transformed_packet_number = (packet_number + offset) % 2^62
Copy link
Contributor

Choose a reason for hiding this comment

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

This might actually be okay, but the possibility that the transformed packet number might wrap around to zero before being truncated feels a little odd.

~~~

Once transformed, the normal rules of packet number encoding are followed, only
encoding the least number of bits required.
Copy link
Contributor

Choose a reason for hiding this comment

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

"only" and "the least" feels duplicative. Maybe just replace the part with the comma with a reference to the section where the truncation is defined?

Better yet, since this is effectively a transform on every packet number, put this in the section about truncation (it becomes a description of how the 64-bit number is encoded on the wire) and make this section purely about determining what the offset will be.

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 20, 2018

if you switched keys because you used a new CID to probe, what key do you use back on the original path while you wait for the probe to complete?

I forgot about my own proposal: No, rekeying is not needed for each new CID. The segmented packet number idea means that each CID is given an internal incremental high bit value. So the IV is the CID counter + the visible PN, permutated or not. Hence the AEAD can last much longer than CID's

Count(CID) * 2^32 + permuation(PN){unique in 32 bits, per CID}

However, for the sake of privacy, you need to do a a high bit increment for each CID, but that is also very cheap.

@huitema
Copy link
Contributor

huitema commented Apr 20, 2018

This design falls in the category of "obfuscation", analyzed in https://github.com/quicwg/base-drafts/wiki/Summary-of-the-PN-encryption-issues-and-alternatives#alternative-pn-encryption. It does not provide privacy, and also does not protect against ossification. You would be better off leaving the PN in clear text.

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 20, 2018

You would be better off leaving the PN in clear text.

That was also my original intend, but it does offer privacy because it is unique per CID and there is no visible gap to be compared across CID's (modulo NAT rebinding). As to obfuscation, if seeded with an unguessable value, and filtered for the zero case, it would not be unbreakable, but neither would it be very trivial to make use of in a busy switch. So it comes down to how much you wan't to harden against ossification - if the answer is "very" then full PNE is the only way.

@ad-l
Copy link
Contributor

ad-l commented Apr 23, 2018

@MikeBishop is right - the proposal only makes sense if it applies to all packets, so the text about this being only for new connection IDs must be removed

@nibanks
Copy link
Member Author

nibanks commented May 3, 2018

No longer necessary as PNE was merged.

@nibanks nibanks closed this May 3, 2018
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.

6 participants