Development discussion of WireGuard
 help / color / mirror / Atom feed
* Iptables WireGuard obfuscation extension
@ 2022-09-10 11:34 Wei Chen
  2022-09-28 11:33 ` Roman Mamedov
  2022-09-28 16:35 ` Jason A. Donenfeld
  0 siblings, 2 replies; 6+ messages in thread
From: Wei Chen @ 2022-09-10 11:34 UTC (permalink / raw)
  To: wireguard

Hi,

Jason once suggested use a netfilter module for obfuscation[1]. Here is one.

https://github.com/infinet/xt_wgobfs

It uses SipHash 1-2 to generate pseudo-random numbers in a reproducible way.
Sender and receiver share a siphash secret key. Sender creates and receiver
re-creates identical siphash output, if input is same. These siphash outputs
are used for obfuscation.

- The first 16 bytes of WG message is obfuscated.
- The mac2 field is also obfuscated if it is all zeros.
- Padding WG message with random bytes, which also has random length. They are
  from kernel get_random_bytes_wait() though.
- Drop 80% of keepalive message at random. Again randomness is from kernel.
- Change the Diffserv field to zero.

Tested working on Alpine linux kernel 5.15 and CentOS 7 kernel 3.10.

Performance test in two Alpine VMs running on same host. Each VM has 1 CPU and
256 MB RAM. Iperf3 results 1.1Gbits/s without,vs 860Mbits/s with obfuscation.


Wei

1. https://lists.zx2c4.com/pipermail/wireguard/2021-September/007155.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iptables WireGuard obfuscation extension
  2022-09-10 11:34 Iptables WireGuard obfuscation extension Wei Chen
@ 2022-09-28 11:33 ` Roman Mamedov
  2022-10-02 23:13   ` Wei Chen
  2022-09-28 16:35 ` Jason A. Donenfeld
  1 sibling, 1 reply; 6+ messages in thread
From: Roman Mamedov @ 2022-09-28 11:33 UTC (permalink / raw)
  To: Wei Chen; +Cc: wireguard

On Sat, 10 Sep 2022 06:34:42 -0500
Wei Chen <weichen302@zoho.com> wrote:

> Hi,
> 
> Jason once suggested use a netfilter module for obfuscation[1]. Here is one.
> 
> https://github.com/infinet/xt_wgobfs
> 
> It uses SipHash 1-2 to generate pseudo-random numbers in a reproducible way.
> Sender and receiver share a siphash secret key. Sender creates and receiver
> re-creates identical siphash output, if input is same. These siphash outputs
> are used for obfuscation.
> 
> - The first 16 bytes of WG message is obfuscated.
> - The mac2 field is also obfuscated if it is all zeros.
> - Padding WG message with random bytes, which also has random length. They are
>   from kernel get_random_bytes_wait() though.
> - Drop 80% of keepalive message at random. Again randomness is from kernel.
> - Change the Diffserv field to zero.
> 
> Tested working on Alpine linux kernel 5.15 and CentOS 7 kernel 3.10.
> 
> Performance test in two Alpine VMs running on same host. Each VM has 1 CPU and
> 256 MB RAM. Iperf3 results 1.1Gbits/s without,vs 860Mbits/s with obfuscation.

Hello,

Are you the author, so we can ask questions about it?

The "Usage" section speaks of "server" and "client". However in the WG world
there's not really a server or client per se, but all WG network members are
peers. As such, is it possible to propose an universal set of iptables rules
that would be fine to use on any network node?

As I understand, all INPUT packets to our local --dport need to be --unobfs,
and all OUTPUT packets from us to any other node need to be --obfs. Right?

-- 
With respect,
Roman

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iptables WireGuard obfuscation extension
  2022-09-10 11:34 Iptables WireGuard obfuscation extension Wei Chen
  2022-09-28 11:33 ` Roman Mamedov
