将加密数据从 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 文档,其中有很多示例。
历史
- 创建的文章


