package de.persosim.simulator.protocols.pace; import java.security.InvalidParameterException; import java.util.Arrays; import de.persosim.simulator.crypto.CryptoSupport; import de.persosim.simulator.crypto.CryptoSupportAes; import de.persosim.simulator.crypto.CryptoUtil; import de.persosim.simulator.protocols.GenericOid; import de.persosim.simulator.utils.HexString; public class PaceOid extends GenericOid implements Pace { public static final int HASHCODEMULTIPLICATOR = 3; protected String idString; /*----------------------------------------------------------------*/ /** * This constructor constructs a {@link PaceOid} based on a byte array representation of a Pace OID. * @param oidByteArray the byte array representation of a Pace OID */ public PaceOid(byte[] oidByteArray) { super(oidByteArray); //check if provided OID is indeed PaceOid idString = getStringRepresentation(oidByteArray); if(idString == null) { throw new IllegalArgumentException("PACE OID " + HexString.encode(oidByteArray) + " is invalid or unknown (not supported)"); } } /*----------------------------------------------------------------*/ /** * This method returns the OID's byte indicating the key agreement and mapping * @return the OID's byte indicating the key agreement and mapping */ public byte getKeyAgreementAndMappingAsByte() { return this.oidByteArray[8]; } /** * This method returns the OID's byte indicating the symmetric cipher and key size * @return the OID's byte indicating the symmetric cipher and key size */ public byte getSymmetricCipherAndKeySizeAsByte() { return this.oidByteArray[9]; } /*----------------------------------------------------------------*/ /** * This method returns the common name of the used key agreement. * @return the common name of the used key agreement */ public String getKeyAgreementName() { switch (this.getKeyAgreementAndMappingAsByte()) { case Pace.ECDH_GM: return "ECDH"; default: throw new InvalidParameterException("no or invalid key agreement selected"); } } /** * This method returns the mapping used with the key agreement. * @return the mapping used with the key agreement */ public String getMappingName() { switch (this.getKeyAgreementAndMappingAsByte()) { case Pace.ECDH_GM: return "GM"; default: throw new InvalidParameterException("no or invalid mapping selected"); } } /** * This method returns the mapping function to be used for mapping. * @return the mapping function to be used for mapping */ public Mapping getMapping() { switch (this.getKeyAgreementAndMappingAsByte()) { case Pace.ECDH_GM: return new GenericMappingEcdh(); default: throw new InvalidParameterException("selected mapping not supported"); } } protected CryptoSupport cryptoSupportCache = null; /** * This method returns the {@link CryptoSupport} object that provides support for the selected symmetric cipher. * @return the {@link CryptoSupport} object that provides support for the selected symmetric cipher */ public CryptoSupport getCryptoSupport() { if(cryptoSupportCache == null) { cryptoSupportCache = createCryptoSupport(); } return cryptoSupportCache; } protected CryptoSupport createCryptoSupport() { String cipherName = getSymmetricCipherAlgorithmNameModePadding(); String macName = getMacName(); switch (CryptoUtil.getCipherNameAsString(cipherName)) { case "AES": return new CryptoSupportAes(cipherName, macName); default: throw new IllegalArgumentException("algorithm " + cipherName + " is unknown or not supported"); } } /*----------------------------------------------------------------*/ /** * This method returns the symmetric cipher algorithm's name, mode and padding in the form cipher/mode/padding. * @return the symmetric cipher algorithm's name, mode and padding */ public String getSymmetricCipherAlgorithmNameModePadding() { switch (this.getSymmetricCipherAndKeySizeAsByte()) { case Pace.AES_CBC_CMAC_128: return "AES/CBC/NoPadding"; case Pace.AES_CBC_CMAC_192: return "AES/CBC/NoPadding"; case Pace.AES_CBC_CMAC_256: return "AES/CBC/NoPadding"; default: throw new InvalidParameterException("no or invalid symmetric cipher selected"); } } /** * This method returns the symmetric cipher algorithm's name, e.g. "AES". * @return the symmetric cipher algorithm's name */ public String getSymmetricCipherAlgorithmName() { return CryptoUtil.getCipherNameAsString(this.getSymmetricCipherAlgorithmNameModePadding()); } /** * This method returns the symmetric cipher algorithm's mode of operation, e.g. "CBC". * @return the symmetric cipher algorithm's mode of operation */ public String getSymmetricCipherAlgorithmMode() { return CryptoUtil.getCipherAlgorithmModeAsString(this.getSymmetricCipherAlgorithmNameModePadding()); } /** * This method returns the symmetric cipher algorithm's padding, e.g. "NoPadding". * @return the symmetric cipher algorithm's padding */ public String getSymmetricCipherAlgorithmPadding() { return CryptoUtil.getCipherAlgorithmPaddingAsString(this.getSymmetricCipherAlgorithmNameModePadding()); } /** * This method returns the key length in Bytes as indicated by the OID. * @return the key length in Bytes as indicated by the OID */ public int getSymmetricCipherKeyLengthInBytes() { switch (this.getSymmetricCipherAndKeySizeAsByte()) { case Pace.AES_CBC_CMAC_128: return 16; case Pace.AES_CBC_CMAC_192: return 24; case Pace.AES_CBC_CMAC_256: return 32; default: throw new InvalidParameterException("no or invalid symmetric cipher selected"); } } /** * This method returns the MAC name as indicated by the OID. * @return the MAC name as indicated by the OID */ public String getMacName() { switch (this.getSymmetricCipherAlgorithmName()) { case "AES": return "aescmac"; default: throw new InvalidParameterException("no or invalid mac selected"); } } /** * This method returns the name of the message digest as indicated by the OID. * @return the name of the message digest as indicated by the OID */ public String getMessageDigestName() { int keyLengthInBytes; keyLengthInBytes = this.getSymmetricCipherKeyLengthInBytes(); if(keyLengthInBytes <= 20) { return "SHA-1"; } if(keyLengthInBytes <= 32) { return "SHA-256"; } throw new NullPointerException("no message digest specified"); } /*----------------------------------------------------------------*/ public String getStringRepresentation(byte[] oidByteArray) { if (Arrays.equals(oidByteArray, id_PACE_ECDH_GM_AES_CBC_CMAC_128)) return id_PACE_ECDH_GM_AES_CBC_CMAC_128_STRING; if (Arrays.equals(oidByteArray, id_PACE_ECDH_GM_AES_CBC_CMAC_192)) return id_PACE_ECDH_GM_AES_CBC_CMAC_192_STRING; if (Arrays.equals(oidByteArray, id_PACE_ECDH_GM_AES_CBC_CMAC_256)) return id_PACE_ECDH_GM_AES_CBC_CMAC_256_STRING; return null; } @Override public String getIdString() { return idString; } }