All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jmrtd.lds.PACEInfo Maven / Gradle / Ivy

There is a newer version: 0.8.1
Show newest version
/*
{ * JMRTD - A Java API for accessing machine readable travel documents.
 *
 * Copyright (C) 2006 - 2015  The JMRTD team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 * 
 * $Id: PACEInfo.java 1580 2015-07-10 21:15:03Z martijno $
 */

package org.jmrtd.lds;

import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;

import javax.crypto.spec.DHParameterSpec;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.crypto.agreement.DHStandardGroups;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.jmrtd.Util;

/**
 * PACE Info object as per SAC TR 1.01, November 11, 2010.
 * 
 * @author The JMRTD team ([email protected])
 * 
 * @version $Revision: 1580 $
 * 
 * @since 0.5.0
 */
public class PACEInfo extends SecurityInfo {

	private static final long serialVersionUID = 7960925013249578359L;

	/** Generic mapping and Integrated mapping. */
	public enum MappingType { GM, IM };

	/** Standardized domain parameters. Based on Table 6. */
	public static final int
	PARAM_ID_GFP_1024_160 = 0,
	PARAM_ID_GFP_2048_224 = 1,
	PARAM_ID_GFP_2048_256 = 2,
	/* RFU 3 - 7 */
	PARAM_ID_ECP_NIST_P192_R1 = 8,
	PARAM_ID_ECP_BRAINPOOL_P192_R1 = 9,
	PARAM_ID_ECP_NIST_P224_R1 = 10,
	PARAM_ID_ECP_BRAINPOOL_P224_R1 = 11,
	PARAM_ID_ECP_NST_P256_R1 = 12,
	PARAM_ID_ECP_BRAINPOOL_P256_R1 = 13,
	PARAM_ID_ECP_BRAINPOOL_P320_R1 = 14,
	PARAM_ID_ECP_NIST_P384_R1 = 15,
	PARAM_ID_ECP_BRAINPOOL_P384_R1 = 16,
	PARAM_ID_ECP_BRAINPOOL_P512_R1 = 17,
	PARAM_ID_ECP_NIST_P521_R1 = 18;
	/* RFU 19-31 */

	private static final DHParameterSpec
	PARAMS_GFP_1024_160 = Util.toExplicitDHParameterSpec(DHStandardGroups.rfc5114_1024_160),
	PARAMS_GFP_2048_224 = Util.toExplicitDHParameterSpec(DHStandardGroups.rfc5114_2048_224),
	PARAMS_GFP_2048_256 = Util.toExplicitDHParameterSpec(DHStandardGroups.rfc5114_2048_256);

	private static final ECParameterSpec
	PARAMS_ECP_NIST_P192_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("secp192r1")),
	PARAMS_ECP_NIST_P224_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("secp224r1")),
	PARAMS_ECP_NIST_P256_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("secp256r1")),
	PARAMS_ECP_NIST_P384_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("secp384r1")),
	PARAMS_ECP_NIST_P521_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("secp521r1")),
	PARAMS_ECP_BRAINPOOL_P192_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp192r1")),
	PARAMS_ECP_BRAINPOOL_P224_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp224r1")),
	PARAMS_ECP_BRAINPOOL_P256_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp256r1")),
	PARAMS_ECP_BRAINPOOL_P320_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp320r1")),
	PARAMS_ECP_BRAINPOOL_P384_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp384r1")),
	PARAMS_ECP_BRAINPOOL_P512_R1 = Util.toExplicitECParameterSpec(ECNamedCurveTable.getParameterSpec("brainpoolp512r1"));

	private String protocolOID;
	private int version;
	private int parameterId;

	/**
	 * Creates a PACEInfo instance.
	 * 
	 * @param oid the OID
	 * @param version should be 2
	 * @param parameterId either a standardized domain parameter id from table 6 or a proprietary domain parameter
	 */
	public PACEInfo(String oid, int version, int parameterId) {
		if (!checkRequiredIdentifier(oid)) { throw new IllegalArgumentException("Invalid OID"); }
		if (version != 2) { throw new IllegalArgumentException("Invalid version, must be 2"); }
		this.protocolOID = oid;
		this.version = version;
		this.parameterId = parameterId;
	}

	public static PACEInfo createPACEInfo(byte[] paceInfoBytes) {
		/*
		 * FIXME: Should add a constructor to PACEInfo that takes byte[] or InputStream, or
		 * align this with SecurityInfo.getInstance().
		 */
		ASN1Sequence sequence = ASN1Sequence.getInstance(paceInfoBytes);
		String oid = ((ASN1ObjectIdentifier)sequence.getObjectAt(0)).getId();
		ASN1Primitive requiredData = sequence.getObjectAt(1).toASN1Primitive();
		ASN1Primitive optionalData = null;
		if (sequence.size() == 3) {
			optionalData = sequence.getObjectAt(2).toASN1Primitive();
		}

		int version = ((ASN1Integer)requiredData).getValue().intValue();
		int parameterId = -1;
		if (optionalData != null) {
			parameterId = ((ASN1Integer)optionalData).getValue().intValue();
		}

		return new PACEInfo(oid, version, parameterId);
	}

	@Override
	public String getObjectIdentifier() {
		return protocolOID;
	}

	public int getVersion() {
		return version;
	}

	public int getParameterId() {
		return parameterId;
	}

	@Override
	ASN1Primitive getDERObject() {
		ASN1EncodableVector vector = new ASN1EncodableVector();

		/* Protocol */
		vector.add(new ASN1ObjectIdentifier(protocolOID));

		/* Required data */
		vector.add(new ASN1Integer(version));

		/* Optional data */
		if (parameterId >= 0) {
			vector.add(new ASN1Integer(parameterId));
		}
		return new DLSequence(vector);
	}

	public String toString() {
		StringBuffer result = new StringBuffer();
		result.append("PaceInfo");
		result.append("[");
		result.append("protocol: " + toProtocolOIDString(protocolOID));
		result.append(", version: " + version);
		if (parameterId >= 0) {
			result.append(", parameterId: " + toStandardizedParamIdString(parameterId));
		}
		result.append("]");
		return result.toString();
	}

	public int hashCode() {
		return 1234567891
				+ 7 * protocolOID.hashCode()
				+ 5 * version
				+ 3 * parameterId;
	}

	public boolean equals(Object other) {
		if (other == null) { return false; }
		if (other == this) { return true; }
		if (!PACEInfo.class.equals(other.getClass())) { return false; }
		PACEInfo otherPACEInfo = (PACEInfo)other;
		return getDERObject().equals(otherPACEInfo.getDERObject());
	}

	public static boolean checkRequiredIdentifier(String oid) {
		return toMappingType(oid) != null;
	}

	/*
	 * FIXME: perhaps we should introduce an enum for PACE identifiers (with a String toOID() method),
	 * so that we can get rid of static methods below. -- MO
	 */

	public static MappingType toMappingType(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)) {	
			return MappingType.GM;
		} else if (ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return MappingType.IM;
		}
		//		return null;
		throw new NumberFormatException("Unknown OID: \"" + oid + "\"");
	}

	public static String toKeyAgreementAlgorithm(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return "DH";
		} else if (ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return "ECDH";
		}
		//		return null;
		throw new NumberFormatException("Unknown OID: \"" + oid + "\"");
	}

	public static String toCipherAlgorithm(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)				
				) {
			return "DESede";
		} else if (ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return "AES";
		}
		//			return null;
		throw new NumberFormatException("Unknown OID: \"" + oid + "\"");
	}

	public static String toDigestAlgorithm(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)) {
			return "SHA-1";
		} else if (ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return "SHA-256";
		}
		//			return null;
		throw new NumberFormatException("Unknown OID: \"" + oid + "\"");
	}

	public static int toKeyLength(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)
				|| ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)
				) {
			return 128;
		} else if (ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)) {
			return 192;
		} else if (ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)
				|| ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) {
			return 256;
		} else {
			// return -1;
			throw new NumberFormatException("Unknown OID: \"" + oid + "\"");
		}
	}

	public static AlgorithmParameterSpec toParameterSpec(int stdDomainParam) {
		switch (stdDomainParam) {
		case PARAM_ID_GFP_1024_160: return PARAMS_GFP_1024_160;
		case PARAM_ID_GFP_2048_224: return PARAMS_GFP_2048_224;
		case PARAM_ID_GFP_2048_256: return PARAMS_GFP_2048_256;
		case PARAM_ID_ECP_NIST_P192_R1: return PARAMS_ECP_NIST_P192_R1;
		case PARAM_ID_ECP_BRAINPOOL_P192_R1:return PARAMS_ECP_BRAINPOOL_P192_R1;
		case PARAM_ID_ECP_NIST_P224_R1: return PARAMS_ECP_NIST_P224_R1;
		case PARAM_ID_ECP_BRAINPOOL_P224_R1: return PARAMS_ECP_BRAINPOOL_P224_R1;
		case PARAM_ID_ECP_NST_P256_R1: return PARAMS_ECP_NIST_P256_R1;
		case PARAM_ID_ECP_BRAINPOOL_P256_R1: return PARAMS_ECP_BRAINPOOL_P256_R1;
		case PARAM_ID_ECP_BRAINPOOL_P320_R1: return PARAMS_ECP_BRAINPOOL_P320_R1;
		case PARAM_ID_ECP_NIST_P384_R1: return PARAMS_ECP_NIST_P384_R1;
		case PARAM_ID_ECP_BRAINPOOL_P384_R1: return PARAMS_ECP_BRAINPOOL_P384_R1;
		case PARAM_ID_ECP_BRAINPOOL_P512_R1: return PARAMS_ECP_BRAINPOOL_P512_R1;
		case PARAM_ID_ECP_NIST_P521_R1: return PARAMS_ECP_NIST_P521_R1;
		default: throw new NumberFormatException("Unknown standardized domain parameters " + stdDomainParam);
		}
	}

	private String toStandardizedParamIdString(int stdDomainParam) {
		switch (stdDomainParam) {
		case PARAM_ID_GFP_1024_160: /* 0 */ return "1024-bit MODP Group with 160-bit Prime Order Subgroup";
		case PARAM_ID_GFP_2048_224: /* 1 */ return "2048-bit MODP Group with 224-bit Prime Order Subgroup";
		case PARAM_ID_GFP_2048_256: /* 2 */ return "2048-bit MODP Group with 256-bit Prime Order Subgroup";
		/* 3 - 7 RFU */
		case PARAM_ID_ECP_NIST_P192_R1: /* 8 */return "NIST P-192 (secp192r1)";
		case PARAM_ID_ECP_BRAINPOOL_P192_R1:/* 9 */ return "BrainpoolP192r1";
		case PARAM_ID_ECP_NIST_P224_R1: /* 10 */ return "NIST P-224 (secp224r1)";
		case PARAM_ID_ECP_BRAINPOOL_P224_R1: /* 11 */ return "BrainpoolP224r1";
		case PARAM_ID_ECP_NST_P256_R1: /* 12 */ return "NIST P-256 (secp256r1)";
		case PARAM_ID_ECP_BRAINPOOL_P256_R1: /* 13 */ return "BrainpoolP256r1";
		case PARAM_ID_ECP_BRAINPOOL_P320_R1: /* 14 */ return "BrainpoolP320r1";
		case PARAM_ID_ECP_NIST_P384_R1: /* 15 */ return "NIST P-384 (secp384r1)";
		case PARAM_ID_ECP_BRAINPOOL_P384_R1: /* 16 */ return "BrainpoolP384r1";
		case PARAM_ID_ECP_BRAINPOOL_P512_R1: /* 17 */ return "BrainpoolP512r1";
		case PARAM_ID_ECP_NIST_P521_R1: /* 18 */ return "NIST P-521 (secp521r1)";
		/* 19-31 RFU */
		default: return Integer.toString(stdDomainParam);
		}
	}

	private String toProtocolOIDString(String oid) {
		if (ID_PACE_DH_GM_3DES_CBC_CBC.equals(oid)) { return "id-PACE-DH-GM-3DES-CBC-CBC"; }
		if (ID_PACE_DH_GM_AES_CBC_CMAC_128.equals(oid)) { return "id-PACE-DH-GM-AES-CBC-CMAC-128"; }
		if (ID_PACE_DH_GM_AES_CBC_CMAC_192.equals(oid)) { return "id-PACE-DH-GM-AES-CBC-CMAC-192"; }
		if (ID_PACE_DH_GM_AES_CBC_CMAC_256.equals(oid)) { return "id-PACE-DH-GM-AES-CBC-CMAC-256"; }
		if (ID_PACE_DH_IM_3DES_CBC_CBC.equals(oid)) { return "id-PACE-DH-IM-3DES-CBC-CBC"; }
		if (ID_PACE_DH_IM_AES_CBC_CMAC_128.equals(oid)) { return "id-PACE-DH-IM-AES-CBC-CMAC-128"; }
		if (ID_PACE_DH_IM_AES_CBC_CMAC_192.equals(oid)) { return "id-PACE-DH-IM-AES-CBC-CMAC-192"; }
		if (ID_PACE_DH_IM_AES_CBC_CMAC_256.equals(oid)) { return "id-PACE_DH-IM-AES-CBC-CMAC-256"; }
		if (ID_PACE_ECDH_GM_3DES_CBC_CBC.equals(oid)) { return "id-PACE_ECDH-GM-3DES-CBC-CBC"; }
		if (ID_PACE_ECDH_GM_AES_CBC_CMAC_128.equals(oid)) { return "id-PACE-ECDH-GM-AES-CBC-CMAC-128"; }
		if (ID_PACE_ECDH_GM_AES_CBC_CMAC_192.equals(oid)) { return "id-PACE-ECDH-GM-AES-CBC-CMAC-192"; }
		if (ID_PACE_ECDH_GM_AES_CBC_CMAC_256.equals(oid)) { return "id-PACE-ECDH-GM-AES-CBC-CMAC-256"; }
		if (ID_PACE_ECDH_IM_3DES_CBC_CBC.equals(oid)) { return "id-PACE-ECDH-IM_3DES-CBC-CBC"; }
		if (ID_PACE_ECDH_IM_AES_CBC_CMAC_128.equals(oid)) { return "id-PACE-ECDH-IM-AES-CBC-CMAC-128"; }
		if (ID_PACE_ECDH_IM_AES_CBC_CMAC_192.equals(oid)) { return "id-PACE-ECDH-IM-AES-CBC-CMAC-192"; }
		if (ID_PACE_ECDH_IM_AES_CBC_CMAC_256.equals(oid)) { return "id-PACE-ECDH-IM-AES-CBC-CMAC-256"; }
		return oid;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy