public LoRaPayloadJoinRequest CreateJoinRequest() { byte[] devNonce = new byte[2]; if (string.IsNullOrEmpty(this.DevNonce) || (!this.isFirstJoinRequest)) { Random random = new Random(); // DevNonce[0] = 0xC8; DevNonce[1] = 0x86; random.NextBytes(devNonce); this.DevNonce = BitConverter.ToString(devNonce).Replace("-", string.Empty); Array.Reverse(devNonce); this.isFirstJoinRequest = false; } else { devNonce = ConversionHelper.StringToByteArray(this.DevNonce); Array.Reverse(devNonce); } TestLogger.Log($"[{this.LoRaDevice.DeviceID}] Join request sent DevNonce: {BitConverter.ToString(devNonce).Replace("-", string.Empty)} / {this.DevNonce}"); var joinRequest = new LoRaPayloadJoinRequest(this.LoRaDevice.AppEUI, this.LoRaDevice.DeviceID, devNonce); joinRequest.SetMic(this.LoRaDevice.AppKey); return(joinRequest); }
public byte[] GetJoinRequest() { // create a join request var AppEUI = LoRaTools.Utils.ConversionHelper.ByteArrayToString(this.LoRaDevice.GetAppEUI()); var DevEUI = LoRaTools.Utils.ConversionHelper.ByteArrayToString(this.LoRaDevice.GetDevEUI()); byte[] DevNonce = new byte[2]; if ((this.LoRaDevice.DevNonce == "") || (!this.isFirstJoinRequest)) { Random random = new Random(); // DevNonce[0] = 0xC8; DevNonce[1] = 0x86; random.NextBytes(DevNonce); this.LoRaDevice.DevNonce = BitConverter.ToString(DevNonce).Replace("-", ""); Array.Reverse(DevNonce); this.isFirstJoinRequest = false; } else { DevNonce = this.LoRaDevice.GetDevNonce(); Array.Reverse(DevNonce); } Logger.LogAlways(this.LoRaDevice.DevEUI, $"Join request sent DevNonce: {BitConverter.ToString(DevNonce).Replace("-","")}"); var join = new LoRaPayloadJoinRequest(AppEUI, DevEUI, DevNonce); join.SetMic(this.LoRaDevice.AppKey); return(join.GetByteMessage()); }
public void When_Creating_Join_Request_Recreating_Should_Pass_Mic_Check( string appEUIText, string devEUIText, string appKeyText, string devNonceText) { var wrongAppKeyText = "00000000000000000000000000003333"; // create a join request var devNonce = ConversionHelper.StringToByteArray(devNonceText); Array.Reverse(devNonce); var join = new LoRaPayloadJoinRequest(appEUIText, devEUIText, devNonce); Assert.Equal(appEUIText, join.GetAppEUIAsString()); Assert.Equal(devEUIText, join.GetDevEUIAsString()); var uplinkMessage = join.SerializeUplink(appKeyText); Assert.False(join.CheckMic(wrongAppKeyText), "Mic check with wrong appKey should not pass"); Assert.True(join.CheckMic(appKeyText), "Mic check should work after setting it"); var rxpk = uplinkMessage.Rxpk[0]; Assert.True(LoRaPayload.TryCreateLoRaPayload(rxpk, out LoRaPayload parsedLoRaPayload)); Assert.IsType <LoRaPayloadJoinRequest>(parsedLoRaPayload); var parsedLoRaJoinRequest = (LoRaPayloadJoinRequest)parsedLoRaPayload; Assert.True(parsedLoRaPayload.CheckMic(appKeyText), "Parsed join request should pass mic check with correct appKey"); Assert.False(parsedLoRaJoinRequest.CheckMic(wrongAppKeyText), "Parsed join request should not pass mic check with wrong appKey"); }
public byte[] GetJoinRequest() { //create a join request byte[] AppEUI = LoRaDevice.GetAppEUI(); Array.Reverse(AppEUI); byte[] DevEUI = LoRaDevice.GetDevEUI(); Array.Reverse(DevEUI); byte[] DevNonce = new byte[2]; if ((LoRaDevice.DevNonce == "") || (!isFirstJoinRequest)) { Random random = new Random(); // DevNonce[0] = 0xC8; DevNonce[1] = 0x86; random.NextBytes(DevNonce); LoRaDevice.DevNonce = BitConverter.ToString(DevNonce).Replace("-", ""); Array.Reverse(DevNonce); isFirstJoinRequest = false; } else { DevNonce = LoRaDevice.GetDevNonce(); Array.Reverse(DevNonce); } Logger.Log(LoRaDevice.DevEUI, $"Join request sent DevNonce: {BitConverter.ToString(DevNonce).Replace("-","")}", Logger.LoggingLevel.Always); var join = new LoRaPayloadJoinRequest(AppEUI, DevEUI, DevNonce); join.SetMic(LoRaDevice.AppKey); return(join.GetByteMessage()); }
byte[] CreateJoinRequest() { //create a join request byte[] AppEUI = ConversionHelper.StringToByteArray(LoRaDevice.AppEUI); Array.Reverse(AppEUI); byte[] DevEUI = ConversionHelper.StringToByteArray(LoRaDevice.DeviceID); Array.Reverse(DevEUI); byte[] devNonce = new byte[2]; if ((string.IsNullOrEmpty(this.DevNonce)) || (!isFirstJoinRequest)) { Random random = new Random(); // DevNonce[0] = 0xC8; DevNonce[1] = 0x86; random.NextBytes(devNonce); this.DevNonce = BitConverter.ToString(devNonce).Replace("-", ""); Array.Reverse(devNonce); isFirstJoinRequest = false; } else { devNonce = ConversionHelper.StringToByteArray(this.DevNonce); Array.Reverse(devNonce); } TestLogger.Log($"[{LoRaDevice.DeviceID}] Join request sent DevNonce: {BitConverter.ToString(devNonce).Replace("-","")} / {this.DevNonce}"); var join = new LoRaPayloadJoinRequest(AppEUI, DevEUI, devNonce); join.SetMic(this.LoRaDevice.AppKey); return(join.GetByteMessage()); }
public void When_Creating_Join_Request_From_Bytes_Should_Pass_Mic_Check( string appEUI, string devEUI, string appKey) { var rawJoinRequestBytes = new byte[] { 0, 4, 0, 0, 0, 0, 16, 229, 251, 4, 0, 0, 0, 0, 16, 229, 251, 254, 228, 147, 93, 188, 238 }; var messageType = rawJoinRequestBytes[0]; Assert.Equal((int)LoRaMessageType.JoinRequest, messageType); var joinRequest = new LoRaPayloadJoinRequest(rawJoinRequestBytes); Assert.NotNull(joinRequest); Assert.Equal(appEUI, joinRequest.GetAppEUIAsString()); Assert.Equal(devEUI, joinRequest.GetDevEUIAsString()); Assert.True(joinRequest.CheckMic(appKey)); }
public ConcentratorDeduplicationTest() { this.cache = new MemoryCache(new MemoryCacheOptions()); this.connectionManager = new LoRaDeviceClientConnectionManager(this.cache, NullLogger <LoRaDeviceClientConnectionManager> .Instance); this.simulatedABPDevice = new SimulatedDevice(TestDeviceInfo.CreateABPDevice(0)); this.dataPayload = this.simulatedABPDevice.CreateConfirmedDataUpMessage("payload"); this.dataRequest = WaitableLoRaRequest.Create(this.dataPayload); this.loRaDevice = new LoRaDevice(this.simulatedABPDevice.DevAddr, this.simulatedABPDevice.DevEUI, this.connectionManager); this.simulatedOTAADevice = new SimulatedDevice(TestDeviceInfo.CreateOTAADevice(0)); this.joinPayload = this.simulatedOTAADevice.CreateJoinRequest(appkey: this.simulatedOTAADevice.AppKey); this.joinRequest = WaitableLoRaRequest.Create(this.joinPayload); this.joinRequest.SetPayload(this.joinPayload); this.concentratorDeduplication = new ConcentratorDeduplication( this.cache, NullLogger <IConcentratorDeduplication> .Instance); }
public void JoinRequest_Should_Succeed_Mic_Check() { var appEUIText = "0005100000000004"; var appEUIBytes = ConversionHelper.StringToByteArray(appEUIText); var devEUIText = "0005100000000004"; var devEUIBytes = ConversionHelper.StringToByteArray(devEUIText); var devNonceText = "ABCD"; var devNonceBytes = ConversionHelper.StringToByteArray(devNonceText); var appKey = "00000000000000000005100000000004"; var joinRequest = new LoRaPayloadJoinRequest(appEUIText, devEUIText, devNonceBytes); joinRequest.SetMic(appKey); Assert.True(joinRequest.CheckMic(appKey)); Assert.True(joinRequest.CheckMic(appKey)); // ensure multiple calls work! var rxpk = new LoRaTools.LoRaPhysical.Rxpk() { Chan = 7, Rfch = 1, Freq = 903.700000, Stat = 1, Modu = "LORA", Datr = "SF10BW125", Codr = "4/5", Rssi = -17, Lsnr = 12.0f, }; var data = joinRequest.GetByteMessage(); rxpk.Data = Convert.ToBase64String(data); rxpk.Size = (uint)data.Length; byte[] decodedJoinRequestBytes = Convert.FromBase64String(rxpk.Data); var decodedJoinRequest = new LoRaTools.LoRaMessage.LoRaPayloadJoinRequest(decodedJoinRequestBytes); Assert.True(decodedJoinRequest.CheckMic(appKey)); }
private static void TestRxpk(Rxpk rxpk) { Assert.True(LoRaPayload.TryCreateLoRaPayload(rxpk, out LoRaPayload loRaPayload)); Assert.Equal(LoRaMessageType.JoinRequest, loRaPayload.LoRaMessageType); LoRaPayloadJoinRequest joinRequestMessage = (LoRaPayloadJoinRequest)loRaPayload; byte[] joinRequestAppKey = new byte[16] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var joinRequestBool = joinRequestMessage.CheckMic(ConversionHelper.ByteArrayToString(joinRequestAppKey)); if (!joinRequestBool) { Console.WriteLine("Join Request type was not computed correclty"); } byte[] joinRequestAppEui = new byte[8] { 1, 2, 3, 4, 1, 2, 3, 4 }; byte[] joinRequestDevEUI = new byte[8] { 2, 3, 4, 5, 2, 3, 4, 5 }; byte[] joinRequestDevNonce = new byte[2] { 16, 45 }; Array.Reverse(joinRequestAppEui); Array.Reverse(joinRequestDevEUI); Array.Reverse(joinRequestDevNonce); Assert.True(joinRequestMessage.AppEUI.ToArray().SequenceEqual(joinRequestAppEui)); Assert.True(joinRequestMessage.DevEUI.ToArray().SequenceEqual(joinRequestDevEUI)); Assert.True(joinRequestMessage.DevNonce.ToArray().SequenceEqual(joinRequestDevNonce)); }
public void TestJoinRequest() { byte[] physicalUpstreamPyld = new byte[12]; physicalUpstreamPyld[0] = 2; string jsonUplink = @"{ ""rxpk"":[ { ""time"":""2013-03-31T16:21:17.528002Z"", ""tmst"":3512348611, ""chan"":2, ""rfch"":0, ""freq"":866.349812, ""stat"":1, ""modu"":""LORA"", ""datr"":""SF7BW125"", ""codr"":""4/6"", ""rssi"":-35, ""lsnr"":5.1, ""size"":32, ""data"":""AAQDAgEEAwIBBQQDAgUEAwItEGqZDhI="" }]}"; var joinRequestInput = Encoding.Default.GetBytes(jsonUplink); LoRaMessage joinRequestMessage = new LoRaMessage(physicalUpstreamPyld.Concat(joinRequestInput).ToArray()); if (joinRequestMessage.loRaMessageType != LoRaMessageType.JoinRequest) { Console.WriteLine("Join Request type was not parsed correclty"); } byte[] joinRequestAppKey = new byte[16] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; var joinRequestBool = joinRequestMessage.CheckMic(BitConverter.ToString(joinRequestAppKey).Replace("-", "")); if (!joinRequestBool) { Console.WriteLine("Join Request type was not computed correclty"); } byte[] joinRequestAppEui = new byte[8] { 1, 2, 3, 4, 1, 2, 3, 4 }; byte[] joinRequestDevEUI = new byte[8] { 2, 3, 4, 5, 2, 3, 4, 5 }; byte[] joinRequestDevNonce = new byte[2] { 16, 45 }; Array.Reverse(joinRequestAppEui); Array.Reverse(joinRequestDevEUI); Array.Reverse(joinRequestDevNonce); LoRaPayloadJoinRequest joinRequestMessagePayload = ((LoRaPayloadJoinRequest)joinRequestMessage.payloadMessage); Assert.True(joinRequestMessagePayload.appEUI.SequenceEqual(joinRequestAppEui)); Assert.True(joinRequestMessagePayload.devEUI.SequenceEqual(joinRequestDevEUI)); Assert.True(joinRequestMessagePayload.devNonce.SequenceEqual(joinRequestDevNonce)); }
/// <summary> /// Process OTAA join request /// </summary> async Task <DownlinkPktFwdMessage> ProcessJoinRequestAsync(Rxpk rxpk, LoRaPayloadJoinRequest joinReq, DateTime startTimeProcessing) { var timeWatcher = new LoRaOperationTimeWatcher(this.loraRegion, startTimeProcessing); using (var processLogger = new ProcessLogger(timeWatcher)) { byte[] udpMsgForPktForwarder = new byte[0]; var devEUI = joinReq.GetDevEUIAsString(); var appEUI = joinReq.GetAppEUIAsString(); // set context to logger processLogger.SetDevEUI(devEUI); var devNonce = joinReq.GetDevNonceAsString(); Logger.Log(devEUI, $"join request received", LogLevel.Information); var loRaDevice = await this.deviceRegistry.GetDeviceForJoinRequestAsync(devEUI, appEUI, devNonce); if (loRaDevice == null) { return(null); } if (string.IsNullOrEmpty(loRaDevice.AppKey)) { Logger.Log(loRaDevice.DevEUI, "join refused: missing AppKey for OTAA device", LogLevel.Error); return(null); } if (loRaDevice.AppEUI != appEUI) { Logger.Log(devEUI, "join refused: AppEUI for OTAA does not match device", LogLevel.Error); return(null); } if (!joinReq.CheckMic(loRaDevice.AppKey)) { Logger.Log(devEUI, "join refused: invalid MIC", LogLevel.Error); return(null); } // Make sure that is a new request and not a replay if (!string.IsNullOrEmpty(loRaDevice.DevNonce) && loRaDevice.DevNonce == devNonce) { Logger.Log(devEUI, "join refused: DevNonce already used by this device", LogLevel.Information); loRaDevice.IsOurDevice = false; return(null); } // Check that the device is joining through the linked gateway and not another if (!string.IsNullOrEmpty(loRaDevice.GatewayID) && !string.Equals(loRaDevice.GatewayID, this.configuration.GatewayID, StringComparison.InvariantCultureIgnoreCase)) { Logger.Log(devEUI, $"join refused: trying to join not through its linked gateway, ignoring join request", LogLevel.Information); loRaDevice.IsOurDevice = false; return(null); } var netIdBytes = BitConverter.GetBytes(this.configuration.NetId); var netId = new byte[3] { netIdBytes[0], netIdBytes[1], netIdBytes[2] }; var appNonce = OTAAKeysGenerator.GetAppNonce(); var appNonceBytes = LoRaTools.Utils.ConversionHelper.StringToByteArray(appNonce); var appKeyBytes = LoRaTools.Utils.ConversionHelper.StringToByteArray(loRaDevice.AppKey); var appSKey = OTAAKeysGenerator.CalculateKey(new byte[1] { 0x02 }, appNonceBytes, netId, joinReq.DevNonce, appKeyBytes); var nwkSKey = OTAAKeysGenerator.CalculateKey(new byte[1] { 0x01 }, appNonceBytes, netId, joinReq.DevNonce, appKeyBytes); var devAddr = OTAAKeysGenerator.GetNwkId(netId); if (!timeWatcher.InTimeForJoinAccept()) { // in this case it's too late, we need to break and avoid saving twins Logger.Log(devEUI, $"join refused: processing of the join request took too long, sending no message", LogLevel.Information); return(null); } Logger.Log(loRaDevice.DevEUI, $"saving join properties twins", LogLevel.Debug); var deviceUpdateSucceeded = await loRaDevice.UpdateAfterJoinAsync(devAddr, nwkSKey, appSKey, appNonce, devNonce, LoRaTools.Utils.ConversionHelper.ByteArrayToString(netId)); Logger.Log(loRaDevice.DevEUI, $"done saving join properties twins", LogLevel.Debug); if (!deviceUpdateSucceeded) { Logger.Log(devEUI, $"join refused: join request could not save twins", LogLevel.Error); return(null); } var windowToUse = timeWatcher.ResolveJoinAcceptWindowToUse(loRaDevice); if (windowToUse == 0) { Logger.Log(devEUI, $"join refused: processing of the join request took too long, sending no message", LogLevel.Information); return(null); } double freq = 0; string datr = null; uint tmst = 0; if (windowToUse == 1) { try { datr = this.loraRegion.GetDownstreamDR(rxpk); freq = this.loraRegion.GetDownstreamChannelFrequency(rxpk); } catch (RegionLimitException ex) { Logger.Log(devEUI, ex.ToString(), LogLevel.Error); } // set tmst for the normal case tmst = rxpk.Tmst + this.loraRegion.Join_accept_delay1 * 1000000; } else { Logger.Log(devEUI, $"processing of the join request took too long, using second join accept receive window", LogLevel.Information); tmst = rxpk.Tmst + this.loraRegion.Join_accept_delay2 * 1000000; if (string.IsNullOrEmpty(this.configuration.Rx2DataRate)) { Logger.Log(devEUI, $"using standard second receive windows for join request", LogLevel.Information); // using EU fix DR for RX2 freq = this.loraRegion.RX2DefaultReceiveWindows.frequency; datr = this.loraRegion.DRtoConfiguration[RegionFactory.CurrentRegion.RX2DefaultReceiveWindows.dr].configuration; } else { Logger.Log(devEUI, $"using custom second receive windows for join request", LogLevel.Information); freq = this.configuration.Rx2DataFrequency; datr = this.configuration.Rx2DataRate; } } loRaDevice.IsOurDevice = true; this.deviceRegistry.UpdateDeviceAfterJoin(loRaDevice); // Build join accept downlink message Array.Reverse(netId); Array.Reverse(appNonceBytes); return(this.CreateJoinAcceptDownlinkMessage( netId, loRaDevice.AppKey, devAddr, appNonceBytes, datr, freq, tmst, devEUI)); } }