@ 2022-09-28 16:35 ` Jason A. Donenfeld
  2022-09-28 18:17   ` Jean-Philippe Aumasson
  2022-10-02 23:35   ` Wei Chen
  1 sibling, 2 replies; 6+ messages in thread
From: Jason A. Donenfeld @ 2022-09-28 16:35 UTC (permalink / raw)
  To: Wei Chen; +Cc: wireguard, jeanphilippe.aumasson

Hey Wei,

On Sat, Sep 10, 2022 at 06:34:42AM -0500, Wei Chen wrote:
> Hi,
> 
> Jason once suggested use a netfilter module for obfuscation[1]. Here is one.
> 
> https://github.com/infinet/xt_wgobfs
> 
> It uses SipHash 1-2 to generate pseudo-random numbers in a reproducible way.
> Sender and receiver share a siphash secret key. Sender creates and receiver
> re-creates identical siphash output, if input is same. These siphash outputs
> are used for obfuscation.
> 
> - The first 16 bytes of WG message is obfuscated.
> - The mac2 field is also obfuscated if it is all zeros.
> - Padding WG message with random bytes, which also has random length. They are
>   from kernel get_random_bytes_wait() though.
> - Drop 80% of keepalive message at random. Again randomness is from kernel.
> - Change the Diffserv field to zero.
> 
> Tested working on Alpine linux kernel 5.15 and CentOS 7 kernel 3.10.
> 
> Performance test in two Alpine VMs running on same host. Each VM has 1 CPU and
> 256 MB RAM. Iperf3 results 1.1Gbits/s without,vs 860Mbits/s with obfuscation.

This is super cool! I'm very glad to see that you've made this.

A couple considerations for improvement (take them or leave them):

- Instead of using siphash, if you can make use of 64 bytes of
  randomness at a time, you might be able to get away with chacha8 (or
  even lower). The input to chacha20 is typically a 256 bit key and a
  nonce, but because we don't care about the cryptographic security here
  -- wireguard handles that part -- we can play fast and lose, and make
  our threat model, "would be too computationally complex to detect in
  real time". Things become quite fun when you don't need real crypto.
  To that end, we could perhaps get away with using chacha8 instead of
  chacha20, and doing so with a 128-bit key. This then provides lots of
  input to chacha:

  * 16 bytes, where the second half of that key was
  * 16 bytes nonce (since it doesn't look like you need more than one block)
  * If you really want to play fast and loose: 32-byte constant...

  Again, this is awful cryptographic advice, but from a traffic analysis
  point of view, I doubt it makes a difference.

  On the other hand, if all you need is 16 bytes output, then I guess
  siphash gets the job done.

- get_random_bytes() is slow if all you need is a byte at a time. That
  computes 96 bytes and then throws away 88 bytes of it. Instead, you
  can use get_random_u32(), which batches, and throw away 3 bytes. Or, I
  think I'll add to kernel 6.1 get_random_u8(), which will waste
  nothing.

  But actually, do you really need to do that? Can't you just run chacha
  or siphash or whatever super fast non-cryptographic thing you have,
  and just have an incrementing nonce? Or, better, since those keepalive
  messages already have a suitably random poly1305 tag, just run siphash
  on that, and discard if the resultant first byte is high/low/whatever.

- If this is to ever go upstream, you might want to add a `--obfs-type
  N` parameter to the XT userspace library and the IPC struct, and make
  it mandatory. To begin, everybody would use `--obfs-type 1`, since
  that's all there is. But maybe overtime, you'll add a fake TCP mode or
  a fake QUIC mode or a fake HTML mode, and then the types will grow.
  This way, maintenance wise, you only have to send updates to the
  netfilter module in the kernel, and don't need to update the libxt
  part.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iptables WireGuard obfuscation extension
  2022-09-28 16:35 ` Jason A. Donenfeld
@ 2022-09-28 18:17   ` Jean-Philippe Aumasson
  2022-10-02 23:35   ` Wei Chen
  1 sibling, 0 replies; 6+ messages in thread
From: Jean-Philippe Aumasson @ 2022-09-28 18:17 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: Wei Chen, wireguard

ChaCha6 is probably enough crypto-wise here.

On Wed 28 Sep 2022 at 18:35 Jason A. Donenfeld <Jason@zx2c4.com> wrote:
> Hey Wei,
>
> On Sat, Sep 10, 2022 at 06:34:42AM -0500, Wei Chen wrote:
> > Hi,
> >
> > Jason once suggested use a netfilter module for obfuscation[1]. Here is
> one.
> >
> > https://github.com/infinet/xt_wgobfs
> >
> > It uses SipHash 1-2 to generate pseudo-random numbers in a reproducible
> way.
> > Sender and receiver share a siphash secret key. Sender creates and
> receiver
> > re-creates identical siphash output, if input is same. These siphash
> outputs
> > are used for obfuscation.
> >
> > - The first 16 bytes of WG message is obfuscated.
> > - The mac2 field is also obfuscated if it is all zeros.
> > - Padding WG message with random bytes, which also has random length.
> They are
> >   from kernel get_random_bytes_wait() though.
> > - Drop 80% of keepalive message at random. Again randomness is from
> kernel.
> > - Change the Diffserv field to zero.
> >
> > Tested working on Alpine linux kernel 5.15 and CentOS 7 kernel 3.10.
> >
> > Performance test in two Alpine VMs running on same host. Each VM has 1
> CPU and
> > 256 MB RAM. Iperf3 results 1.1Gbits/s without,vs 860Mbits/s with
> obfuscation.
>
> This is super cool! I'm very glad to see that you've made this.
>
> A couple considerations for improvement (take them or leave them):
>
> - Instead of using siphash, if you can make use of 64 bytes of
>   randomness at a time, you might be able to get away with chacha8 (or
>   even lower). The input to chacha20 is typically a 256 bit key and a
>   nonce, but because we don't care about the cryptographic security here
>   -- wireguard handles that part -- we can play fast and lose, and make
>   our threat model, "would be too computationally complex to detect in
>   real time". Things become quite fun when you don't need real crypto.
>   To that end, we could perhaps get away with using chacha8 instead of
>   chacha20, and doing so with a 128-bit key. This then provides lots of
>   input to chacha:
>
>   * 16 bytes, where the second half of that key was
>   * 16 bytes nonce (since it doesn't look like you need more than one
> block)
>   * If you really want to play fast and loose: 32-byte constant...
>
>   Again, this is awful cryptographic advice, but from a traffic analysis
>   point of view, I doubt it makes a difference.
>
>   On the other hand, if all you need is 16 bytes output, then I guess
>   siphash gets the job done.
>
> - get_random_bytes() is slow if all you need is a byte at a time. That
>   computes 96 bytes and then throws away 88 bytes of it. Instead, you
>   can use get_random_u32(), which batches, and throw away 3 bytes. Or, I
>   think I'll add to kernel 6.1 get_random_u8(), which will waste
>   nothing.
>
>   But actually, do you really need to do that? Can't you just run chacha
>   or siphash or whatever super fast non-cryptographic thing you have,
>   and just have an incrementing nonce? Or, better, since those keepalive
>   messages already have a suitably random poly1305 tag, just run siphash
>   on that, and discard if the resultant first byte is high/low/whatever.
>
> - If this is to ever go upstream, you might want to add a `--obfs-type
>   N` parameter to the XT userspace library and the IPC struct, and make
>   it mandatory. To begin, everybody would use `--obfs-type 1`, since
>   that's all there is. But maybe overtime, you'll add a fake TCP mode or
>   a fake QUIC mode or a fake HTML mode, and then the types will grow.
>   This way, maintenance wise, you only have to send updates to the
>   netfilter module in the kernel, and don't need to update the libxt
>   part.
>
> Jason
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iptables WireGuard obfuscation extension
  2022-09-28 11:33 ` Roman Mamedov
@ 2022-10-02 23:13   ` Wei Chen
  0 siblings, 0 replies; 6+ messages in thread
