Ich versuche mit Windows 10 IoT Core und C# eine Verbindung zu machen mit dem Miniserver aber es gelingt mir eben nicht. Unten alle code welche ich bis jetzt geschrieben habe. Einig funktioniert aber de Schritt wo der Client ein KeyExchange machen sollte funktioniert nicht (not found).
Wenn ich das laufen lasse bekomme ich folgendes:
Sending to http://192.168.1.200/jdev/sys/getPublicKey/ =>
Content: {"LL": { "control": "dev/sys/getPublicKey/", "value": "-----BEGIN CERTIFICATE-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTEBiUtYNiGl rRZm184J5buRR/MYPNMR0eIPfOseIskiJkvDqXQ75YlU+3M6/zEAy1IVunc5yPoVFMESg4C+mCXrtLnJxTuSucEmpGMgycoDCZi o/maOKHRJQtoTAYQJ1C55N2OmFDAy5nHDfpQX1wDo79o1TZo7xa+ mrWRBOjHQIDAQAB-----END CERTIFICATE-----", "Code": "200"}}
Socket opened
Sending to http://192.168.1.200/jdev/sys/keyexchange/ => G2fUypak2bQUabMcuWetSwclkiPQcoc6sjMIMTPoddTkxxnT3N 05DA5kxypIVu1Koc3NPMbM8lLiuHQrDpq6SiMJysQeeWHXDBIs JRf8fquqjQjsL4khf3FiPZ8oBiPKQCjzWAZv4nLpiauOid7+8D 3Qu4v4bsVCuxfX0kybCms2eJJuCIq6IuGW0af0uJcE92bz2/sloVPsFAC/NHRBfFeRd8LmqLnQthT1+ARCSWldznG3Zh7OHzwPLa/iXXqFGr9RhmMNYMWXJi1BZ7CgUGoSlxZ3tjigTyngYrgwFGIAx YQeNH3JlY0SaQF/Rdr9OQPU+ZJzpt11EooBHjOP7+2+YGSnqmCBzGm+9m6Z6WBByX/ZJ2FQ4maXPeX+vbo9
Content: <html><head><title>error</title></head><body><errorcode>404</errorcode> <errordetail>Not Found</errordetail></body></html>
Sending to http://192.168.1.200/jdev/cfg/api/authenticate/ =>
Content: {"LL": { "control": "dev/cfg/api/authenticate/", "value": "{'snr': 'EE:E0:00:48:00:5C', 'version':'10.0.9.24'}", "Code": "200"}}
Socket closed:
Also ein public key bekomme ich schon. Socket wird auch geöffnet aber demnächst wieder geschlossen weil der 'keyexchange' fehlgeschlagen ist. Es gibt so viele möglichkeiten es falsch zu machen aber nur eine Lösung welche funktioniert. Dokus sind auch sehr begrenzt. Wer kann mir weiter helfen?
Hier ist der Code:
using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using TGBGateway.Viewmodel;
using WebSocketSharp;
using Windows.ApplicationModel.Resources.Core;
using Windows.UI.Xaml.Controls;
namespace TGBGateway
{
public sealed partial class MainPage : Page
{
private const string m_Host = "192.168.1.200";
private const int m_Port = 80;
private static readonly string m_WsRfc6455 = $"ws://{m_Host}:{m_Port}/ws/rfc6455";
private static readonly string m_ApiBaseUrl = $"http://{m_Host}:{m_Port}/jdev/cfg/api/";
private static readonly string m_SpsBaseUrl = $"http://{m_Host}:{m_Port}/jdev/sps/";
private static readonly string m_SysBaseUrl = $"http://{m_Host}:{m_Port}/jdev/sys/";
private static readonly string m_GetkeyUrl = $"{m_SysBaseUrl}getPublicKey/";
private static readonly string m_keyExchangeUrl = $"{m_SysBaseUrl}keyexchange/";
private static readonly string m_AuthenticateUrl = $"{m_ApiBaseUrl}authenticate/";
private static readonly string m_EnableBinStatusUpdate = $"{m_SpsBaseUrl}enablebinstatusupdate";
private readonly Uri m_WsRfc6455Uri;
private readonly Uri m_GetkeyUri;
private readonly Uri m_KeyExchangeUri;
private string UserId => Parameter("UserId");
private string Password => Parameter("Password");
private WebSocket socket;
private byte[] m_PublicKey;
private AesManaged m_AesManaged = new AesManaged();
private RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
struct LoxoneHeaderDef
{
byte cBinType; // fix 0x03
byte cIdentifier; // 8-Bit Unsigned Integer (little endian)
byte cInfo; // Info
byte cReserved; // reserved
uint nLen; // 32-Bit Unsigned Integer (little endian)
};
public MainPage()
{
this.InitializeComponent();
this.DataContext = new SettingViewmodel();
m_WsRfc6455Uri = new Uri(m_WsRfc6455);
m_GetkeyUri = new Uri($"{m_GetkeyUrl}");
m_KeyExchangeUri = new Uri(m_keyExchangeUrl);
Task task = Task.Run(async () => await StartServer());
}
private string Parameter(string id)
{
var subtree = ResourceManager.Current.MainResourceMap.GetSubtree ("Constants");
var result = subtree.GetValue(id, ResourceContext.GetForViewIndependentUse());
return result.ValueAsString;
}
/// <summary>
/// Start listening
/// </summary>
private async Task StartServer()
{
try
{
m_PublicKey = await GetPublicKeyFromLoxone();
socket = new WebSocket(m_WsRfc6455, "remotecontrol");
socket.SetCredentials(UserId, Password, true);
socket.OnMessage += Client_OnMessage;
socket.OnError += Socket_OnError;
socket.OnClose += Socket_OnClose;
socket.OnOpen += Socket_OnOpen;
socket.Connect();
// socket.Send(EnableBinStatusUpdate); // Get NOT FOUND
await ExchangeKeysWithLoxone(); // Get NOT FOUND
await AuthenticateWithLoxone();
}
catch (Exception ex)
{
Debug.WriteLine($"Error occured: {ex.Message}");
throw ex;
}
}
/// <summary>
/// Called upon opening the socket
/// </summary>
private void Socket_OnOpen(object sender, EventArgs e)
{
Debug.WriteLine($"Socket opened");
}
/// <summary>
/// Called after the socket was closed
/// </summary>
private void Socket_OnClose(object sender, CloseEventArgs e)
{
Debug.WriteLine($"Socket closed: {e.Reason}");
}
/// <summary>
/// Called on error (never gets called??)
/// </summary>
private void Socket_OnError(object sender, ErrorEventArgs e)
{
Debug.WriteLine($"Socket error: {e.Message}");
}
/// <summary>
/// Called on receiving a message
/// </summary>
private void Client_OnMessage(object sender, MessageEventArgs e)
{
Debug.WriteLine(e.Data);
}
/// <summary>
/// Authenticate with the miniserver.
/// </summary>
private async Task AuthenticateWithLoxone()
{
var authenticateUri = new Uri($"{m_AuthenticateUrl}");
var result = await SendHttpMessage(authenticateUri, string.Empty, true);
}
/// <summary>
/// Exchange my Key and IV with the miniserver
/// </summary>
private async Task ExchangeKeysWithLoxone()
{
RSAParameters rsaKeyInfo = rsa.ExportParameters(false);
rsaKeyInfo.Modulus = m_PublicKey;
rsa.ImportParameters(rsaKeyInfo);
var encrypted = rsa.Encrypt($"{m_AesManaged.Key}:{m_AesManaged.IV} ".Select(chr => (byte)chr).ToArray(), false);
var message = Convert.ToBase64String(encrypted);
await SendHttpMessage(m_KeyExchangeUri, message);
}
/// <summary>
/// Get the public key from the miniserver
/// </summary>
private async Task<byte[]> GetPublicKeyFromLoxone()
{
// Get a key from the mini server
HttpResponseMessage result = await SendHttpMessage(m_GetkeyUri, string.Empty);
// Get the answer from the mini server
var json = await result.Content.ReadAsStringAsync();
// Parse the received string into a JSON object
dynamic keypacket = JObject.Parse(json);
// Get the 'LL' part from the JSON (result is a JSON)
JObject LL = (dynamic)keypacket["LL"];
// Get the hashkey (value) from the JSON
var publicKeyString = (string)LL["value"];
publicKeyString = publicKeyString.Replace("-----BEGIN CERTIFICATE-----", String.Empty).Replace("-----END CERTIFICATE-----", string.Empty);
var plainTextBytes = Encoding.UTF8.GetBytes(publicKeyString);
// return publicKeyString.Select(chr => (byte)chr).ToArray();
// Convert it into a Base64 byte array
return Convert.ToBase64String(plainTextBytes).Select(chr => (byte)chr).ToArray();
}
/// <summary>
/// Send a request to the miniserver
/// </summary>
private async Task<HttpResponseMessage> SendHttpMessage(Uri uri, string message, bool withCredentials = false)
{
try
{
HttpClient client = new HttpClient
{
BaseAddress = uri
};
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, message);
if (withCredentials)
{
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{ UserId}:{Password}")));
}
Debug.WriteLine($"Sending to {uri.AbsoluteUri} => {message}");
var result = await client.SendAsync(request);
var content = await result.Content.ReadAsStringAsync();
Debug.WriteLine($"Content: {content}");
return result;
}
catch (Exception ex)
{
Debug.WriteLine($"Sending failed. Message{ex.Message}");
throw;
}
}
}
}
Kommentar