title: How to get KeyStore from usb token in Java
body: <p>I have a SafeNet 5100 eToken already with a valid certificate in it that I use to access a web application from my company that requires it (multi-factor authentication).</p>
  
  <p>I'm creating a desktop application to access this website. I am already able to add the website's certificate to the <code>TrustStore</code> and get my certificate into a <code>KeyStore</code>.</p>
  
  <p>What I've got so far is:</p>
  
  <pre><code>System.setProperty("javax.net.ssl.trustStore", "U:\\Certificados\\efau.truestore");
  System.setProperty("javax.net.ssl.trustStoreType", "jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "oiadad");
  
  KeyManagerFactory kFac;
  SSLContext sslContext;
  SSLSocketFactory sockFactory = null;
  KeyStore ks;
  
  try {
      // load keystore present in windows and print aliases found (only one, so nextElement always prints same information (name of certificate inside usb token I want to open))
      ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
      ks.load(null, null);
      System.out.println(ks.aliases().nextElement());
      System.out.println(ks.aliases().nextElement());
  
      // try to load my certificate specifically from all certificates and passes necessary token password to it
      InputStream in = IOUtils.toInputStream(ks.aliases().nextElement(), "UTF-8");
      System.out.println(in);
      ks.load(in, password);
  
      // print certificate to check if I have it
      System.out.println(ks.getCertificate(ks.aliases().nextElement()));
  
      // get ssl context and key manager factory
      sslContext = SSLContext.getInstance("SSL", "SunJSSE");
      kFac = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
      kFac.init(ks,null);
  
      sslContext.init(kFac.getKeyManagers(), null, null);
      sockFactory = sslContext.getSocketFactory();
  
      // start connection with website
      HttpsURLConnection conn = (HttpsURLConnection)new URL(&lt;my-https-url&gt;).openConnection();
      conn.setRequestMethod("GET");
      conn.setDoInput(true);
      conn.setSSLSocketFactory(sockFactory);
  
      int responseCode = conn.getResponseCode();
      System.out.println("RESPONSE: " + responseCode);
  
  } catch (KeyStoreException e) {
      e.printStackTrace();
  } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
  } catch (CertificateException e) {
      e.printStackTrace();
  } catch (IOException e) {
      e.printStackTrace();
  } catch (NoSuchProviderException e) {
      e.printStackTrace();
  } catch (UnrecoverableKeyException e1) {
      e1.printStackTrace();
  } catch (KeyManagementException e1) {
      e1.printStackTrace();
  }
  </code></pre>
  
  <p>When I run this code I get:</p>
  
  <pre><code>javax.net.ssl.SSLHandshakeException: Received fatal alert: decrypt_error
      at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
      at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source)
      at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source)
      at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
      at java.net.HttpURLConnection.getResponseCode(Unknown Source)
      at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
      at receita.system.monitoring.Ping.main(Ping.java:313)
  </code></pre>
  
  <p>And I get this error when I type the correct password for the token and when I type a wrong one, so I think I'm never passing it the password in the correct way.</p>
  
  <p>Why am I receiving the exception?</p>
  
  <p>--------- Updated ---------</p>
  
  <p>I created a config file with the following information pointing to my PKCS11.dll library:</p>
  
  <pre><code>name = Aladdin
  library = C:/WINDOWS/system32/eTPKCS11.dll
  </code></pre>
  
  <p>And in the main function I add:</p>
  
  <pre><code>SunPKCS11 newProvider = new SunPKCS11("u:/Certificados/etpkcs11.cfg");
  Provider a = newProvider;
  Security.addProvider(a);
  
  KeyStore ks;
  try {
      ks = KeyStore.getInstance("PKCS11");
      ...
  }
  </code></pre>
  
  <p>And now I'm getting this as an error:</p>
  
  <pre><code>java.security.KeyStoreException: PKCS11 not found
      at java.security.KeyStore.getInstance(Unknown Source)
      at receita.system.monitoring.Ping.main(Ping.java:292)
  Caused by: java.security.NoSuchAlgorithmException: PKCS11 KeyStore not available
      at sun.security.jca.GetInstance.getInstance(Unknown Source)
      at java.security.Security.getImpl(Unknown Source)
      ... 2 more
  </code></pre>
  
  <p>I also tried to modify Keystore.getInstance to:</p>
  
  <pre><code>ks = KeyStore.getInstance("PKCS11", a);
  </code></pre>
  
  <p>and then I get this different error:</p>
  
  <pre><code>java.security.KeyStoreException: PKCS11 not found
      at java.security.KeyStore.getInstance(Unknown Source)
      at receita.system.monitoring.Ping.main(Ping.java:292)
  Caused by: java.security.NoSuchAlgorithmException: no such algorithm: PKCS11 for provider SunPKCS11-Aladdin
      at sun.security.jca.GetInstance.getService(Unknown Source)
      at sun.security.jca.GetInstance.getInstance(Unknown Source)
      at java.security.Security.getImpl(Unknown Source)
      ... 2 more
  </code></pre>
  
  <p>--------- Updated 2 (Working Code) ---------</p>
  
  <p>My final working code is:</p>
  
  <pre><code>System.setProperty("javax.net.ssl.trustStore", "U:\\Certificados\\efau.truestore");
  System.setProperty("javax.net.ssl.trustStoreType", "jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "oiadad");
  
  KeyManagerFactory kFac;
  SSLContext sslContext;
  SSLSocketFactory sockFactory = null;
  
  SunPKCS11 providerMSCAPI = new SunPKCS11("u:/Certificados/etpkcs11.cfg");
  Provider a = providerMSCAPI;
  Security.addProvider(a);
  
  KeyStore ks;
  try {
      ks = KeyStore.getInstance("PKCS11");
  
      ks.load(null, password);
  
      InputStream in = IOUtils.toInputStream(ks.aliases().nextElement(), "UTF-8");
      ks.load(in, password);
  
  
      sslContext = SSLContext.getInstance("SSL", "SunJSSE");
      kFac = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
      kFac.init(ks,null);
  
      sslContext.init(kFac.getKeyManagers(), null, null);
      sockFactory = sslContext.getSocketFactory();
  
      HttpsURLConnection conn = (HttpsURLConnection)new URL(/*&lt;my-url&gt;*/).openConnection();
      conn.setRequestMethod("GET");
      conn.setDoInput(true);
      conn.setSSLSocketFactory(sockFactory);
  
      int responseCode = conn.getResponseCode();
  
      InputStream inputstream = conn.getInputStream();
      InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
      BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
  
      String line = null;
      String htmlResponse = "";
  
      while ((line = bufferedreader.readLine()) != null) {
          htmlResponse += line + "\n";
      }
  
  } catch (KeyStoreException e) {
      e.printStackTrace();
  } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
  } catch (CertificateException e) {
      e.printStackTrace();
  } catch (IOException e) {
      e.printStackTrace();
  } catch (NoSuchProviderException e) {
      e.printStackTrace();
  } catch (UnrecoverableKeyException e1) {
      e1.printStackTrace();
  } catch (KeyManagementException e1) {
      e1.printStackTrace();
  }
  </code></pre>
  
  <p>And I have to or set the debug argument in run configurations:</p>
  
  <pre><code>-Djava.security.debug=sunpkcs11
  </code></pre>
  
  <p>Or set the slot in the .cfg file:</p>
  
  <pre><code>name=SafeNet
  library=C:\Windows\System32\eTPKCS11.dll
  slot=4
  </code></pre>