因專案需求需要讀取自然人憑證,找不到相關範例,不是重Windows憑證管理取出來,是直接於讀卡機溝通。
有範例連到憑證但是不知改如何取出憑證內資料。
下列是範例:
// 讀取指令
var apduCommand = new PCSC.Iso7816.CommandApdu(PCSC.Iso7816.IsoCase.Case4Short, oReader.ActiveProtocol)
此段之後程式就會錯誤,不知道改如何取資料。
麻煩大神能提供能實際運用程式碼。
// 執行
var oAdpuProfileResponse = oReader.Transmit(apduCommand);
錯誤訊息:
**
PCSC.Iso7816.InvalidApduException: 'Invalid APDU.'
**
using PCSC.Iso7816;
using System;
using System.Linq;
using System.Reflection.PortableExecutable;
class Program
{
public static void Main()
{
string cReader;
// 尋找本機讀卡機設備
using (var oReaders = PCSC.ContextFactory.Instance.Establish(PCSC.SCardScope.User))
{
cReader = oReaders.GetReaders().FirstOrDefault();
if (string.IsNullOrEmpty(cReader))
{
Console.WriteLine("# 系統找不到任何讀卡機,請重新檢查硬體。");
return;
}
else
{
Console.Clear();
Console.WriteLine("# 歡迎使用台灣自然人憑證檢視程式");
Console.WriteLine($"# 共找到 {oReaders.GetReaders().Count()} 部設備並使用「{cReader}」讀卡機,程式運行期間請勿任意移除設備。");
}
}
// 建立事件監控
using (var oMonitor = PCSC.Monitoring.MonitorFactory.Instance.Create(PCSC.SCardScope.System))
{
oMonitor.CardRemoved += (oSender, oArgs) => { Console.WriteLine("# 偵測到晶片卡移除。"); };
oMonitor.CardInserted += (oSender, oArgs) =>
{
Console.WriteLine("# 偵測到晶片卡插入。");
GetIDCardInfo(cReader); // 讀取自然人憑證資料
};
oMonitor.MonitorException += (oSender, oArgs) =>
{
Console.WriteLine("# 讀卡機被移除或是讀取晶片卡出現異常,請重新啟動程式。");
System.Environment.Exit(0); // 強制退出
};
oMonitor.Start(cReader);
// 有可能執行程式前讀卡機與卡片就都已經準備好,如此一來並不會觸發事件,因此先強制執行一次讀取看看
try
{
GetIDCardInfo(cReader);
}
catch
{
// 若有讀取出錯就直接跳過(可能是未插卡)
}
// 設定離開程序
ConsoleKeyInfo oKey;
do
{
Console.WriteLine("# 若要離開程式,請按下 ESC 鍵。");
oKey = Console.ReadKey(true);
} while (oKey.Key != ConsoleKey.Escape);
}
// 程式結束
Console.WriteLine("# 程式結束。");
}
/// <summary>
/// 讀取台灣自然人憑證資料
/// </summary>
public static void GetIDCardInfo(string cReader)
{
using (var oContext = PCSC.ContextFactory.Instance.Establish(PCSC.SCardScope.User))
using (var oReader = new PCSC.Iso7816.IsoReader(
context: oContext,
readerName: cReader,
mode: PCSC.SCardShareMode.Shared,
protocol: PCSC.SCardProtocol.Any
))
{
Console.WriteLine("-----");
// 初始化自然人憑證卡
var oAdpuInit = new PCSC.Iso7816.CommandApdu(PCSC.Iso7816.IsoCase.Case4Short, oReader.ActiveProtocol)
{
CLA = 0x00,
INS = 0xA4,
P1 = 0x04,
P2 = 0x00,
Data = new byte[] { 0x3F, 0x00, 0x5F, 0x01, 0x00 }
};
Console.WriteLine($"@ APDU InitCard: {System.BitConverter.ToString(oAdpuInit.ToArray())}");
// 取得初始化自然人憑證回應
var oAdpuInitResponse = oReader.Transmit(oAdpuInit);
Console.WriteLine($"@ Response: SW1={oAdpuInitResponse.SW1.ToString("X")}|SW2={oAdpuInitResponse.SW2.ToString("X")}");
// 檢查回應是否正確(9000)
if (!oAdpuInitResponse.SW1.Equals(0x90) && !oAdpuInitResponse.SW2.Equals(0x00))
{
Console.WriteLine("-----");
Console.WriteLine("# 晶片卡並非自然人憑證,請換張卡片試看看。");
return;
}
// 讀取指令
var apduCommand = new PCSC.Iso7816.CommandApdu(PCSC.Iso7816.IsoCase.Case4Short, oReader.ActiveProtocol)
{
CLA = 0xFF,
Instruction = InstructionCode.GetData,
P1 = 0x00,
P2 = 0x00,
Le = 0 // We don't know the ID tag size
};
// 傳送指令並接收回應
var oAdpuProfileResponse = oReader.Transmit(apduCommand);
// 解析自然人憑證資訊
if (oAdpuProfileResponse.HasData)
{
// 解析自然人憑證資訊
var responseData = oAdpuProfileResponse.GetData();
// 處理 responseData,根據自然人憑證的規格來解析資料
// 例如,假設資料格式為固定長度的姓名、身分證號碼、出生日期等
var nameBytes = responseData.Take(20).ToArray();
var idNumberBytes = responseData.Skip(20).Take(10).ToArray();
var birthdateBytes = responseData.Skip(30).Take(8).ToArray();
// 其他資訊的處理類似
var name = System.Text.Encoding.UTF8.GetString(nameBytes).Trim();
var idNumber = System.Text.Encoding.UTF8.GetString(idNumberBytes).Trim();
var birthdate = System.Text.Encoding.UTF8.GetString(birthdateBytes).Trim();
// 列印資訊
Console.WriteLine($"姓名:{name}");
Console.WriteLine($"身分證號:{idNumber}");
Console.WriteLine($"出生日期:{birthdate}");
// 其他資訊的列印類似
}
}
}
}