示例#1
0
 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;
 }
示例#2
0
        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);
        }
示例#3
0
        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 static async Task WriteFidoU2FHidMessageAsync([NotNull] this IHidDevice device,
            FidoU2FHidMessage message, CancellationToken cancellationToken)
        {
            if (device == null) throw new ArgumentNullException(nameof(device));

            log.Debug($"Sending U2FHid message {message.Command} on channel 0x{message.Channel:X8} with {message.Data.Count} bytes of data");
                
            var report = device.CreateOutputReport();
            var packets = MakeOutputPackets(report.Data.Count, message);
            packets.Item1.WriteTo(report.Data);
            
            await device.SendOutputReportAsync(report, cancellationToken);

            foreach (var continuation in packets.Item2)
            {
                await device.SendOutputReportAsync(ToOutputReport(device, continuation), cancellationToken);
            }
        }
示例#5
0
        public static async Task WriteFidoU2FHidMessageAsync([NotNull] this IHidDevice device,
                                                             FidoU2FHidMessage message, CancellationToken cancellationToken)
        {
            if (device == null)
            {
                throw new ArgumentNullException(nameof(device));
            }

            log.Debug($"Sending U2FHid message {message.Command} on channel 0x{message.Channel:X8} with {message.Data.Count} bytes of data");

            var report  = device.CreateOutputReport();
            var packets = MakeOutputPackets(report.Data.Count, message);

            packets.Item1.WriteTo(report.Data);

            await device.SendOutputReportAsync(report, cancellationToken);

            foreach (var continuation in packets.Item2)
            {
                await device.SendOutputReportAsync(ToOutputReport(device, continuation), cancellationToken);
            }
        }
示例#6
0
        static Tuple <InitializationPacket, List <ContinuationPacket> > MakeOutputPackets(
            int paketLength, FidoU2FHidMessage message)
        {
            var availableInInit         = paketLength - InitializationPacket.NoDataSize;
            var availableInContinuation = paketLength - ContinuationPacket.NoDataSize;
            var data = message.Data;

            var init = new InitializationPacket
            {
                ChannelIdentifier = message.Channel,
                CommandIdentifier = (byte)message.Command,
                PayloadLength     = (ushort)data.Count,
                Data = new ArraySegment <byte>(data.Array, data.Offset,
                                               Math.Min(data.Count, availableInInit))
            };

            var  sizeHandled   = init.Data.Count;
            var  continuations = new List <ContinuationPacket>();
            byte sequence      = 0;

            while (sizeHandled < data.Count)
            {
                var continuation = new ContinuationPacket
                {
                    ChannelIdentifier = message.Channel,
                    PaketSequence     = sequence,
                    Data = new ArraySegment <byte>(data.Array, data.Offset + sizeHandled,
                                                   Math.Min(data.Count - sizeHandled, availableInContinuation))
                };

                continuations.Add(continuation);

                sizeHandled += continuation.Data.Count;
                sequence    += 1;
            }

            return(Tuple.Create(init, continuations));
        }
        static Tuple<InitializationPacket, List<ContinuationPacket>> MakeOutputPackets(
            int paketLength, FidoU2FHidMessage message)
        {
            var availableInInit = paketLength - InitializationPacket.NoDataSize;
            var availableInContinuation = paketLength - ContinuationPacket.NoDataSize;
            var data = message.Data;

            var init = new InitializationPacket
            {
                ChannelIdentifier = message.Channel,
                CommandIdentifier = (byte)message.Command,
                PayloadLength = (ushort)data.Count,
                Data = new ArraySegment<byte>(data.Array, data.Offset,
                    Math.Min(data.Count, availableInInit))
            };

            var sizeHandled = init.Data.Count;
            var continuations = new List<ContinuationPacket>();
            byte sequence = 0;
            while (sizeHandled < data.Count)
            {
                var continuation = new ContinuationPacket
                {
                    ChannelIdentifier = message.Channel,
                    PaketSequence = sequence,
                    Data = new ArraySegment<byte>(data.Array, data.Offset + sizeHandled,
                        Math.Min(data.Count - sizeHandled, availableInContinuation))
                };

                continuations.Add(continuation);

                sizeHandled += continuation.Data.Count;
                sequence += 1;
            }

            return Tuple.Create(init, continuations);
        }
示例#8
0
        /// <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;
        }
示例#9
0
        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;
        }
示例#10
0
 static void ThrowForError(FidoU2FHidMessage message)
 {
     var error = GetError(message);
     throw new Exception("Error: " + EnumDescription.Get(error));
 }
示例#11
0
        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);
            }
        }
示例#12
0
        /// <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;
        }
示例#13
0
 public Task WinkAsync(CancellationToken cancellationToken = default(CancellationToken))
 {
     var message = new FidoU2FHidMessage(GetChannel(), U2FHidCommand.Wink);
     return QueryLowLevelAsync(message, cancellationToken);
 }
示例#14
0
        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);
        }