How to Implement USB Token-Based Security with Oracle JDK

ClientSample.java

import static org.apache.commons.codec.binary.Base64.encodeBase64;

import static java.lang.System.out;

import java.io.InputStream;
import java.security.AuthProvider;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;

import sun.security.pkcs11.SunPKCS11;

public final class ClientSample {
  private static final Pattern DN_PATTERN = Pattern.compile("CN=([^,]*),");

  public static void main(final String[] args) {
    final InputStream in = getClass().getResourceAsStream("/config/pkcs11.cfg");

    final AuthProvider provider = new SunPKCS11(in); // token-specific

    final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); // token-specific

    final KeyStore ks = KeyStore.getInstance("PKCS11", provider); // connect to token

    ks.load(in, "password".toCharArray());

    final String alias = ks.aliases().nextElement();

    final Key key = ks.getKey(alias, null);

    cipher.init(Cipher.ENCRYPT_MODE, key);

    final X509Certificate cert = (X509Certificate) ks.getCertificate(alias);

    final Matcher matcher = DN_PATTERN.matcher(cert.getSubjectX500Principal().getName()); // content is user name

    out.println(encodeBase64(cipher.doFinal(matcher.group(1).getBytes())));
  }

}

config/pkcs11.cfg

name=FeitianPKCS#11
library=ngp11v211.dll

ServerSample.java

import static org.apache.commons.codec.binary.Base64.decodeBase64;

import static java.lang.System.out;

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

public final class ServerSample {

  public static void main(final String[] args) {
    final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // token-specific

    final KeyFactory factory = KeyFactory.getInstance("RSA");

    final X509EncodedKeySpec spec = new X509EncodedKeySpec(decodeBase64(args[0]).getBytes())); // args[0] is the key

    final PublicKey key = factory.generatePublic(spec);

    cipher.init(Cipher.DECRYPT_MODE, key);

    out.println(cipher.doFinal(decodeBase64(args[1]).getBytes())); // args[1] is the password
  }

}

If you client is an applet, you will also need a java.policy file:

grant {
  permission java.lang.RuntimePermission "accessClassInPackage.sun.security.pkcs11";
  permission java.util.PropertyPermission "java.home", "read";
  permission java.security.SecurityPermission "authProvider.SunPKCS11-FeitianPKCS";
};

One thought on “How to Implement USB Token-Based Security with Oracle JDK

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s