private async Task SendRequestAsync(FidoHidMsgType msgType, byte[] data = null) { if (data == null) { data = new byte[0]; } var size = data.Length; var payloadData = data.Take(HidReportSize - 7).ToArray(); var payloadBuilder = new ByteArrayBuilder(); payloadBuilder.Append(_channelId); payloadBuilder.Append((byte)msgType); payloadBuilder.Append((byte)(size >> 8 & 0xff)); payloadBuilder.Append((byte)(size & 0xff)); payloadBuilder.Append(payloadData); payloadBuilder.AppendZerosTill(HidReportSize); var report = _hidDevice.CreateReport(); report.Data = payloadBuilder.GetBytes(); if (!await _hidDevice.WriteReportAsync(report, HidTimeoutMs).ConfigureAwait(false)) { throw new FidoException(FidoError.InterruptedIO, "Error writing to token"); } var remainingData = data.Skip(HidReportSize - 7).ToArray(); var seq = 0; while (remainingData.Length > 0) { payloadData = remainingData.Take(HidReportSize - 5).ToArray(); payloadBuilder.Clear(); payloadBuilder.Append(_channelId); payloadBuilder.Append((byte)(0x7f & seq)); payloadBuilder.Append(payloadData); payloadBuilder.AppendZerosTill(HidReportSize); report = _hidDevice.CreateReport(); report.Data = payloadBuilder.GetBytes(); if (!await _hidDevice.WriteReportAsync(report, HidTimeoutMs).ConfigureAwait(false)) { throw new FidoException(FidoError.InterruptedIO, "Error writing to token"); } remainingData = remainingData.Skip(HidReportSize - 5).ToArray(); seq++; } }
public byte[] GetBytes() { var bytes = _byteArrayBuilder.GetBytes(); var outBytes = new ByteArrayBuilder(); byte currentByte = 0; var currentBit = 7; for (int i = 0; i < _byteArrayBuilder.Length; i++) { currentByte |= (byte)(bytes[i] << currentBit); currentBit--; if (currentBit < 0) { outBytes.Append(currentByte); currentByte = 0; currentBit = 7; } } if (currentBit < 7) { outBytes.Append(currentByte); } return(outBytes.GetBytes()); }
public async Task <byte[]> ApduMessageAsync(FidoInstruction instruction, FidoParam1 param1 = FidoParam1.None, FidoParam2 param2 = FidoParam2.None, byte[] data = null) { if (data == null) { data = new byte[0]; } var dataLen = data.Length; var adpu = new ByteArrayBuilder(); adpu.Append(new byte[] { 0x00, //CLA byte (byte)instruction, (byte)param1, (byte)param2, //some tokens only work with extended length (byte)(dataLen >> 16 & 0xff), (byte)(dataLen >> 8 & 0xff), (byte)(dataLen & 0xff) }); adpu.Append(data); //max response size: 65536 byte //needed for hyperfido adpu.Append(new byte[] { 0x00, 0x00 }); var apduData = adpu.GetBytes(); var response = await CallAsync(FidoHidMsgType.ApduMessage, apduData).ConfigureAwait(false); var responseData = response.Take(response.Length - 2).ToArray(); var status = response.Skip(response.Length - 2).Take(2).Reverse().ToArray(); var statusCode = (FidoApduResponse)BitConverter.ToUInt16(status, 0); if (statusCode != FidoApduResponse.Ok) { throw new FidoException(statusCode); } return(responseData); }
private async Task <byte[]> ReadResponseAsync(FidoHidMsgType msgType) { HidReport report; FidoHidMsgType recvdMsgType; do { report = await _hidDevice.ReadReportAsync(HidTimeoutMs).ConfigureAwait(false); if (report.ReadStatus != HidDeviceData.ReadStatus.Success) { throw new FidoException(FidoError.InterruptedIO, $"Error reading from token: {report.ReadStatus}"); } } while (!CheckHeader(report.Data, out recvdMsgType)); if (msgType != recvdMsgType) { throw new FidoException(FidoError.ProtocolViolation, $"received {recvdMsgType} instead of {msgType}"); } var dataLength = (report.Data[5] << 8) + report.Data[6]; var payloadData = report.Data.Skip(7).Take(Math.Min(dataLength, HidReportSize)).ToArray(); var payload = new ByteArrayBuilder(); payload.Append(payloadData); dataLength -= (int)payload.Length; var seq = 0; while (dataLength > 0) { do { report = await _hidDevice.ReadReportAsync(HidTimeoutMs).ConfigureAwait(false); if (report.ReadStatus != HidDeviceData.ReadStatus.Success) { throw new FidoException(FidoError.InterruptedIO, $"Error reading from token: {report.ReadStatus}"); } } while (!CheckHeader(report.Data, out recvdMsgType)); if ((recvdMsgType & FidoHidMsgType.CommandFlag) > 0) { throw new FidoException(FidoError.ProtocolViolation, "fragmented message continuation had command flag set"); } if ((byte)recvdMsgType != (seq & (byte)FidoHidMsgType.SequenceIdMask)) { throw new FidoException(FidoError.ProtocolViolation, $"received out-of-sequence message: Recvd:0x{(byte)recvdMsgType:X}, seq-nr:{seq}"); } seq++; payloadData = report.Data.Skip(5).Take(Math.Min(dataLength, HidReportSize)).ToArray(); dataLength -= payloadData.Length; payload.Append(payloadData); } return(payload.GetBytes()); }