使用SunMSCAPI签署文档并禁止“输入PIN”对话框

我正在开发一个使用证书令牌签署文档的java代码。 到目前为止,一切都很好,但我想抑制“输入引脚”对话框,因为我存储用户的引脚,所以他/她不需要每次都输入它。 这里的真正问题是此代码将以批处理模式运行(无用户交互)。 我知道一旦键入,键可能在内存中,因此不需要在短时间内再次键入。 但我不能依赖它,我需要提供PIN。 这是我到目前为止的代码(它只是一个样本,它可能不完整也不起作用):

protected KeyStore loadKeyStoreFromSmartCard() { keyStore = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); keyStore.load(null, null); return keyStore; } public void signDocument(byte[] conteudoParaAssinar, String certAlias) { char[] pass = (char[]) null; PrivateKey key = (PrivateKey) loadKeyStoreFromSmartCard.getKey(certAlias, pass); Certificate[] chain = loadKeyStoreFromSmartCard(true).getCertificateChain(certAlias); CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC"); X509Certificate cert = (X509Certificate) chain[0]; CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1); gen.addCertificatesAndCRLs(certsAndCRLs); CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar); CMSSignedData signed = gen.generate(data, true, "SunMSCAPI"); byte[] envHex = signed.getEncoded(); } 

编辑

我听说过CryptSetProvParam PP_KEYEXCHANGE_PIN女巫可能是解决方案,但我不知道如何从java调用它。 我找到的所有例子都是针对.net的。

我实现了类似于此的一次,但不幸的是智能卡驱动程序是错误的,因此驱动程序试图提出驱动程序本身有时实现的本机PIN回调。 但是我们假设你的司机做得更好。

首先,您需要实现一个CallbackHandler ,该文档对该概念进行了很好的概述。 在你的情况下,这是有趣处理的PasswordCallback案例。

接下来,按如下方式创建KeyStore (省略exception处理)

 Provider provider = Security.getProvider("SunMSCAPI"); CallbackHandler cbh = // your implementation KeyStore.ProtectionParameter protection = new KeyStore.CallbackHandlerProtection(cbh); //get a handle of the CAPI KeyStore as before KeyStore.Builder keystoreBuilder = KeyStore.Builder.newInstance("Windows-MY", provider, protection); KeyStore store = keystoreBuilder.getKeyStore(); 

然后,要访问私钥,请执行以下操作:

 KeyStore.Entry ke = store.getEntry(alias, null); if (!(ke instanceof KeyStore.PrivateKeyEntry)) throw new RuntimeException("The entry is not a private key."); PrivateKey key = ((KeyStore.PrivateKeyEntry) ke).getPrivateKey(); 

提供程序将自动生成要发送到CallbackHandler的相应PasswordCallback 。 处理回调时,您只需传递缓存的密码即可。

毋庸置疑,密码缓存通常不受欢迎;)

MS CryptoAPI不提供指定PIN的统一方式。 如果可能,您唯一的选择是从CyrptoAPI切换到PKCS#11 – PKCS#11要求您在代码中“登录”设备并在代码中提供PIN。

更新: 某些硬件供应商提供的某些 CSP(加密服务提供商)模块允许您调用特殊的CryptoAPI函数(CSPSetProvParam, http://msdn.microsoft.com/en-us/library/aa379858%28v=VS.85%29 .aspx )并将PIN传递给它。 如果硬件的CSP支持这种设置PIN的方法,那么您需要联系供应商以获取信息,如果是,则确切的参数ID是什么等。