3

証明書トークンを使用してドキュメントに署名する 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用です。

4

2 に答える 2

2

これに似たものを一度実装しましたが、残念ながらスマート カード ドライバーにバグがあり、ドライバー自体に実装されているネイティブ PIN コールバックを呼び出そうとすることがありました。しかし、あなたのドライバーがその点で優れていると仮定しましょう。

まず、CallbackHandlerを実装する必要があります。ドキュメントでは、概念の概要がよく説明されています。あなたの場合、処理するのが興味深いのはPasswordCallbackケースです。

次に、次のように作成KeyStoreします(例外処理は省略)

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();

PasswordCallbackプロバイダーは、に送信される適切な を自動的に生成しますCallbackHandler。コールバックを処理するときは、キャッシュされたパスワードを渡すだけです。

言うまでもなく、パスワードのキャッシュは一般的に嫌われています;)

于 2011-07-08T01:47:31.840 に答える
1

MS CryptoAPI には、PIN を指定する方法がまったくありません。唯一のオプションは、可能であれば CryptoAPI から PKCS#11 に切り替えることです。PKCS#11 では、コードでデバイスに「ログオン」し、コードで PIN も提供する必要があります。

更新:一部のハードウェア ベンダーが出荷する一部の CSP (暗号化サービス プロバイダー) モジュールでは、特別な CryptoAPI 関数 (CryptSetProvParam、https: //docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt) を呼び出すことができます。 -cryptsetprovparam ) に PIN を渡します。ハードウェアの CSP がこの方法で PIN を設定する方法をサポートしているかどうか、サポートしている場合は正確なパラメーター ID などについては、ベンダーに問い合わせる必要があります。標準の SunMSCAPI プロバイダを使用する Java アプリケーション。

于 2011-06-27T17:56:34.857 に答える