将加密数据从 PC 发送到 Raspberry Pi 2






4.56/5 (4投票s)
在带有 Windows 10 IoT 的 Raspberry Pi 2 和 PC 之间发送加密字符串,并作为字节发送/接收
引言
这个项目将向您展示如何使用 C# 和 UWP(通用 Windows 平台)通过 TCP/IP 网络在带有 Windows 10 IoT 的 Raspberry Pi 2 和带有 Windows 10 的 PC 之间加密一个 string
并作为字节发送,其中 Raspberry 是服务器,接收并发送消息给客户端,并且 PC 是客户端,PC 向 Raspberry 发送消息。
背景
UWP - 通用 Windows 平台
UWP 是 Microsoft 的一种新型项目,它允许应用程序在任何 Windows 平台(如 Windows 8 或更高版本、Xbox、Windows phone 等)上运行,而无需任何修改,并且现在您有一个“Manifest”,如果您未在 manifest 中授予权限,您的应用程序将无法运行。 有关更多信息,请访问此链接。
Windows 10 IoT Core
Windows 10 IoT Core 是 Windows 10 的一个版本,它针对有或没有显示器的小型设备进行了优化。 撰写本文时,Windows 10 IoT Core 支持以下设备
- Raspberry Pi 2
- Arrow DragonBoard 410c
- MinnowBoard Max.
您可以使用 UWP 为 Windows 10 IoT Core 开发应用程序。 有关更多信息,请访问此链接。
要求
- VS 2015
- SDK Windows 10 IoT
- 带有 Windows 10 IoT Core 的 Raspberry Pi 2 通过以太网(如果您使用的是 Wi-Fi,则可能在调试和/或部署时遇到一些问题)。
项目
此项目有两个解决方案,一个用于 raspberry,另一个用于 Windows App。 如果您有一个解决方案和两个项目,则可能在调试时遇到一些问题,因为 raspberry 使用架构 ARM,而 PC 使用 x86。
Using the Code
加密
Cryptographic
类负责加密/解密数据,对于本文,我使用了对称算法。 要加密或解密一些数据,需要一些步骤
- 创建一个
SymmectricKeyAlgorithmProvider
,它有一个static
方法来创建,您可以在其中传递算法名称,SymmetricAlgorithmNames
类具有支持的算法名称 - 从密钥生成哈希
- 将文本转换为二进制
- 加密传递密钥,二进制文本和 iv(初始化向量,可以为
null
)
对于本文,我使用了加密密钥 "123
"。
有关如何支持算法的更多信息,请访问此链接。
加密
public static byte[] Encrypt(string text, string passPhrase)
{
IBuffer iv = null;
//Create SymmetricKeyAlgorithmProvider
var symetric = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
//Create hash for passPhrase to create symmetric Key
IBuffer keyBuffer = Hash(passPhrase);
//Create symmetric
CryptographicKey key = symetric.CreateSymmetricKey(keyBuffer);
//Convert texto to binary, for encrypt
IBuffer data = CryptographicBuffer.ConvertStringToBinary(text, BinaryStringEncoding.Utf8);
//Encrypt data
//Encrypt method return IBuffer
return CryptographicEngine.Encrypt(key, data, iv).ToArray();
}
解密
public static string Decrypt(IBuffer data, string passPhrase)
{
IBuffer iv = null;
//Create SymmetricKeyAlgorithmProvider
var symetric = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
//Create hash for passPhrase to create symmetric Key
IBuffer keyBuffer = Hash(passPhrase);
//Create symmetric key
CryptographicKey key = symetric.CreateSymmetricKey(keyBuffer);
//Decrypt data
IBuffer bufferDecrypted = CryptographicEngine.Decrypt(key, data, iv);
//Convert binary to string
return CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf8, bufferDecrypted);
}
哈希
public static IBuffer Hash(string text)
{
//Create HashAlgorithmProvider
var hash = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
//Create Hash object
CryptographicHash cryptographicHash = hash.CreateHash();
//Convert string to binary
IBuffer data = CryptographicBuffer.ConvertStringToBinary(text, BinaryStringEncoding.Utf8);
//Append data to generate Hash
cryptographicHash.Append(data);
//Generate Hash
return cryptographicHash.GetValueAndReset();
}
服务器 TCP
ServerTcp
类负责绑定和监听任何端口,对于此示例,我绑定了端口 9000。
为了绑定任何端口,您需要在以下位置标记标志:Package.appmanifest -> Capabilities -> InterneT(Client & Server)。
绑定端口
public async void StartAsync()
{
try
{
//Create a new Cancel Token
_cancel = new CancellationTokenSource();
_listener = new StreamSocketListener();
//Assigned event when have a new connection
_listener.ConnectionReceived += Listener_ConnectionReceived;
//Bind port
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
{
//If Close
while (!_cancel.IsCancellationRequested)
{
//Wait receive some data
byte[] data = await ReciveData(reader);
IBuffer buffer = data.AsBuffer();
//Decrypt message
string text = Cryptographic.Decrypt(buffer, "123");
//Invoke event when message is received
InvokeOnDataRecive(text);
}
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
收到连接后,我们需要监听端口以检查是否收到了一些数据。
private async Task<byte[]> ReciveData(DataReader reader)
{
//Read length of Message
uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
//if disconnect
if (sizeFieldCount != sizeof(uint))
throw new Exception("Disconnect");
//Get length of Message from buffer
uint bufferSize = reader.ReadUInt32();
//Read Message
uint dataRecive = await reader.LoadAsync(bufferSize);
//if disconnect
if (dataRecive != bufferSize)
throw new Exception("Disconnect");
var data = new byte[bufferSize];
//Get message from buffer
reader.ReadBytes(data);
return data;
}
发送消息
public async Task SendAsync(string text)
{
try
{
// DataWriter, who is send a message
var writer = new DataWriter(_socket.OutputStream);
//Encrypt message
byte[] data = Cryptographic.Encrypt(text, "123");
//Write length of message in buffer
writer.WriteInt32(data.Length);
//Write message in buffer
writer.WriteBytes(data);
//Send buffer
await writer.StoreAsync();
//Clear buffer
await writer.FlushAsync();
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
在 Raspberry Pi 上启动应用程序
当我们创建项目后台应用程序 (IoT) 时,VS 创建了一个 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();
});
}
private async void Server_OnDataRecive(ServerTcp sender, string args)
{
//answer text receive
await sender.SendAsync(string.Concat("Text Recive:", args));
}
客户端
Socket(套接字)
SocketClient
类负责创建套接字并与某些服务器通信。
连接
public async Task ConnectAsync(string ip, int port)
{
Ip = ip;
Port = port;
try
{
//Resolved HostName to connect
var hostName = new HostName(Ip);
_socket = new StreamSocket();
//Indicates whether keep-alive packets are sent to the remote destination
_socket.Control.KeepAlive = true;
//Connect
await _socket.ConnectAsync(hostName, Port.ToString());
_cancel = new CancellationTokenSource();
_writer = new DataWriter(_socket.OutputStream);
//Read Data
ReadAsync();
}
catch (Exception ex)
{
InvokeOnError(ex.Message);
}
}
ReadAsync
private async Task ReadAsync()
{
_reader = new DataReader(_socket.InputStream);
try
{
//If Close
while (!_cancel.IsCancellationRequested)
{
//Wait receive some data
byte[] data = await ReciveData(_reader);
IBuffer buffer = data.AsBuffer();
//Decrypt message
string text = Cryptographic.Decrypt(buffer, "123");
//Invoke event when message Recive
InvokeOnDataRecive(text);
}
}
catch (Exception e)
{
InvokeOnError(e.Message);
}
}
方法 ReceiveData
与 ServerTcp
类上的相同。
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);
}
}
结论
创建服务器和客户端之间的通信以发送加密消息并不难,但是您有一些工作要做。 关于 UWP/IoT core 的一个问题是找到一些信息,因为与 AspNet 或 WinForm 相比,我们有一个很小的站点来谈论这个问题。 找到它的最佳位置是 Microsoft 文档,其中有很多示例。
历史
- 创建的文章