在当今的数字化世界中,数据安全变得越来越重要。无论是在个人项目还是在企业环境中,确保数据在传输过程中的安全性都是一个关键的考虑因素。本文将介绍如何使用C#和UWP(Universal Windows Platform)在Raspberry Pi 2(作为服务器)和Windows 10 PC(作为客户端)之间建立加密通信。
UWP是微软推出的一种新型项目类型,它允许应用程序在任何Windows平台上运行,无需任何修改。这包括Windows 8或更高版本、Xbox、Windows Phone等。此外,UWP应用程序现在有一个“清单”文件,如果未在清单中授予权限,应用程序将无法正常工作。
Windows 10 IoT Core是Windows 10的一个版本,专为小型设备优化,无论是否带显示屏。截至本文撰写时,Windows 10 IoT Core支持以下设备:
可以使用UWP为Windows 10 IoT Core开发应用程序。
要完成这个项目,需要:
这个项目包含两个解决方案,一个用于Raspberry Pi,另一个用于Windows应用程序。如果有一个解决方案和两个项目,可能会在调试时遇到问题,因为Raspberry Pi使用ARM架构,而PC使用x86架构。
在本文中,将使用对称算法来加密和解密数据。以下是加密和解密数据所需的步骤:
SymmetricKeyAlgorithmProvider
,它有一个静态方法来创建,可以通过传递算法的名称来调用它。在本文中,使用了加密密钥"123"。
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();
}
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);
}
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();
}
ServerTcp
类负责绑定并监听任何端口。在这个例子中,绑定了端口9000。要绑定任何端口,需要在Package.appmanifest -> Capabilities -> Internet(Client & Server)中标记标志。
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);
}
}
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);
}
}
private async Task 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;
}
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);
}
}
当创建了后台应用程序项目(IoT)时,Visual Studio会创建一个StartUpTask
类,应用程序将从该类中的Run
方法开始运行。
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();
});
}
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);
}
}
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);
}
}
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);
}
}