From: Wei Chen @ 2022-10-02 23:13 UTC (permalink / raw)
  To: Roman Mamedov; +Cc: wireguard

Hi Roman,

> The "Usage" section speaks of "server" and "client". However in the WG world
> there's not really a server or client per se, but all WG network members are
> peers. As such, is it possible to propose an universal set of iptables rules
> that would be fine to use on any network node?
> 
> As I understand, all INPUT packets to our local --dport need to be --unobfs,
> and all OUTPUT packets from us to any other node need to be --obfs. Right?
> 

Yes, you are right. Besides unobfs/obfs INPUT/OUTPUT chain for a local
WG installation, one can also use it on a Linux gateway, mangle the
FORWARD chain. I haven't test it but it should work.


Wei

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Iptables WireGuard obfuscation extension
  2022-09-28 16:35 ` Jason A. Donenfeld
  2022-09-28 18:17   ` Jean-Philippe Aumasson
@ 2022-10-02 23:35   ` Wei Chen
  1 sibling, 0 replies; 6+ messages in thread
From: Wei Chen @ 2022-10-02 23:35 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: wireguard

Hi Jason,

Thank you for the suggestions!

> - Instead of using siphash, if you can make use of 64 bytes of
>   randomness at a time, you might be able to get away with chacha8 (or
>   even lower). The input to chacha20 is typically a 256 bit key and a
>   nonce, but because we don't care about the cryptographic security here
>   -- wireguard handles that part -- we can play fast and lose, and make
>   our threat model, "would be too computationally complex to detect in
>   real time". Things become quite fun when you don't need real crypto.
>   To that end, we could perhaps get away with using chacha8 instead of
>   chacha20, and doing so with a 128-bit key. This then provides lots of
>   input to chacha:
> 

It does need more than 16 bytes. Currently it gets away with it by
borrowing one byte from where supposed to XOR with reserved field. If
the all zeros reserved field changes as WG protocol evolving, then this
siphash128 approach will stop working.

> - get_random_bytes() is slow if all you need is a byte at a time. That
>   computes 96 bytes and then throws away 88 bytes of it. Instead, you
>   can use get_random_u32(), which batches, and throw away 3 bytes. Or, I
>   think I'll add to kernel 6.1 get_random_u8(), which will waste
>   nothing.
> 
>   But actually, do you really need to do that? Can't you just run chacha
>   or siphash or whatever super fast non-cryptographic thing you have,
>   and just have an incrementing nonce? Or, better, since those keepalive
>   messages already have a suitably random poly1305 tag, just run siphash
>   on that, and discard if the resultant first byte is high/low/whatever.
> 

I have a feeling get_random_bytes() might not fast, but have no idea I
have wasted so many bytes. Thank you! I will try get_random_u32() first.

> - If this is to ever go upstream, you might want to add a `--obfs-type
>   N` parameter to the XT userspace library and the IPC struct, and make
>   it mandatory. To begin, everybody would use `--obfs-type 1`, since
> 

Added to todo list.


Wei

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-10-02 23:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-10 11:34 Iptables WireGuard obfuscation extension Wei Chen
2022-09-28 11:33 ` Roman Mamedov
2022-10-02 23:13   ` Wei Chen
2022-09-28 16:35 ` Jason A. Donenfeld
2022-09-28 18:17   ` Jean-Philippe Aumasson
2022-10-02 23:35   ` Wei Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).