iT邦幫忙

0

請教大神讀卡機讀取自人憑證C#完整範例

  • 分享至 

  • xImage

請教大神讀卡機讀取自人憑證C#完整範例

因專案需求需要讀取自然人憑證,找不到相關範例,不是重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}");
                // 其他資訊的列印類似
            }



        }
    }
}

看更多先前的討論...收起先前的討論...
黃彥儒 iT邦高手 1 級 ‧ 2024-03-25 16:15:53 檢舉
有考慮直接接政府的跨平台程式嗎?那個似乎是走HTTP,好像要申請
DennisLu iT邦研究生 1 級 ‧ 2024-03-25 17:05:50 檢舉
"此段之後程式就會錯誤,不知道改如何取資料。"

沒給錯誤訊息資料,路過看到的人,就算很熟這塊,沒給也看看就走了。
spitsnow iT邦新手 5 級 ‧ 2024-03-25 20:30:40 檢舉
@黃彥儒
請問是哪邊有資訊能參考?
spitsnow iT邦新手 5 級 ‧ 2024-03-25 20:30:57 檢舉
@DennisLu
// 執行
var oAdpuProfileResponse = oReader.Transmit(apduCommand);
錯誤訊息:
**
PCSC.Iso7816.InvalidApduException: 'Invalid APDU.'
**
froce iT邦大師 1 級 ‧ 2024-03-26 08:14:49 檢舉
如果你只是要簽章和解密的話,不用動到直接和讀卡機溝通,裝hicos,然後用httpclient打HiPKI Local Server 就能處理了。
網頁範例。
https://gpkiapi.nat.gov.tw/PKCS7Verify/

申請好像是會給你api手冊而已。不清楚。
其實自己去讀HiPKI的源碼就行了。node.js寫的。
C:\Program Files (x86)\HiPKILocalSignServer
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友回答

立即登入回答