Re: Iptables WireGuard obfuscation extension
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
Re: Iptables WireGuard obfuscation extension
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
Re: Iptables WireGuard obfuscation extension
ChaCha6 is probably enough crypto-wise here. On Wed 28 Sep 2022 at 18:35 Jason A. Donenfeld 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 >
Re: Iptables WireGuard obfuscation extension
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
Iptables WireGuard obfuscation extension
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