be.fedict.eid.applet.service.impl.UserIdentifierUtil.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.applet.service.impl.UserIdentifierUtil.java

Source

/*
 * eID Applet Project.
 * Copyright (C) 2008-2009 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.eid.applet.service.impl;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Utility class for user identifier construction.
 * 
 * @author Frank Cornelis
 * 
 */
public class UserIdentifierUtil {

    private static final Log LOG = LogFactory.getLog(UserIdentifierUtil.class);

    private UserIdentifierUtil() {
        super();
    }

    /**
     * Gives back a unique user identifier given an X509 certificate.
     * 
     * @param signingCertificate
     * @return
     */
    public static String getUserId(X509Certificate signingCertificate) {
        X500Principal userPrincipal = signingCertificate.getSubjectX500Principal();
        String name = userPrincipal.toString();
        int serialNumberBeginIdx = name.indexOf("SERIALNUMBER=");
        if (-1 == serialNumberBeginIdx) {
            throw new SecurityException("SERIALNUMBER not found in X509 CN");
        }
        int serialNumberValueBeginIdx = serialNumberBeginIdx + "SERIALNUMBER=".length();
        int serialNumberValueEndIdx = name.indexOf(",", serialNumberValueBeginIdx);
        if (-1 == serialNumberValueEndIdx) {
            serialNumberValueEndIdx = name.length();
        }
        String userId = name.substring(serialNumberValueBeginIdx, serialNumberValueEndIdx);
        return userId;
    }

    public static final String HMAC_ALGO = "HmacSHA1";

    /**
     * Gives back a non-reversible citizen identifier (NRCID).
     * 
     * @param userId
     *            the primary user identifier, i.e. the national registry
     *            number.
     * @param orgId
     *            the optional organization identifier.
     * @param appId
     *            the optional application identifier.
     * @param secret
     *            the application specific secret. Should be at least 128 bit
     *            long. Encoded in hexadecimal format.
     * @return
     */
    public static String getNonReversibleCitizenIdentifier(String userId, String orgId, String appId,
            String secret) {
        if (null == secret) {
            throw new IllegalArgumentException("secret key is null");
        }
        /*
         * Avoid XML formatting issues introduced by some web.xml XML editors.
         */
        secret = secret.trim();
        if (null != orgId) {
            orgId = orgId.trim();
        } else {
            LOG.warn("it is advised to use an orgId");
        }
        if (null != appId) {
            appId = appId.trim();
        } else {
            LOG.warn("it is advised to use an appId");
        }

        /*
         * Decode the secret key.
         */
        byte[] secretKey;
        try {
            secretKey = Hex.decodeHex(secret.toCharArray());
        } catch (DecoderException e) {
            LOG.error("secret is not hexadecimal encoded: " + e.getMessage());
            throw new IllegalArgumentException("secret is not hexadecimal encoded");
        }
        if ((128 / 8) > secretKey.length) {
            /*
             * 128 bit is seen as secure these days.
             */
            LOG.warn("secret key is too short");
            throw new IllegalArgumentException("secret key is too short");
        }

        /*
         * Construct the HMAC input sequence.
         */
        String input = userId;
        if (null != appId) {
            input += appId;
        }
        if (null != orgId) {
            input += orgId;
        }
        byte[] inputData = input.getBytes();

        SecretKey macKey = new SecretKeySpec(secretKey, HMAC_ALGO);
        Mac mac;
        try {
            mac = Mac.getInstance(macKey.getAlgorithm());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("HMAC algo not available: " + e.getMessage());
        }
        try {
            mac.init(macKey);
        } catch (InvalidKeyException e) {
            LOG.error("invalid secret key: " + e.getMessage(), e);
            throw new RuntimeException("invalid secret");
        }
        mac.update(inputData);
        byte[] resultHMac = mac.doFinal();
        String resultHex = new String(Hex.encodeHex(resultHMac)).toUpperCase();
        return resultHex;
    }
}