App Tethering using Encryption Hooks

Posted by on in Programming

RAD Studio 10.1 Berlin – App Tethering using Encryption Hooks

Introduction

App Tethering was first introduced in RAD Studio XE6 as a way to extend your VCL and FireMonkey (FMX) apps to other companion applications.  The companion apps can be Windows, Mac OS X and/or FMX multi-device apps.

ATSlide

RAD Studio 10.1 Berlin adds these App Tethering Improvements:

 

With App Tethering, you can properly, safely and securely exchange streams and data messages between apps, and you can execute remote actions like pressing a Button remotely or moving a Track Bar remotely.

With App Tethering, you can breathe new life into your existing Windows apps by extending Windows VCL and FMX apps connecting devices, sensors, data and services to build connected apps to add to a distributed Internet of Things (IoT) solution!

Here we have an App Tethering Server connected to an App Tethering Client:

AppTetheringServer_Client

We want to share or send data or streams between these two or more App Tethered connected applications.  For security, we need to encrypt the data before sending to any connected app, and then we need to decrypt the data when it’s received by any of the connected apps.

RAD Studio XE8 introduced 4 new intercept event handlers for the TTetheringAppProfile component to intercept the data or stream allowing you to add custom encryption to the data or stream before sending to app tethered connected apps, and then use the intercept event handlers to decrypt the data or stream.

These are the four new event handlers;

OnBeforeSendDataOnAfterReceiveDataOnBeforeSendStream, OnAfterReceiveStream:

AppTetheringAppProfile

OnBeforeSendData - Post processing of the data that occurs before the application profile sends data to the remote application profile.

Define a function for the OnBeforeSendData event to process ADataBuffer before sending it to the remote application profile. Put the result in the processed data.

Note: Define the inverse function of this event (OnAfterReceiveData) in the remote application profile.

 

OnAfterReceiveData - Preprocessing of the data that occurs when the application profile receives data from a remote application profile.

Define a function for the OnAfterReceiveData event to process the received ADataBuffer, according to the processing done in the remote application profile, and then return processed (or equivalent) data.

Note: Define this function if in the remote application profile the data is processed before being sent.

 

OnBeforeSendStream - Post processing of the stream data that occurs before the application profile sends the stream to the remote application profile.

Define a function for the OnBeforeSendStream event to process AInputStream before sending it to the remote application profile. Put the result in the processed AOutputStream stream.

You need to process the complete stream before sending it.

Note: Define the inverse function of this event (OnAfterReceiveStream) in the remote application profile.

 

OnAfterReceiveStream - Preprocessing of the input stream data that occurs when the application profile receives a stream data from the remote application profile.

Define a function for the OnAfterReceiveStream event to process the received AInputStream, according to the processing done in the remote application profile, and then return a processed AOutputStream.

You need to process the complete received InputStream.

Note: Define this function if in the remote application profile the stream is processed before being sent.

 

Implementation

Looking at the OnBeforeSendData and OnAfterReceiveData events:

BeforeSendData

AfterReceiveData

We see they are functions, so you need to return the data you want.  

ADataBuffer is the incoming received data to the functions.

For example, using the OnBeforeSendData event, we can take the incoming data string, and encrypt it using a cyphering method, such as XOR cipher (XOR $55), like this:

  Result := Copy(ADataBuffer);
    begin
      for I := Low(Result) to High(Result) do
        Result[I] := Result[I] xor $55; //encrypt data with XOR to every character using a key $55
    end;

In the sample Cypher Client and Cypher Server App Tethering applications we are using here, we will receive an encrypted string, and in the OnAfterReceiveData event, we need to decrypt the string data and return the plain data result to the tethered apps.  It’s important that you must always return the Result for the function, like this:

Result := Copy(ADataBuffer);
 begin
      for I := Low(Result) to High(Result) do
        Result[I] := Result[I] xor $55;  // decrypt data with XOR to every character using a key $55 
 end;

The 4 new intercept event handler functions are hooks where you first receive the data or streams from the OnBeforeSendData or OnBeforeSendStream events, and then you can modify the data or stream in some way, such as encrypting the data or stream.   Then using the OnAfterReceiveData or OnAfterReceiveStream events, you can decrypt the received data.  Remember you always need to return the Result from these functions to the tethering apps.

On the Cypher Server app, clicking “Resource 1” Button, sends the Resource Data “Hello from Server” to the connected tethered apps, by calling the TetheringAppProfile1.SendString() method.  But before the string data is sent, the TetheringAppProfile’s intercept event handler OnBeforeSendData fires and the string data gets encrypted using cyphering method: XOR data with $55:

for I := Low(Result) to High(Result) do
        Result[I] := Result[I] xor $55; // encrypt the string data

AppTetheringServer_Client_SendData

AppTetheringServer_Client_SendData_Log

BeforeSendData Raw "{D42B7408-A31D-417F-A29D-1F633106F418}#Res1#{"ResourceType":0,"DataType":5,"Value":"Hello from Server"}"

BeforeSendData Out ".agbaemxfdxadbxglxdcffdecadm(v0&dv.w0&: '60,%0woeyw4!4,%0wo`yw49 0wow099:u3':8u0'#0'w("

On the connected Cypher Client app, the TetheringAppProfile’s OnResourceUpdated and OnResourceReceived events fire:

AppProfile Resource Updated: "Res1 = Hello from Server
AppProfile Resource Received: "{D94F090E-7197-458B-82A0-8A08BF3C1044} = Resource "Hello from Server"

But before the string data is received by the connected tethered Client app, the TetheringAppProfile’s intercept event handler OnAfterReceiveData fires:

AfterReceiveData Raw ".agbaemxfdxadbxglxdcffdecadm(v0&dv.w0&: '60,%0woeyw4!4,%0wo`yw49 0wow099:u3':8u0'#0'w("

And the encrypted string data from the server gets decrypted in the OnAfterReceiveData event:

for I := Low(Result) to High(Result) do
        Result[I] := Result[I] xor $55;  // decrypt the data using cyphering method: XOR data with $55
    end;

AfterReceiveData In  "SND_STRING$1$Test#Resource "Hello from Server""

 

And the process works the same if I send data from the Cypher Client to the Cypher Server:

Cypher Client sends data “Hello from Client”:

BeforeSendData Raw "{A2E78695-3CE7-4558-85C9-9BE395EE95D0}#Res2#{"ResourceType":0,"DataType":5,"Value":"Hello from Client"}"

BeforeSendData Out ".gbmcl`xfbxa``mxm`lxlfl`l`e(v0&gv.w0&: '60,%0woeyw4!4,%0wo`yw49 0wow099:u3':8u9<0;!w("

 

Cypher Server receives data from Cypher Client:

AfterReceiveData Raw ".gbmcl`xfbxa``mxm`lxlfl`l`e(v0&gv.w0&: '60,%0woeyw4!4,%0wo`yw49 0wow099:u3':8u9<0;!w("

AfterReceiveData In  "{A2E78695-3CE7-4558-85C9-9BE395EE95D0}#Res2#{"ResourceType":0,"DataType":5,"Value":"Hello from Client"}"

 

Using these techniques with App Tethering, you can now add your own custom encryption to the data or stream before sending to app tethered connected apps, allowing safe and secure exchange of streams and data messages between apps!

 

RAD Studio 10.1 Berlin includes several sample App Tethering projects for both Object Pascal and C++ installed in the Samples folder:

Object Pascal/RTL/Tethering  and  Object Pascal/Multi-Device Samples/Device Sensors and Services/App Tethering

CPP/RTL/Tethering  and  CPP/Multi-Device Samples/Device Sensors and Services/App Tethering/MediaPlayer

 AppTetheringExamples

The DB_ShoppingList app shows AppTethering Sharing Data Resources between other paired profiles. 

 

The MediaPlayer app shows AppTethering executing remote actions like Play, Stop and Volume Control (using Remote Control) between other paired profiles. 

There’s a MediaPlayerHD app that’s Multi-Device (Windows/Mac, Android and iOS devices) for playing the video.

And a separate MediaPlayerCommand app for remote control for the video player.  It’s also a Multi-Device app (Android and iOS devices, Windows and Mac if you want it to.

 

The DesktopCast app shows sending screenshots & actions to other paired apps.  Any of the apps can take LiveScreenshots and then LiveCast to image to the other connected apps.

DesktopCast application has a client-server architecture where a client application can connect to a server application and receive a screenshot taken by the server application once or every 5 seconds using app tethering. The server application is a VCL application, and the client application is available both as a VCL application and as a FireMonkey application. Using TetheringAppProfile OnBeforeSendStream intercept event handler to encrypt STREAM before sending to app tethered connected apps. Using LockBox 2.1 VCL and FMX to encrypt/decrypt data using Rijndael (pronounced rain-dahl) AES from LockBox 2.1 (installed using Getit Package Manager).

 

Install LockBox 2.1 VCL and FMX using Getit Package Manager:

LockBoxInstall

C++ Builder (C++) source code for the Rijindael LockBox Cypher Client and Rijindael LockBox Cypher Server App Tethering applications can be download here: http://cc.embarcadero.com/item/30473

 FMXDeskTopCastAdaptersATServerAppAfterReceiveStream1

 

The PhotoWall app shows AppTethering sending streams between other paired profiles. 

The Photo Wall app has a DesktopWall viewer app is a Multi-Device app to display photos taken with its mobile counterpart application.

The Mobile app from the PhotoWall lets you take a photo with your Android or iOS device and display it on one or more DesktopWall instances over the network.

This sample demonstrates how to scan for App Tethering enabled Remote Instances across a network, pair with individual Remote Instances, and send Temporary Resources to those individual Remote Instances.

 

For additional information, see the docwiki: http://docwiki.embarcadero.com/RADStudio/Seattle/en/Using_App_Tethering

 

You can download the source code for the Delphi Cypher Client and Cypher Server App Tethering applications here:  http://cc.embarcadero.com/item/30437

 

C++ Builder (C++) source code for the Rijindael LockBox Cypher Client and Rijindael LockBox Cypher Server App Tethering applications can be download here: http://cc.embarcadero.com/item/30473

 

 



About
Gold User, Rank: 90, Points: 4
Al Mannarino has 25+ years of software development experience, including object-oriented analysis and design (OOAD) and developing and deploying production applications. He is currently a Principal Software Consultant and Evangelist for Embarcadero Technologies. Prior to joining Embarcadero, Al spent three years working with CodeGear, a division of Borland that was acquired by Embarcadero in 2008. He also worked for five years as a lead systems engineer for Borland supporting application lifecycle management, software delivery optimization and developer tools solutions. Prior to Borland, Al served as a systems engineer for companies including Objectivity, Versant, Red Brick Systems, Information Builders, and was an electrical engineer for Grumman Aerospace performing application implementations on complex electrical-mechanical systems. Al has a bachelor's of science degree in electrical engineering from Manhattan College.

Comments

Check out more tips and tricks in this development video: