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

Commit

Permalink
Add Complete XOR Patch Functionality (#255)
Browse files Browse the repository at this point in the history
Co-authored-by: Davide De Rosa <[email protected]>
  • Loading branch information
tmthecoder and keeshux authored Nov 6, 2022
1 parent e225ca1 commit 5ecd732
Show file tree
Hide file tree
Showing 19 changed files with 567 additions and 97 deletions.
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

0 comments on commit 5ecd732

Please sign in to comment.