使用C#讀取自然人憑證(MOICA)及數位簽章
最近在開發電子公文系統的線上簽核功能,雖然學校幾年前就已經採購了一批32K RSA Smartcard,也已經可以做一些應用了;但若教職員忘了帶卡片,就沒辦法簽公文了。
因此想多一個「自然人憑證」做數位簽章的功能,讓使用者可以二選一。接著依自然人憑證網站上的申請方法,取得了MOICA API,壓縮檔中包含了DLL、文件、範例(C++),這些DLL都是Unmanaged,因此沒辦法直接讓C#來引用參考。
以下是我寫出來的一些功能,分享出來給大家參考,其中包含PIN碼驗證、取出卡片中的憑證、將訊息丟到卡片做數位簽章、驗證由自然人憑證所簽出來的Signature、驗證身分。由於這些API(DLL)是有版權的(內政部所有),因此不能放上來給大家抓,大家有需要API的話,請至自然人憑證網站申請,申請完畢後,幾天之後,內政部憑證管理中心就會mail給你一組帳號密碼,你就能上去Download了!Download下來後,把那些DLL和你的程式放在同一個目錄下,就可執行了(不必再安裝SafeSign軟體,因為API是用PKCS#11,而不是CSP)。
目前所使用的API版本是5.3,內政部近期將更新為6版,是為了要支援2048-bit的卡片,但把第6版的DLL放到我的程式執行,會有一些衝突,我有機會再來測試看看。目前所遇到的問題是:
- 放到x64的OS(XP, Vista)會無法執行,打電話去內政部詢問,他們也無解(傳給我第6版API,但我測了還是不能使用)
- 使用OCSP時,永遠都回應「2」(找不到憑證),測了三天還是試不出來,再找時間測測LDAP的方式來驗是否被Revoke
To內政部、中華電信:以下的程式是我自己寫出來的,若部分程式碼有侵權,絕對不是故意的,請通知我,立即移除。
/// <summary>
/// 自然人憑證別
/// </summary>
public enum MOICACertType
{
/// <summary>
/// 數位簽章用憑證
/// </summary>
DigitalSignature = 1,
/// <summary>
/// 加解密用憑證
/// </summary>
Encrypt = 2
}
/// <summary>
/// PIN Code回應狀態
/// </summary>
public enum MOICAPINStatus
{
/// <summary>
/// 成功
/// </summary>
OK = 0,
/// <summary>
/// PIN Code太長
/// </summary>
PINTooLong = -65521,
/// <summary>
/// PIN碼嚐試剩餘2次
/// </summary>
PINLeft2 = 25538,
/// <summary>
/// PIN碼嚐試剩餘1次
/// </summary>
PINLeft1 = 25537,
/// <summary>
/// PIN碼被鎖
/// </summary>
PINLeft0 = 25536,
/// <summary>
/// PIN碼被鎖
/// </summary>
PINBlocked = 27011,
/// <summary>
/// 讀取失敗
/// </summary>
Failed = -1,
/// <summary>
/// 卡片未插入
/// </summary>
CardNotInsertted = 29442
}
public class MoicaFunctions
{
#region DllImport
//----------------------------------------------------------------------
/// <summary>
/// 從自然人憑證中取得憑證
/// </summary>
/// <param name="iCertID">卡片內之憑證ID,1=簽章用,2=加解密用</param>
/// <param name="certificate">憑證(輸出)</param>
/// <param name="certificateLength">憑證長度(輸出)</param>
/// <param name="readerName">讀卡機名稱,可設為null自動尋找</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_GPKICardFunction.dll")]
private static extern int GetCertificateFromGPKICard(int iCertID, byte[] certificate, ref int certificateLength, string readerName);
//----------------------------------------------------------------------
/// <summary>
/// 驗證自然人憑證的PIN Code
/// </summary>
/// <param name="PINCode">使用者所輸入的PIN Code</param>
/// <returns>見MOICAPINStatus</returns>
[DllImport("ChtHiSECURE5_GPKICardFunction.dll")]
private static extern int GPKICardVerifyUserPIN(string PINCode);
//----------------------------------------------------------------------
/// <summary>
/// 根據所選擇的讀卡機名稱作初始化的動作,若沒有指定讀卡機名稱則會自動尋找正在使用中的讀卡機並作初使化
/// </summary>
/// <param name="readerName">讀卡機之名稱</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_GPKICardFunction.dll")]
private static extern int GPKICardInitialize(string readerName);
//----------------------------------------------------------------------
/// <summary>
/// 釋放GPKICardInitial所佔用的資源
/// </summary>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_GPKICardFunction.dll")]
private static extern int GPKICardClose();
//----------------------------------------------------------------------
/// <summary>
/// 啟動密碼模組
/// </summary>
/// <param name="moduleDLL">選擇想要採用何種加解密運算模組。即必須輸入欲使用的Module名稱﹝該模組之DLL檔案名稱﹞。</param>
/// <param name="initArgs">建立模組時所需要的參數,通常設定為null</param>
/// <param name="moduleHandle">模組的控制指標(輸出)</param>
/// <returns></returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int InitModule(string moduleDLL, string initArgs, ref int moduleHandle);
//----------------------------------------------------------------------
/// <summary>
/// 釋放Module所佔用的資源
/// </summary>
/// <param name="moduleHandle">模組控制的指標,由InitModule產生</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int CloseModule(int moduleHandle);
//----------------------------------------------------------------------
/// <summary>
/// Session為新版本安全保密函式庫運作的基本單位,此函式的功能為設定一個Session以提供後續的函式使用
/// </summary>
/// <param name="moduleHandle">模組控制的指標,由InitModule產生</param>
/// <param name="iFlags">用以決定產生何種的Session,可分為唯讀﹝CKF_SERIAL_SESSION﹞及可讀可寫﹝CKF_RW_SESSION | CKF_SERIAL_SESSION﹞兩種,端看使用的密碼模組。詳細說明請參考PKCS11。CKF_RW_SESSION = 2。CKF_SERIAL_SESSION=4</param>
/// <param name="UserPIN">PIN Code</param>
/// <param name="iUserPINLength">PIN Code長度</param>
/// <param name="sessionHandle">運作的基本單位Session的控制指標(輸出)</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int InitSession(int moduleHandle, int iFlags, string UserPIN, int iUserPINLength, ref int sessionHandle);
//----------------------------------------------------------------------
/// <summary>
/// 釋放Session所佔用的資源
/// </summary>
/// <param name="moduleHandle">模組的控制指標,由InitModule產生</param>
/// <param name="sessionHandle">運作的基本單位Session的控制指標</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int CloseSession(int moduleHandle, int sessionHandle);
//----------------------------------------------------------------------
/// <summary>
/// 產生密碼模組運算時候所需要的金鑰物件的控制指標
/// </summary>
/// <param name="moduleHandle">模組控制的指標,由InitModule函式得出</param>
/// <param name="sessionHandle">運作的基本單位Session指標</param>
/// <param name="iKeyType">欲產生的金鑰種類,0=私密金鑰,1=公開金鑰,2=對稱式金鑰</param>
/// <param name="KeyID">採用KeyID的方式來取得金鑰物件。若採用pvPara與iParaLength來呼叫則此欄位設為NULL。</param>
/// <param name="iKeyIDLength">KeyID長度。若採用pvPara與iParaLength來呼叫則此欄位設為0。</param>
/// <param name="parameter">採用自行定義的資料來取得金鑰物件。例如:iKeyType=0時,pvPara為選取IC卡中第幾把金鑰,請參考 MakeSignature。iKeyType=1時,pvPara為憑證資料 ,請參考 VerifySignature。iKeyType=2時,pvPara為對稱式金鑰物件 ,請參考 GenerateSessionKey</param>
/// <param name="iParameterLength">自行定義的資料的長度</param>
/// <param name="KeyObjHandle">產生之金鑰物件控制指標(輸出)</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int GetKeyObjectHandle(int moduleHandle, int sessionHandle, int iKeyType, string KeyID, int iKeyIDLength, string parameter, int iParameterLength, ref int KeyObjHandle);
//----------------------------------------------------------------------
/// <summary>
/// 釋放金鑰物件所佔用的資源
/// </summary>
/// <param name="moduleHandle">模組控制的指標,由InitModule函式得出</param>
/// <param name="sessionHandle">運作的基本單位Session指標</param>
/// <param name="KeyObjHandle">金鑰物件控制指標</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int DeleteKeyObject(int moduleHandle, int sessionHandle, int KeyObjHandle);
//----------------------------------------------------------------------
/// <summary>
/// 根據輸入的演算法對資料產生數位簽章函式
/// </summary>
/// <param name="moduleHandle">模組控制的指標,由InitModule函式得出</param>
/// <param name="sessionHandle">運作的基本單位Session指標</param>
/// <param name="algorithm">使用之簽章演算法。目前提供的簽章演算法只有 SHA1_RSA(0x06)</param>
/// <param name="Message">將被簽章的輸入資料</param>
/// <param name="iMessageLength">資料的長度</param>
/// <param name="PrivateKeyObj">簽章時使用之私密金鑰物件指標,於GetKeyObject時產生</param>
/// <param name="Signature">輸出簽章動作後的簽體資料,此處輸入為指標的位址(輸出)</param>
/// <param name="iSignatureLength">輸出或輸入簽體資料的長度,請參看 MakeSignature範例 之呼叫(輸入/輸出)</param>
/// <returns>成功=0</returns>
[DllImport("ChtHiSECURE5_CryptoAPIva.dll")]
private static extern int MakeSignature(int moduleHandle, int sessionHandle, int algorithm, string Message, int iMessageLength, int PrivateKeyObj, byte[] Signature, ref int iSignatureLength);
#endregion DllImport
//----------------------------------------------------------------------
/// <summary>
/// 取得自然人憑證卡片中的憑證
/// </summary>
/// <param name="certType">憑證別(簽章或加密用)</param>
/// <param name="readerName">讀卡機名稱(見機碼HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\Readers下的名稱),傳入null代表自動尋找</param>
/// <returns>X509Certificate2憑證</returns>
public static X509Certificate2 GetCertificateFromMOICACard(MOICACertType certType, string readerName)
{
int iCertLength = 0;
byte[] byteCert = new byte[0];
try
{
GetCertificateFromGPKICard((int)certType, byteCert, ref iCertLength, readerName);
byteCert = new byte[iCertLength];
GetCertificateFromGPKICard((int)certType, byteCert, ref iCertLength, readerName);
return new X509Certificate2(byteCert);
}
catch
{
return null;
}
}
//----------------------------------------------------------------------
/// <summary>
/// 取得自然人憑證卡片中的憑證(自動尋找讀卡機)
/// </summary>
/// <param name="certType">憑證別(簽章或加密用)</param>
/// <returns>X509Certificate2憑證</returns>
public static X509Certificate2 GetCertificateFromMOICACard(MOICACertType certType)
{
return GetCertificateFromMOICACard(certType, null);
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證自然人憑證PIN Code
/// </summary>
/// <param name="strPIN">使用者輸入的PIN Code</param>
/// <param name="readerName">讀卡機名稱(見機碼HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\Readers下的名稱),傳入null代表自動尋找</param>
/// <returns>PIN Code回應</returns>
public static MOICAPINStatus VerifyMOICAPIN(string strPIN, string readerName)
{
try
{
if (GPKICardInitialize(readerName) != 0)
return MOICAPINStatus.Failed;
MOICAPINStatus status = (MOICAPINStatus)GPKICardVerifyUserPIN(strPIN);
GPKICardClose();
return status;
}
catch
{
return MOICAPINStatus.Failed;
}
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證自然人憑證PIN Code(自動尋找讀卡機)
/// </summary>
/// <param name="strPIN">使用者輸入的PIN Code</param>
/// <param name="readerName">讀卡機名稱(見機碼HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\Readers下的名稱),傳入null代表自動尋找</param>
/// <returns>PIN Code回應</returns>
public static MOICAPINStatus VerifyMOICAPIN(string strPIN)
{
return VerifyMOICAPIN(strPIN, null);
}
//----------------------------------------------------------------------
/// <summary>
/// 使用自然人憑證中的簽章憑證來將一個訊息簽章
/// </summary>
/// <param name="PINCode">PIN Code</param>
/// <param name="Message">訊息來源</param>
/// <returns>數位簽章</returns>
public static byte[] GetSignature(string PINCode, string Message)
{
int moduleHandle = 0;
int sessionHandle = 0;
int keyHandle = 0;
string strMsg = Convert.ToBase64String(System.Text.ASCIIEncoding.Default.GetBytes(Message));
try
{
InitModule("CHTGPKICDLL.dll", null, ref moduleHandle);
InitSession(moduleHandle, 0x4, PINCode, PINCode.Length, ref sessionHandle);
GetKeyObjectHandle(moduleHandle, sessionHandle, 0, null, 0, "1", 1, ref keyHandle);
byte[] byteSignature = new byte[0];
int iSignatureLength = 0;
MakeSignature(moduleHandle, sessionHandle, 6, strMsg, strMsg.Length, keyHandle, byteSignature, ref iSignatureLength);
byteSignature = new byte[iSignatureLength];
MakeSignature(moduleHandle, sessionHandle, 6, strMsg, strMsg.Length, keyHandle, byteSignature, ref iSignatureLength);
DeleteKeyObject(moduleHandle, sessionHandle, keyHandle);
CloseSession(moduleHandle, sessionHandle);
CloseModule(moduleHandle);
return byteSignature;
}
catch
{
return new byte[0];
}
}
//----------------------------------------------------------------------
/// <summary>
/// 取得訊息的SHA1值
/// </summary>
/// <param name="Message">訊息來源</param>
/// <returns>SHA1值</returns>
private static string ComputeSHA1(byte[] Message)
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] byteSHA1 = sha1.ComputeHash(Message);
int iLength = byteSHA1.Length;
string strMsg = "";
for (int i = 0; i < iLength; i++)
{
strMsg += byteSHA1[i].ToString("x2");
}
return strMsg;
}
//----------------------------------------------------------------------
/// <summary>
/// 取得訊息的SHA1值
/// </summary>
/// <param name="Message">訊息來源</param>
/// <returns>SHA1值</returns>
private static string ComputeSHA1(string Message)
{
return ComputeSHA1(System.Text.ASCIIEncoding.Default.GetBytes(Message));
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證數位簽章
/// </summary>
/// <param name="Message">訊息</param>
/// <param name="Signature">訊息的簽章</param>
/// <param name="rsaCSP">簽章者的RSACSP(內含用來驗證的公開金鑰)</param>
/// <returns>回傳True代表驗證成功</returns>
public static bool VerifySignature(byte[] Message, byte[] Signature, RSACryptoServiceProvider rsaCSP)
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
return rsaCSP.VerifyData(System.Text.ASCIIEncoding.Default.GetBytes(Convert.ToBase64String(Message)), "SHA1", Signature);
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證數位簽章
/// </summary>
/// <param name="Message">訊息</param>
/// <param name="Signature">訊息的簽章</param>
/// <param name="rsaCSP">簽章者公開的數位憑證</param>
/// <returns>回傳True代表驗證成功</returns>
public static bool VerifySignature(byte[] Message, byte[] Signature, X509Certificate2 x509Certificate2)
{
RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider();
rsaCSP.FromXmlString(x509Certificate2.PublicKey.Key.ToXmlString(false));
return rsaCSP.VerifyData(System.Text.ASCIIEncoding.Default.GetBytes(Convert.ToBase64String(Message)), "SHA1", Signature);
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證數位簽章
/// </summary>
/// <param name="Message">訊息</param>
/// <param name="Signature">訊息的簽章(Base64String)</param>
/// <param name="rsaCSP">簽章者公開的數位憑證</param>
/// <returns>回傳True代表驗證成功</returns>
public static bool VerifySignature(string Message, string Signature, X509Certificate2 x509Certificate2)
{
return VerifySignature(System.Text.ASCIIEncoding.Default.GetBytes(Message), Convert.FromBase64String(Signature), x509Certificate2);
}
//----------------------------------------------------------------------
/// <summary>
/// 驗證使用者身分
/// </summary>
/// <param name="PINCode">PIN Code</param>
/// <param name="strIDNO">身分證字號</param>
/// <param name="PINStatus">若發生錯誤,則回應錯誤代碼</param>
/// <returns>驗證是否成功</returns>
public static bool Authenticate(string PINCode, string strIDNO, ref MOICAPINStatus PINStatus)
{
if ( (PINStatus = VerifyMOICAPIN(PINCode)) != MOICAPINStatus.OK)
return false;
X509Certificate2 cert = GetCertificateFromMOICACard(MOICACertType.DigitalSignature);
if (cert == null)
return false;
DateTime now = DateTime.Now;
if (now > cert.NotAfter || now < cert.NotBefore)
return false;
X509Extension extension = cert.Extensions["2.5.29.9"];
if (extension == null)
return false;
string strID = Encoding.ASCII.GetString(extension.RawData, extension.RawData.Length - 4, 4);
return strIDNO.EndsWith(strID);
}
}
小目 說:
就是我是先建置一個VS專案
裡面有一個WEB FORM的專案,和一個CLASS的專案
我在WEB FORM去寫呼叫CLASS專案的METHOD
也就是您以上的範例來跑
它可以抓出憑證資料,並驗證PIN CODE
但我把此專案發行到本機的WEB,然後把VS開掉
用IIS的方式去呼叫剛才在VS可以RUN的網頁
它就抓不到憑證了~~
這和我沒包裝成ACTIVEX有關嗎
回應
Blave 回應:
八月 11th, 2010 at 16:14:16
我記得好像要包成activex,而且好像要用「簽署程式碼」的憑證去包activex
太久沒碰這塊了,不太記得了~
您有試出來,還請您分享給弟啊
回應
小目 說:
你好,請教一下
我用了這個範例去試
vs runtime 的時候,它可以抓到資料
但我把它發行到本機的網站去試,它就抓不到憑證了~
這是什麼問題呢
不是一樣都在本機嗎 @@
回應
Blave 回應:
八月 11th, 2010 at 15:37:35
抱歉…不太懂「它發行到本機的網站去試,它就抓不到憑證了」
可以詳加說明嗎?
回應
gattaca 說:
網路有一篇
自行開發之自然人憑證SDK(不需中華電信Hisecure API)
請問作者是你嗎?
有支援2048bit的新卡嗎?
回應
sk 說:
感謝!Blave Huang 這樣我有點方向了!
回應
sk 說:
您好 想請教您 自然人憑證要如何整合到 web的應用
簽章,驗證網站會員登入的部份
因完全摸不到頭緒~
麻煩您了~
回應
Blave 回應:
十一月 20th, 2009 at 14:24:25
要讓網頁可以驗證自然人憑證,通常都是要寫成ActiveX,用ATL或MFC來寫,您可以去自然人憑證申請MOICA API(要是機關單位,所以要發函),將這個API整合到您的ActiveX元件,就可以用了。
不過老實說,弟沒有寫過ActiveX,所以也沒辦法深入跟您分享了。
回應
Roy 說:
很抱歉又來打擾了!~
請問使用Win32的方法大概是怎樣的一個流程?
跟使用ActiveX有什麼樣的不同?
您所分享的函式庫範例中
[DllImport("ChtHiSECURE5_GPKICardFunction.dll")]是否為動態載入嗎?
這些DLL是不是要先註冊到Client的電腦?
非常感謝!!
回應
Blave Huang 回應:
七月 9th, 2009 at 12:12:20
我想Win32和ActiveX的流程應該都一樣,就是把資料塞給卡片,叫它給你一串的數位簽章,然後你就可以拿這串簽章值去儲存或其他應用…。
那些Dll必須放在Client的電腦裡面,要和.exe檔放在一起,或許放在system32目錄下也行,但我沒試過就是了。
回應
Kim 說:
沒想到本網頁有檔飆記語法
以下是我試過的
1.傳入一個的完整SignedInfo區塊
2.僅傳入DigestValue的值
回應
Kim 說:
Hi , 再請教個問題,簽章時呼叫的MakeSignature(),就我所知道的電子簽章是傳入一個訊息摘要,但究竟是要傳入何種形式的字串內容?就我測試過的簽出來都有點問題。以下是我試過的
1.傳入一個的完整tag區塊
2.僅傳入DigestValue的值
試問正確傳入簽章的 訊息摘要應該是哪一種呢?
回應
Roy 說:
我是將您的C# Class改成VB來進行開發(VS2005)
假設使用者電腦都有.net framework
我還是必須要用到ActiveX+Script嗎?有可能不用到嗎?
如果沒有其它方式,冒昧地請問有ActiveX及Script範例可以參考嗎?
我的Mail : iori945@gmail.com
回應
Blave Huang 回應:
七月 3rd, 2009 at 09:02:12
數位簽章一定要把程式放到Client執行,所以一定要用ActiveX才行!
我們的數位簽章是應用到電子公文系統,電子公文是用Win32的方式,所以我們沒有ActiveX的範例囉…所以也沒去研究ActiveX怎麼寫呢…
加油!!
回應
Kim 說:
多謝你的連結!
不過因為自然人憑證的私鑰的Key是無法直接取得的,所以MSDN上的範例不太適用。我剛查詢了,簽章取回的byte array 是需要以Base64String編碼的。
回應
Roy 說:
真的是非常的感謝您熱心的回答!
Smartcard Reader Driver 安裝無誤。
我是做web Form的程式,作法上會有什麼樣的不同嗎?
我只能用ActiveX + Script才能達到我要的功能嗎?
因為我不會ActiveX及Script,有其他的作法嗎?萬分感激!~
回應
Blave Huang 回應:
七月 2nd, 2009 at 16:32:10
原來您是用aspx啊…那麼數位簽章就一定要用activex了
建議用c++(mfc, atl)開發
不然用C#開發,使用者電腦如果沒有.net framework,還是一樣不能用…
回應
Roy 說:
黃先生 你好 :
我已經取得HiSECURE 5.3 Windows(C語言)標準版
但是更正過DLL檔後,Local及Server都無法執行
請問一下我要怎麼知道DllImport是否成功?
謝謝!~
回應
Blave Huang 回應:
七月 2nd, 2009 at 16:12:05
您好:
所有DLL檔和主程式.exe是否放在同一個目錄呢?
另外,Smartcard Reader Driver是否安裝成功?
正常而言應該是可以執行的,而且讀卡機的燈會閃…
是不是有遺漏了什麼呢?
回應
Kim 說:
Hi 黃先生您好,
再請叫個問題,當呼叫 MakeSignature(int moduleHandle, int sessionHandle, int algorithm, string Message, int iMessageLength, int PrivateKeyObj, byte[] Signature, ref int iSignatureLength);,執行簽章的作業之後,簽回來的資料都存在於 Signature,請問這個要以何種編碼方式進行轉換,才能轉為符合XML Signature格式的資料內容?
回應
Blave Huang 回應:
七月 2nd, 2009 at 15:55:48
抱歉…小弟沒轉成 XML Signature過,不過您或許可以參考這個:
http://msdn.microsoft.com/zh-tw/library/system.security.cryptography.xml.signature.aspx
回應
Roy 說:
謝謝你相當迅速的回覆了!~
我是安裝http://moica.nat.gov.tw/html/download_1.htm中的
憑證匯入工具MOICA_HiCOS_Setup
安裝後再到C:\Windows\System32目錄下將檔案取出來(DLL檔名有些許不同)
引用到您所分享的函式中
在本機端(VS的執行環境)執行正常
將程式放上IIS後,就出現 " 並未將物件參考設定為物件的執行個體 "的錯誤
請問我可能少了什麼動作,還是DLL的不同所造成的?
在此再次感謝!謝謝!~
回應
Blave Huang 回應:
七月 1st, 2009 at 14:20:53
看起來應該是DLL不同的樣子…
您可能還是需要那些DLL檔呦~~
回應
Roy 說:
黃先生你好,
請問一下 API的部份是應該要安裝SafeSign還是HiCos?
因為我是新手可以提供範例嗎?
在此先謝謝你的回答!
回應
Blave Huang 回應:
七月 1st, 2009 at 08:30:33
讀取卡片有兩種方式最方便,一種是CSP,這是一種Microsoft提出的介面,只要廠商的API符合CSP介面,應用程式就可以去操作卡片,就像Outlook也可以叫卡片來數位簽章,所以Safesign是CSP。
另一種方式是PKCS#11,通常廠商會給你C++的檔案;或是DLL檔,當然也要有說明文件才能去使用DLL。這個範例就是使用PKCS#11,然而範例中使用的DLL是內政部所有,因此我不可放到網路上給大家抓,您可自行到以下網址申請API:
http://61.60.9.15/apply/action/basicWaymarkDispatcher?waymark=register
或是從moica網站進入後也找得到。
範例的話…上面這個就是範例了,您缺少的應該是API的DLL...
回應
Kim 說:
Hi 黃先生你好,
在使用憑證加簽時,一直有碰到個問題就加簽完後的byte array,以 Convert.ToBase64String 取回時,這個值應該就是SignatureValue對嗎?
我取得的這個值 看起來似乎是錯的,因為最後一個字元並不是" = "
請問你先前開發時有碰到類似問題嗎?
回應
Blave Huang 回應:
六月 11th, 2009 at 19:00:47
Base64String的最後面不一定會是 "=",您可以再把Base64String再轉回byte[](記得應該是Convert.FromBase64String()),如果發生錯誤,代表那串base64是有問題的!
我會轉為Base64是為了顯示給使用者看,及存入資料庫較方便。
回應