65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (4投票s)

2016年4月3日

CPOL

3分钟阅读

viewsIcon

18041

downloadIcon

243

在带有 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 类负责加密/解密数据,对于本文,我使用了对称算法。 要加密或解密一些数据,需要一些步骤

  1. 创建一个 SymmectricKeyAlgorithmProvider,它有一个 static 方法来创建,您可以在其中传递算法名称,SymmetricAlgorithmNames 类具有支持的算法名称
  2. 从密钥生成哈希
  3. 将文本转换为二进制
  4. 加密传递密钥,二进制文本和 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));
} 

客户端

客户端是使用 C# UWP 的 Windows App。

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);
    }
}   

方法 ReceiveDataServerTcp 类上的相同。

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 文档,其中有很多示例。

历史

  • 创建的文章
© . All rights reserved.