Skip to content
This repository has been archived by the owner on Sep 29, 2024. It is now read-only.

Add Complete XOR Patch Functionality #255

Merged
merged 15 commits into from
Nov 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ on:
- "master"
paths-ignore:
- "*.md"
pull_request:
types: [ opened, synchronize ]

concurrency:
group: ${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}

jobs:
run_tests:
name: Run tests
runs-on: macos-12
timeout-minutes: 10
timeout-minutes: 5
steps:
- uses: actions/checkout@v2
- uses: maxim-lobanov/setup-xcode@v1
Expand Down
2 changes: 1 addition & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"repositoryURL": "https://github.com/passepartoutvpn/wireguard-apple",
"state": {
"branch": null,
"revision": "b4f74b7bcba9004a1852e615298f9cbc68fb7f67",
"revision": "d3b8f1ac6f3361d69bd3daf8aee3c43012c6ec0b",
"version": "1.0.16"
}
}
Expand Down
9 changes: 9 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ let package = Package(
name: "TunnelKitCoreTests",
dependencies: [
"TunnelKitCore"
],
exclude: [
"RandomTests.swift",
"RawPerformanceTests.swift",
"RoutingTests.swift"
]),
.testTarget(
name: "TunnelKitOpenVPNTests",
Expand All @@ -169,6 +174,10 @@ let package = Package(
"TunnelKitOpenVPNAppExtension",
"TunnelKitLZO"
],
exclude: [
"DataPathPerformanceTests.swift",
"EncryptionPerformanceTests.swift"
],
resources: [
.process("Resources")
]),
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,20 @@ TunnelKit can parse .ovpn configuration files. Below are a few details worth men

#### Non-standard

- Single-byte XOR masking
- Via `--scramble xormask <character>`
- XOR all incoming and outgoing bytes by the ASCII value of the character argument
- See [Tunnelblick website][about-tunnelblick-xor] for more details
- XOR-patch functionality:
- Multi-byte XOR Masking
- Via `--scramble xormask <passphrase>`
- XOR all incoming and outgoing bytes by the passphrase given
- XOR Position Masking
- Via `--scramble xorptrpos`
- XOR all bytes by their position in the array
- Packet Reverse Scramble
- Via `--scramble reverse`
- Keeps the first byte and reverses the rest of the array
- XOR Scramble Obfuscate
- Via `--scramble obfuscate <passphrase>`
- Performs a combination of the three above (specifically `xormask <passphrase>` -> `xorptrpos` -> `reverse` -> `xorptrpos` for reading, and the opposite for writing)
- See [Tunnelblick website][about-tunnelblick-xor] for more details (Patch was written in accordance with Tunnelblick's patch for compatibility)

#### Unsupported

Expand Down Expand Up @@ -221,6 +231,7 @@ A custom TunnelKit license, e.g. for use in proprietary software, may be negotia
- [SURFnet][ppl-surfnet]
- [SwiftyBeaver][dep-swiftybeaver-repo] - Copyright (c) 2015 Sebastian Kreutzberger
- [XMB5][ppl-xmb5] for the [XOR patch][ppl-xmb5-xor] - Copyright (c) 2020 Sam Foxman
- [tmthecoder][ppl-tmthecoder] for the complete [XOR patch][ppl-tmthecoder-xor] - Copyright (c) 2022 Tejas Mehta
- [eduVPN][ppl-eduvpn] for the convenient WireGuardKitGo script

### OpenVPN
Expand Down Expand Up @@ -264,6 +275,8 @@ Website: [passepartoutvpn.app][about-website]
[ppl-surfnet]: https://www.surf.nl/en/about-surf/subsidiaries/surfnet
[ppl-xmb5]: https://github.com/XMB5
[ppl-xmb5-xor]: https://github.com/passepartoutvpn/tunnelkit/pull/170
[ppl-tmthecoder]: https://github.com/tmthecoder
[ppl-tmthecoder-xor]: https://github.com/passepartoutvpn/tunnelkit/pull/255
[ppl-eduvpn]: https://github.com/eduvpn/apple
[about-tunnelblick-xor]: https://tunnelblick.net/cOpenvpn_xorpatch.html
[about-pr-bitcode]: https://github.com/passepartoutvpn/tunnelkit/issues/51
Expand Down
34 changes: 34 additions & 0 deletions Sources/CTunnelKitOpenVPNCore/include/XORMethodNative.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// XORMethodNative.h
// TunnelKit
//
// Created by Davide De Rosa on 11/4/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of TunnelKit.
//
// TunnelKit is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// TunnelKit is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger, XORMethodNative) {
XORMethodNativeNone,
XORMethodNativeMask,
XORMethodNativePtrPos,
XORMethodNativeReverse,
XORMethodNativeObfuscate
};
35 changes: 14 additions & 21 deletions Sources/CTunnelKitOpenVPNProtocol/PacketStream.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,16 @@
//

