async Task <FidoU2FHidMessage> QueryLowLevelAsync(FidoU2FHidMessage query, CancellationToken cancellationToken, bool throwErrors = true) { try { await device.WriteFidoU2FHidMessageAsync(query, cancellationToken); var init = await device.ReadFidoU2FHidMessageAsync(cancellationToken); if (init.Channel != query.Channel) { throw new Exception( $"Bad channel in query answer (0x{init.Channel:X8} but expected 0x{query.Channel:X8})"); } if (init.Command == U2FHidCommand.Error) { if (throwErrors) { ThrowForError(init); } return(init); } if (init.Command != query.Command) { throw new Exception($"Bad command in query answer ({init.Command} but expected {query.Command})"); } return(init); } catch (DeviceNotConnectedException exception) { throw new KeyGoneException("The key isn't connected anymore", exception); } }
/// <summary> /// The lock command places an exclusive lock for one channel to communicate with the device. /// As long as the lock is active, any other channel trying to send a message will fail. /// In order to prevent a stalling or crashing application to lock the device indefinitely, a lock time up to /// 10 seconds may be set. An application requiring a longer lock has to send repeating lock commands to /// maintain the lock. /// </summary> public async Task <bool> LockAsync(byte timeInSeconds, CancellationToken cancellationToken = default(CancellationToken)) { if (timeInSeconds > 10) { throw new ArgumentOutOfRangeException(nameof(timeInSeconds), timeInSeconds, "Lock time must be between 0 and 10s"); } var data = new [] { timeInSeconds }.Segment(); var message = new FidoU2FHidMessage(GetChannel(), U2FHidCommand.Lock, data); var response = await QueryLowLevelAsync(message, cancellationToken, false); if (response.Command == U2FHidCommand.Error) { var errorCode = GetError(response); if (errorCode == U2FHidErrors.Busy) { return(false); } ThrowForError(response); } return(true); }
protected override async Task <ArraySegment <byte> > QueryAsync(ArraySegment <byte> message, CancellationToken cancellationToken = default(CancellationToken)) { var fidoMessage = new FidoU2FHidMessage(GetChannel(), U2FHidCommand.Message, message); var response = await QueryLowLevelAsync(fidoMessage, cancellationToken); return(response.Data); }
/// <summary> /// Sends a transaction to the device, which immediately echoes the same data back. /// This command is defined to be an uniform function for debugging, latency and performance measurements. /// </summary> public async Task <ArraySegment <byte> > Ping(ArraySegment <byte> pingData, CancellationToken cancellationToken = default(CancellationToken)) { var message = new FidoU2FHidMessage(GetChannel(), U2FHidCommand.Ping, pingData); var response = await QueryLowLevelAsync(message, cancellationToken); if (!pingData.ContentEquals(response.Data)) { throw new InvalidPingResponseException("The device didn't echo back our ping message."); } return(response.Data); }
private static U2FHidErrors GetError(FidoU2FHidMessage message) { Debug.Assert(message.Command == U2FHidCommand.Error); if (message.Data.Count < 1) { throw new Exception("Bad length for error"); } var error = (U2FHidErrors)message.Data.AsEnumerable().First(); return(error); }
U2FHidDeviceInfo OnInitAnswered(FidoU2FHidMessage response, ArraySegment <byte> requestNonce) { log.Info("Initialization response received"); ArraySegment <byte> responseNonce; var deviceInfo = MessageCodec.DecodeInitResponse(response.Data, out responseNonce); if (!responseNonce.ContentEquals(requestNonce)) { throw new Exception("Invalid nonce, not an answer to our init request"); } DeviceInfo = deviceInfo; return(deviceInfo); }
public async Task <U2FHidDeviceInfo> InitAsync(ArraySegment <byte> nonce, CancellationToken cancellationToken = default(CancellationToken)) { if (nonce.Count != InitNonceSize) { throw new ArgumentException( $"Nonce should be exactly {InitNonceSize} bytes but is {nonce.Count} bytes long instead.", nameof(nonce)); } log.Info("Sending initialization"); var message = new FidoU2FHidMessage(BroadcastChannel, U2FHidCommand.Init, nonce); var answer = await QueryLowLevelAsync(message, cancellationToken); return(OnInitAnswered(answer, nonce)); }
static unsafe void Wink(Win32HidDevice device, byte b1, byte b2, byte b3, byte b4) { var msg = new FidoU2FHidMessage( (uint)(unchecked (b1 << 24 | b2 << 16 | b3 << 8 | b4)), U2FHidCommand.Wink); device.WriteFidoU2FHidMessageAsync(msg, CancellationToken.None).Wait(); var caps = device.Information.Capabilities; var bufferOut = new byte[caps.OutputReportByteLength]; fixed(byte *pBuffer = bufferOut) { var intPtr = new IntPtr(pBuffer); var task = Kernel32Dll.ReadFileAsync(device.Handle, intPtr, bufferOut.Length); var read = task.Result; Console.WriteLine("Read {0} bytes", read); } WriteBuffer(bufferOut); }
static void ThrowForError(FidoU2FHidMessage message) { var error = GetError(message); throw new Exception("Error: " + EnumDescription.Get(error)); }
public Task WinkAsync(CancellationToken cancellationToken = default(CancellationToken)) { var message = new FidoU2FHidMessage(GetChannel(), U2FHidCommand.Wink); return(QueryLowLevelAsync(message, cancellationToken)); }