Introduction
This project will show you how to encrypt a string
and send as bytes between Raspberry Pi 2 with Windows 10 IoT and PC with Windows 10 using C# and UWP (Universal Windows Platform) over TCP/IP network, where Raspberry is a server, receiving and send message to client when receive, and PC is a client and PC sends a message to Raspberry.
Background
UWP - Universal Windows Platform
UWP is a new type of project from Microsoft which allows applications to run in any Windows platform (like Windows 8 or superior, Xbox, Windows phone, etc.) without any modification, and now you have a “Manifest”, if you don't give permission in manifest, your app won't work. For further information, access this link.
Windows 10 IoT Core
Windows 10 IoT Core is a version of Windows 10 that is optimized for small devices with or without display. When this article was written, Windows 10 IoT Core supported the following devices:
- Raspberry Pi 2
- Arrow DragonBoard 410c
- MinnowBoard Max.
You can use UWP to develop apps for Windows 10 IoT Core. For more information, access this link.
Requirements
- VS 2015
- SDK Windows 10 IoT
- Raspberry Pi 2 with Windows 10 IoT Core on ethernet (if you are using Wi-fi, maybe you will have some problem to debug and/or deploy).
Project
This project has two solutions, one for raspberry and another for Windows App. If you have one solution and two projects, maybe you will have some problem to debug because raspberry uses architecture ARM and PC x86.
Using the Code
Encrypt
The Cryptographic
class is responsible to encrypt/decrypt data, for this article, I used symmetric Algorithm. To encrypt or decrypt some data, some steps are necessary:
- Create a
SymmectricKeyAlgorithmProvider
, that has a static
method to create where you pass name of the algorithm, SymmetricAlgorithmNames
class that has name of algorithm is supported - Generate Hash from key
- Convert text to binary
- Encrypt passing key, binary text and iv (Initialization Vector, this can be
null
)
For this article, I used encrypt key "123
".
For further information about how algorithms are supported, access this link.
Encrypt
public static byte[] Encrypt(string text, string passPhrase)
{
IBuffer iv = null;
var symetric = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
IBuffer keyBuffer = Hash(passPhrase);
CryptographicKey key = symetric.CreateSymmetricKey(keyBuffer);
IBuffer data = CryptographicBuffer.ConvertStringToBinary(text, BinaryStringEncoding.Utf8);
return CryptographicEngine.Encrypt(key, data, iv).ToArray();
}
Decrypt
public static string Decrypt(IBuffer data, string passPhrase)
{
IBuffer iv = null;
var symetric = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
IBuffer keyBuffer = Hash(passPhrase);
CryptographicKey key = symetric.CreateSymmetricKey(keyBuffer);
IBuffer bufferDecrypted = CryptographicEngine.Decrypt(key, data, iv);
return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, bufferDecrypted);
}
Hash
public static IBuffer Hash(string text)
{
var hash = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
CryptographicHash cryptographicHash = hash.CreateHash();
IBuffer data = CryptographicBuffer.ConvertStringToBinary(text, BinaryStringEncoding.Utf8);
cryptographicHash.Append(data);
return cryptographicHash.GetValueAndReset();
}
Server TCP
ServerTcp
class is responsible to bind and listen to any port, for this example I was binding port 9000.
For work bind any port, you need to mark flag in: Package.appmanifest -> Capabilities -> InterneT(Client & Server).
Bind Port
public async void StartAsync()
{
try
{
_cancel = new CancellationTokenSource();
_listener = new StreamSocketListener();
_listener.ConnectionReceived += Listener_ConnectionReceived;
await _listener.BindServiceNameAsync(_port.ToString());
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
Wait for Some Connection
private async void Listener_ConnectionReceived
(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
_socket = args.Socket;
var reader = new DataReader(args.Socket.InputStream);
try
{
while (!_cancel.IsCancellationRequested)
{
byte[] data = await ReciveData(reader);
IBuffer buffer = data.AsBuffer();
string text = Cryptographic.Decrypt(buffer, "123");
InvokeOnDataRecive(text);
}
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
After receive connection, we need listening port to check if some data is received.
private async Task<byte[]> ReciveData(DataReader reader)
{
uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
if (sizeFieldCount != sizeof(uint))
throw new Exception("Disconnect");
uint bufferSize = reader.ReadUInt32();
uint dataRecive = await reader.LoadAsync(bufferSize);
if (dataRecive != bufferSize)
throw new Exception("Disconnect");
var data = new byte[bufferSize];
reader.ReadBytes(data);
return data;
}
Send Message
public async Task SendAsync(string text)
{
try
{
var writer = new DataWriter(_socket.OutputStream);
byte[] data = Cryptographic.Encrypt(text, "123");
writer.WriteInt32(data.Length);
writer.WriteBytes(data);
await writer.StoreAsync();
await writer.FlushAsync();
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
Start Application on Raspberry Pi
When we created project Background Application(IoT), the VS created a StartUpTask
class, and this will have method Run
, application begins to run from that.
public void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral background = taskInstance.GetDeferral();
var server = new ServerTcp(9000);
server.OnError += Server_OnError;
server.OnDataRecive += Server_OnDataRecive;
ThreadPool.RunAsync(x =>{
server.StartAsync();
});
}
When data received:
private async void Server_OnDataRecive(ServerTcp sender, string args)
{
await sender.SendAsync(string.Concat("Text Recive:", args));
}
Client
A client is a Windows App using C# UWP.
Socket
A SocketClient
class is responsible to create socket and communicated with some server.
Connect
public async Task ConnectAsync(string ip, int port)
{
Ip = ip;
Port = port;
try
{
var hostName = new HostName(Ip);
_socket = new StreamSocket();
_socket.Control.KeepAlive = true;
await _socket.ConnectAsync(hostName, Port.ToString());
_cancel = new CancellationTokenSource();
_writer = new DataWriter(_socket.OutputStream);
ReadAsync();
}
catch (Exception ex)
{
InvokeOnError(ex.Message);
}
}
ReadAsync
private async Task ReadAsync()
{
_reader = new DataReader(_socket.InputStream);
try
{
while (!_cancel.IsCancellationRequested)
{
byte[] data = await ReciveData(_reader);
IBuffer buffer = data.AsBuffer();
string text = Cryptographic.Decrypt(buffer, "123");
InvokeOnDataRecive(text);
}
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
Method ReceiveData
is the same on ServerTcp
class.
DisconnectAsync
public async Task DisconnectAsync()
{
try
{
_cancel.Cancel();
_reader.DetachStream();
_reader.DetachBuffer();
_writer.DetachStream();
_writer.DetachBuffer();
await _socket.CancelIOAsync();
_cancel = new CancellationTokenSource();
}
catch (Exception ex)
{
InvokeOnError(ex.Message);
}
}
Conclusion
Create a communication between server and client send encrypt message isn't hard, but you have a little work. One problem about UWP/IoT core is to find some information, because we have a small site to talk about this, compared to AspNet or WinForm. The best place to find this is Microsoft documentation, there are many examples.
History