#import "PacketStream.h"
#import "XOR.h"

static const NSInteger PacketStreamHeaderLength = sizeof(uint16_t);

@implementation PacketStream

+ (void)memcpyXor:(uint8_t *)dst src:(NSData *)src xorMask:(uint8_t)xorMask
{
if (xorMask != 0) {
for (int i = 0; i < src.length; ++i) {
dst[i] = ((uint8_t *)(src.bytes))[i] ^ xorMask;
}
return;
}
memcpy(dst, src.bytes, src.length);
}

+ (NSArray<NSData *> *)packetsFromStream:(NSData *)stream until:(NSInteger *)until xorMask:(uint8_t)xorMask
+ (NSArray<NSData *> *)packetsFromInboundStream:(NSData *)stream
until:(NSInteger *)until
xorMethod:(XORMethodNative)xorMethod
xorMask:(NSData *)xorMask
{
NSInteger ni = 0;
NSMutableArray<NSData *> *parsed = [[NSMutableArray alloc] init];
Expand All @@ -54,11 +47,7 @@ + (void)memcpyXor:(uint8_t *)dst src:(NSData *)src xorMask:(uint8_t)xorMask
}
NSData *packet = [stream subdataWithRange:NSMakeRange(start, packlen)];
uint8_t* packetBytes = (uint8_t*) packet.bytes;
if (xorMask != 0) {
for (int i = 0; i < packet.length; i++) {
packetBytes[i] ^= xorMask;
}
}
xor_memcpy(packetBytes, packet, xorMethod, xorMask, false);
[parsed addObject:packet];
ni = end;
}
Expand All @@ -68,19 +57,23 @@ + (void)memcpyXor:(uint8_t *)dst src:(NSData *)src xorMask:(uint8_t)xorMask
return parsed;
}

+ (NSData *)streamFromPacket:(NSData *)packet xorMask:(uint8_t)xorMask
+ (NSData *)outboundStreamFromPacket:(NSData *)packet
xorMethod:(XORMethodNative)xorMethod
xorMask:(NSData *)xorMask
{
NSMutableData *raw = [[NSMutableData alloc] initWithLength:(PacketStreamHeaderLength + packet.length)];

uint8_t *ptr = raw.mutableBytes;
*(uint16_t *)ptr = CFSwapInt16HostToBig(packet.length);
ptr += PacketStreamHeaderLength;
[PacketStream memcpyXor:ptr src:packet xorMask:xorMask];
xor_memcpy(ptr, packet, xorMethod, xorMask, true);

return raw;
}

+ (NSData *)streamFromPackets:(NSArray<NSData *> *)packets xorMask:(uint8_t)xorMask
+ (NSData *)outboundStreamFromPackets:(NSArray<NSData *> *)packets
xorMethod:(XORMethodNative)xorMethod
xorMask:(NSData *)xorMask
{
NSInteger streamLength = 0;
for (NSData *p in packets) {
Expand All @@ -92,7 +85,7 @@ + (NSData *)streamFromPackets:(NSArray<NSData *> *)packets xorMask:(uint8_t)xorM
for (NSData *packet in packets) {
*(uint16_t *)ptr = CFSwapInt16HostToBig(packet.length);
ptr += PacketStreamHeaderLength;
[PacketStream memcpyXor:ptr src:packet xorMask:xorMask];
xor_memcpy(ptr, packet, xorMethod, xorMask, true);
ptr += packet.length;
}
return raw;
Expand Down
16 changes: 13 additions & 3 deletions Sources/CTunnelKitOpenVPNProtocol/include/PacketStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,24 @@
//

#import <Foundation/Foundation.h>
#import "XORMethodNative.h"

NS_ASSUME_NONNULL_BEGIN

@interface PacketStream : NSObject

+ (NSArray<NSData *> *)packetsFromStream:(NSData *)stream until:(NSInteger *)until xorMask:(uint8_t)xorMask;
+ (NSData *)streamFromPacket:(NSData *)packet xorMask:(uint8_t)xorMask;
+ (NSData *)streamFromPackets:(NSArray<NSData *> *)packets xorMask:(uint8_t)xorMask;
+ (NSArray<NSData *> *)packetsFromInboundStream:(NSData *)stream
until:(NSInteger *)until
xorMethod:(XORMethodNative)xorMethod
xorMask:(nullable NSData *)xorMask;

+ (NSData *)outboundStreamFromPacket:(NSData *)packet
xorMethod:(XORMethodNative)xorMethod
xorMask:(nullable NSData *)xorMask;

+ (NSData *)outboundStreamFromPackets:(NSArray<NSData *> *)packets
xorMethod:(XORMethodNative)xorMethod
xorMask:(nullable NSData *)xorMask;

@end

Expand Down
99 changes: 99 additions & 0 deletions Sources/CTunnelKitOpenVPNProtocol/include/XOR.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// XOR.h
// TunnelKit
//
// Created by Tejas Mehta on 5/24/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of TunnelKit.
//
// TunnelKit is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// TunnelKit is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with TunnelKit. If not, see <http://www.gnu.org/licenses/>.
//

#import <Foundation/Foundation.h>
#import "XORMethodNative.h"

static inline void xor_mask(uint8_t *dst, const uint8_t *src, NSData *xorMask, size_t length)
{
if (xorMask.length > 0) {
for (size_t i = 0; i < length; ++i) {
dst[i] = src[i] ^ ((uint8_t *)(xorMask.bytes))[i % xorMask.length];
}
return;
}
memcpy(dst, src, length);
}

static inline void xor_ptrpos(uint8_t *dst, const uint8_t *src, size_t length)
{
for (size_t i = 0; i < length; ++i) {
dst[i] = src[i] ^ (i + 1);
}
}

static inline void xor_reverse(uint8_t *dst, const uint8_t *src, size_t length)
{
size_t start = 1;
size_t end = length - 1;
uint8_t temp = 0;
dst[0] = src[0];
while (start < end) {
temp = src[start];
dst[start] = src[end];
dst[end] = temp;
start++;
end--;
}
if (start == end) {
dst[start] = src[start];
}
}

static inline void xor_memcpy(uint8_t *dst, NSData *src, XORMethodNative method, NSData *mask, BOOL outbound)
{
const uint8_t *source = (uint8_t *)src.bytes;
switch (method) {
case XORMethodNativeNone:
memcpy(dst, source, src.length);
break;

case XORMethodNativeMask:
xor_mask(dst, source, mask, src.length);
break;

case XORMethodNativePtrPos:
xor_ptrpos(dst, source, src.length);
break;

case XORMethodNativeReverse:
xor_reverse(dst, source, src.length);
break;

case XORMethodNativeObfuscate:
if (outbound) {
xor_ptrpos(dst, source, src.length);
xor_reverse(dst, dst, src.length);
xor_ptrpos(dst, dst, src.length);
xor_mask(dst, dst, mask, src.length);
} else {
xor_mask(dst, source, mask, src.length);
xor_ptrpos(dst, dst, src.length);
xor_reverse(dst, dst, src.length);
xor_ptrpos(dst, dst, src.length);
}
break;
}
}
5 changes: 3 additions & 2 deletions Sources/TunnelKitAppExtension/LinkProducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public protocol LinkProducer {
/**
Returns a `LinkInterface`.

- Parameter xorMask: The XOR mask.
- Parameter userObject: Optional user data.
- Returns: A generic `LinkInterface`.
**/
func link(xorMask: UInt8?) -> LinkInterface
func link(userObject: Any?) -> LinkInterface
}
3 changes: 0 additions & 3 deletions Sources/TunnelKitCore/LinkInterface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,4 @@ public protocol LinkInterface: IOInterface {

/// The number of packets that this interface is able to bufferize.
var packetBufferSize: Int { get }

/// A byte to xor all packet payloads with.
var xorMask: UInt8 { get }
}
Loading