21 Oct 2012

JavaCard STK usage example: One Time Password


Today I'd like to show you one of the ways of JavaCard STK applet usage. In the world of information systems a good authentication procedure is one of the most important topics. And one of the most reliable ways to do it is two factor authentication usage. The most known two factor authentication is One Time Password (OTP).

OTP - is a password which is valid only for one authentication session. Password validity could be also limited in time. The advantage of One Time Password is inability to
use the same password twice. Hence if password is intercepted somehow it will be useless.

The aim of this post is not to give you all pros and cons of OTP. I'll let my reader dig it on his own :) Instead I want to show you how OTP could be implemented in JavaCard STK applet.

The main problem of OTP for end-users is inability to keep in mind all One Time Passwords therefore we need some additional device to generate it on the fly - JavaCard STK applet.

Let's have a look how we can do it. First of all we will implement 2 menu items for Init key and Get next password as:

/**
 * Constructor of the applet
 */
public otp() {
    // Get the reference of the applet ToolkitRegistry object
    reg = ToolkitRegistry.getEntry ();

    menuGetNextPasswd = new byte[] { (byte) 'G', (byte) 'e', (byte) 't',
            (byte) ' ', (byte) 'n', (byte) 'e', (byte) 'x', (byte) 't',
            (byte) ' ', (byte) 'p', (byte) 'a', (byte) 's', (byte) 's',
            (byte) 'w', (byte) 'o', (byte) 'r', (byte) 'd' };
    menuInitKey = new byte[] { (byte) 'I', (byte) 'n', (byte) 'i',
            (byte) 't', (byte) ' ', (byte) 'k', (byte) 'e', (byte) 'y' };
    // Define the applet Menu Entry
    idMenuGetNextPasswd = reg
            .initMenuEntry (menuGetNextPasswd, (short) 0,
                            (short) menuGetNextPasswd.length,
                            PRO_CMD_SELECT_ITEM, false, (byte) 0, (short) 0);
    idMenuInitKey = reg
            .initMenuEntry (menuInitKey, (short) 0,
                            (short) menuInitKey.length, (byte) 0, false,
                            (byte) 0, (short) 0);

    // during instantiation of the applet key isn't initialized yet
    isKeyInitialized = false;
    // fixing key length to 20 bytes
    key = new byte[KEY_LENGTH];

    tmpBuf = new byte[KEY_LENGTH_ASCII];
}

Then we have to implement processToolkit() method to treat menu items selections:


public void processToolkit(byte event) {
    EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler ();

    // Manage the request following the MENU SELECTION event type
    if (event == EVENT_MENU_SELECTION) {
        // Get the selected item
        byte selectedItemId = envHdlr.getItemIdentifier ();

        // Perform the required service following the menuGetNextPasswd
        // selected item
        if (selectedItemId == idMenuGetNextPasswd) {
            getNextPasswd ();
        }

        // Perform the required service following the menuInitKey selected
        // item
        if (selectedItemId == idMenuInitKey) {
            initKey ();
        }
    }
}

The initKey() method will request initial key which will be used for next password calculation. The method getNextPasswd() could be implemented in the following way:


/**
 * Manage the menuGetNextPasswd selection
 */
private void getNextPasswd() {
    if (isKeyInitialized) {
        try {
            hash = MessageDigest.getInstance (MessageDigest.ALG_SHA, true);
            hash.doFinal (key, (short) 0, (short) key.length
                         , tmpBuf, (short) 0);
            Util.arrayCopyNonAtomic (tmpBuf, (short) 0, key, (short) 0,
                                     (short) key.length);
            displayHexBuffer (key, (short) key.length);
        } catch (CryptoException e) {
        }
    } else {
        displayText(msgKeyNotInited);
    }
    return;
}

After password generation we need to verify it somehow on the server side. Let's implement authentication server simulator. I'll show you only proof-of-concept implementation, a simple GUI application wich requires password and verifies it. It looks like this:



I've used Clojure for it:


(def md (MessageDigest/getInstance "SHA-1"))

(defn ascii2hex [ascii-str]
  (map #(Integer/parseInt % 16) (map #(apply str %) (partition 2 ascii-str))))

(defn bytes2hexStr [bytes]
  (apply str
         (map #(.toUpperCase %)
              (map #(format "%02x" %)
                   (map #(bit-and 0xFF %) (seq bytes))))))

(defn get-next-password [key-str]
  (. md reset)
  (bytes2hexStr
   (seq
    (. md digest
       (into-array Byte/TYPE
                   (map #(.byteValue %)
                        (ascii2hex key-str)))))))

The full source code of the applet and authentication server simulator could be found on my GitHub page.

Peace on you! :)


No comments: