/// <summary> /// Creates a new <seealso cref="BluetoothUnlockPacket"/> object from the given payload. /// </summary> /// <param name="payload">The API frame payload. It must start with the frame type corresponding /// to a Bluetooth Unlock packet (<c>0x2C</c>). The byte array must be in <see cref="OperatingMode.API"/> /// mode.</param> /// <returns>Parsed Bluetooth Unlock packet.</returns> /// <exception cref="ArgumentException">If <c>payload[0] != APIFrameType.BLE_UNLOCK.GetValue()</c> /// or if <c>payload.Length <![CDATA[<]]> <see cref="MIN_API_PAYLOAD_LENGTH"/></c>.</exception> /// <exception cref="ArgumentNullException">If <c><paramref name="payload"/> == null</c>.</exception> public static BluetoothUnlockPacket CreatePacket(byte[] payload) { if (payload == null) { throw new ArgumentNullException("Bluetooth Unlock packet payload cannot be null."); } // 1 (Frame type) + 1 (Step) + 32 (Hash length) if (payload.Length < MIN_API_PAYLOAD_LENGTH) { throw new ArgumentException("Incomplete Bluetooth Unlock packet."); } if ((payload[0] & 0xFF) != APIFrameType.BLE_UNLOCK.GetValue()) { throw new ArgumentException("Payload is not a Bluetooth Unlock packet."); } // payload[0] is the frame type. int index = 1; // SRP phase. SrpPhase phase = SrpPhase.UNKNOWN.Get(payload[index]); index = index + 1; // Data. byte[] data = null; if (index < payload.Length) { data = new byte[payload.Length - index]; Array.Copy(payload, index, data, 0, data.Length); } return(new BluetoothUnlockPacket(phase, data)); }
/// <summary> /// Class constructor. Instantiates a <see cref="BluetoothUnlockPacket"/> with the given parameters. /// </summary> /// <param name="phase">The SRP phase.</param> /// <param name="data">The data.</param> /// <exception cref="ArgumentException">If <paramref name="phase"/> is <see cref="SrpPhase.UNKNOWN"/>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="data"/> is <c>null</c>.</exception> /// <seealso cref="Models.SrpPhase"/> public BluetoothUnlockPacket(SrpPhase phase, byte[] data) : base(APIFrameType.BLE_UNLOCK) { if (phase == SrpPhase.UNKNOWN) { throw new ArgumentException("SRP phase cannot be unknown."); } SrpPhase = phase; Data = data ?? throw new ArgumentNullException("Data cannot be null."); logger = LogManager.GetLogger <BluetoothUnlockPacket>(); }
/// <summary> /// Gets the <see cref="SrpPhase"/> associated with the specified ID <paramref name="value"/>. /// </summary> /// <param name="source"></param> /// <param name="value">ID value to retrieve <see cref="SrpPhase"/>.</param> /// <returns>The <see cref="SrpPhase"/> for the specified ID <paramref name="value"/>, /// <see cref="SrpPhase.UNKNOWN"/> if it does not exist.</returns> public static SrpPhase Get(this SrpPhase source, byte value) { var values = Enum.GetValues(typeof(SrpPhase)).OfType <SrpPhase>(); if (values.Cast <byte>().Contains(value)) { return((SrpPhase)value); } return(SrpPhase.UNKNOWN); }
/// <summary> /// Returns the <see cref="SrpPhase"/> in string format. /// </summary> /// <param name="source"></param> /// <returns>The <see cref="SrpPhase"/> in string format.</returns> public static string ToDisplayString(this SrpPhase source) { return(string.Format("({0}) {1}", HexUtils.ByteArrayToHexString(ByteUtils.IntToByteArray((byte)source)), GetName(source))); }
/// <summary> /// Gets the SRP phase name. /// </summary> /// <param name="source"></param> /// <returns>The SRP phase name.</returns> public static string GetName(this SrpPhase source) { return(lookupTable.ContainsKey(source) ? lookupTable[source] : source.ToString()); }
/// <summary> /// Gets the SRP phase value. /// </summary> /// <param name="source"></param> /// <returns>The SRP phase value.</returns> public static byte GetValue(this SrpPhase source) { return((byte)source); }
/// <summary> /// Starts the bluetooth authentication with the XBee device. /// </summary> /// <exception cref="BluetoothAuthenticationException">If there is any error performing the /// bluetooth authentication.</exception> /// <exception cref="InterfaceNotOpenException">If the connection interface is not open.</exception> /// <exception cref="XBeeException">If there is any error in the communication process.</exception> public void Authenticate() { // Check connection. if (!device.IsOpen) { throw new InterfaceNotOpenException(); } device.PacketReceived += ReceiveBLEPacket; try { User user = new User(API_USERNAME, password); // Phase 1. byte[] clientEphemeral = user.StartAuthentication(); expectedPhase = SrpPhase.PHASE_2; unlockResponse = null; device.SendPacketAsync(new BluetoothUnlockPacket(SrpPhase.PHASE_1, clientEphemeral)); lock (unlockLock) { Monitor.Wait(unlockLock, TIMEOUT_AUTH); } CheckResponsePacket(); // Phase 2. int index = 0; byte[] salt = new byte[LENGTH_SALT]; Array.Copy(unlockResponse.Data, index, salt, 0, salt.Length); index += LENGTH_SALT; byte[] serverEphemeral = new byte[LENGTH_EPHEMERAL]; Array.Copy(unlockResponse.Data, index, serverEphemeral, 0, serverEphemeral.Length); // Phase 3. byte[] clientSessionProof = user.ProcessChallenge(salt, serverEphemeral); expectedPhase = SrpPhase.PHASE_4; unlockResponse = null; device.SendPacketAsync(new BluetoothUnlockPacket(SrpPhase.PHASE_3, clientSessionProof)); lock (unlockLock) { Monitor.Wait(unlockLock, TIMEOUT_AUTH); } CheckResponsePacket(); // Phase 4. index = 0; byte[] serverSessionProof = new byte[LENGTH_SESSION_PROOF]; Array.Copy(unlockResponse.Data, index, serverSessionProof, 0, serverSessionProof.Length); index += LENGTH_SESSION_PROOF; TxNonce = new byte[LENGTH_NONCE]; Array.Copy(unlockResponse.Data, index, TxNonce, 0, TxNonce.Length); index += LENGTH_NONCE; RxNonce = new byte[LENGTH_NONCE]; Array.Copy(unlockResponse.Data, index, RxNonce, 0, RxNonce.Length); user.VerifySession(serverSessionProof); if (!user.authenticated) { throw new BluetoothAuthenticationException(string.Format(ERROR_AUTH_EXTENDED, ERROR_BAD_PROOF)); } // Save the sesion key. Key = user.SessionKey; } catch (IOException e) { throw new XBeeException(ERROR_WRITING, e); } finally { device.PacketReceived -= ReceiveBLEPacket; } }