packages
packages copied to clipboard
xtables-wgobfs: add an iptables extension module to obfuscate WireGuard
Maintainer: @infinet Compile tested: (ramips-mt7620 19.07.9 and 22.03.2, x86_64 19.07.9) Run tested: (x86_64 19.07.9)
Port from https://github.com/infinet/xt_wgobfs, this extension obfuscates WireGuard by:
-
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 long random bytes.
-
Drop keepalive message with 80% probability.
-
Change the Diffserv field to zero.
See https://github.com/infinet/xt_wgobfs/blob/main/README.md for usage.
Example as client:
Add two iptables rules to firewall.user:
iptables -t mangle -I INPUT -p udp -m udp --sport 6789 -j WGOBFS --key mysecretkey --unobfs
iptables -t mangle -I OUTPUT -p udp -m udp --dport 6789 -j WGOBFS --key mysecretkey --obfs
Here assuming remote server is listening on port 6789.
Signed-off-by: Wei Chen [email protected]
I changed the tile. Could you please re-run the Formalities test? Thanks!
You need to change commit title also
No usage of AUTORELEASE found in changes
Not sure why but only 1 of the usual 10+ checks ran, I suggest rebasing on current master and doing a force push.
@infinet It seems that your ChaCha8 hash function implementation has some crypto related flaws compared to reference ChaCha20 one:
- Although your macro called
EIGHT_ROUNDS
it runs only 4 rounds, so your hash is actually ChaCha4 - https://github.com/infinet/xt_wgobfs/blob/440a2ff505fec95a393c4a316ae2811c60ae0948/src/chacha8.c#L76-L79 - you have to callDOUBLE_ROUND
4 times to get 8 rounds, see reference https://git.zx2c4.com/wireguard-linux-compat/tree/src/crypto/zinc/chacha20/chacha20.c#n71 - You use ChaCha state part related to key in return value, whereas ChaCha20 skips it to nonce one - https://git.zx2c4.com/wireguard-linux-compat/tree/src/crypto/zinc/chacha20/chacha20.c#n150
- ChaCha state after rounds gets ORed with the initial state - https://github.com/infinet/xt_wgobfs/blob/440a2ff505fec95a393c4a316ae2811c60ae0948/src/chacha8.c#L101 - considering previous point it gets ORed with 4 well known constants and first half of the key. ChaCha20 hash doesn`t do OR before return at all.
Thank you for the insight! It will take some time to review and correct that part of code. In general, this module is trying to remove wireguard packets signature with minimal overhead, while wireguard is taking care of the communication security.
I've taken another look at chacha8 implementation.
-
You're correct; the chacha8 indeed only does 4 rounds. Need to test the performance of 8 rounds. If the overhead is similar to current 4 rounds, then revise the code to 8 rounds.
-
Wireguard uses XChaCha variant. It uses 128 bits nonce and original 256 bits key to generate a derived key, which is used by chacha20 with 96 bits nonce to encrypt message. The derived key generation takes first 32 bits and last 32 bits(Edit: first and last 128 bits) of multiple quarter rounds output, as you mentioned in remark 2.
-
The keystream used by wireguard to encrypt message is generated by ChaCha20 block function. Its output is different from the key derive function. It adds the original state to the quarter rounds output. This module use the same approach. https://git.zx2c4.com/wireguard-linux-compat/tree/src/crypto/zinc/chacha20/chacha20.c#n84
@infinet I also reviewed everything again and found this useful piece of information - https://crypto.stackexchange.com/a/11215
In short, original state addition (feed-forward) is required when you take parts of result that is being added with key (64 bits in the middle). In other words, you can omit feed-forward if you take first and last 32 bits, because they are being added with known input, so it will improve performance a bit.
So the only concern is number of rounds.
@infinet I also reviewed everything again and found this useful piece of information - https://crypto.stackexchange.com/a/11215
So the only concern is number of rounds.
I have made few modifications.
- The hash function is now chacha6 instead of chacha4.
- Input to chacha is 16 bytes instead of 8 bytes.
- All inputs for chacha are from the 16th to 31st bytes of WG message. First byte is used as counter and incremented each time to generate a new PRN.
The performance is almost the same.
I have rebased it on the latest master branch.