標籤:位置 message 失敗 sig 設定 blob 擴充 長度 hang
其實CSP主要是對容器裡的金鑰組操作的,和認證關係不大。容器裡的金鑰組有兩種類型:一種是AT_KEYEXCHANGE,表示加密的金鑰組,一種是AT_SIGNATURE表示簽名的金鑰組。由於美國的出口限制,在MS的CSP中加密的金鑰組可以取的密鑰最大長度通常會比簽名的金鑰組短。通常加密的金鑰組只會用於加密,簽名的金鑰組只會用於簽名,由於某些原因(例如產生認證請求),加密的金鑰組也可以用於簽名。我把AT_KEYEXCHANGE和AT_SIGNATURE看作是容器裡的兩個位置。在智慧卡CSP中可以把認證寫入容器中,和加密的金鑰組對應的認證寫到AT_KEYEXCHANGE位置中,和簽名的金鑰組對應的認證寫到AT_SIGNATURE位置中。這裡判斷依據是認證的公開金鑰和金鑰組的公開金鑰相同,而不是認證中的密鑰用法擴充。使用Crypto API可以根據認證庫裡的認證的CERT_KEY_PROV_INFO_PROP_ID找到相對應得容器裡的金鑰組。CRYPT_KEY_PROV_INFO中的dwKeySpec就是指容器裡的金鑰組類型。如果在CSP實現的層次根據認證的密鑰用法擴充來限制是否能夠加密和簽名,要先讀出認證,這個操作比較慢,估計實現者比較少採用。 事實上,明華EKey的CSP的AT_KEYEXCHANGE和AT_SIGNATURE類型的金鑰組都是既可以加密也可以簽名的(CryptDecrypt和CryptSignHash是沒問題的,沒怎麼測過CryptImportKey,不知道是不是簽名的金鑰組能不能成功匯入工作階段金鑰)。我沒有和你的版本一樣的xcsp_eclib.dll,我使用了一個稍微舊一點的版本的來測試。我測試了CryptDecryptMessage函數,發現如果是簽名金鑰組不管我認證的密鑰用法擴充如何設定則解密總是會失敗(用MS的CSP也一樣)。而使用加密金鑰對則可以成功。雖然OUTLOOK可能不是使用CryptDecryptMessage來解密CMS的EnvelopedData的,但是我相信最終都會調用CSP的CryptImportKey解出對稱金鑰,再解密的。CryptDecryptMessage傳給CryptImportKey的是一個Simple-Key BLOBs。我的測試發現EKey好像總是使用加密的金鑰組來解密。這可能是這個Simple-Key BLOBs的結構有問題導致解密失敗或者EKey的CSP的CryptImportKey有BUG導致解密失敗。 看來,如果要使得認證既能加密也能簽名,必須首先保證使用的是加密金鑰對。產生加密金鑰對可以在產生認證請求的時候使用Xenroll來設定,至於使用PKCS#12檔案匯入的方式要取決於使用的軟體是根據什麼來判斷應該建立什麼類型的金鑰組。
Windows密鑰容器和認證的關係