package de.persosim.simulator.securemessaging; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.globaltester.cryptoprovider.Crypto; import de.persosim.simulator.crypto.CryptoSupport; import de.persosim.simulator.crypto.CryptoUtil; import de.persosim.simulator.crypto.SendSequenceCounter; import de.persosim.simulator.exception.CryptoException; import de.persosim.simulator.processing.UpdatePropagation; public class SmDataProviderTr03110 implements SmDataProvider { @Override public Class<? extends UpdatePropagation> getKey() { return SmDataProvider.class; } private Cipher cipher; private SecretKeySpec keyEnc; private Mac mac; private SecretKeySpec keyMac; private boolean pendingCommandApdu; /** * SendSequenceCounter according to BSI TR-03110 */ private SendSequenceCounter ssc; public SmDataProviderTr03110(SecretKeySpec cipherKey, SecretKeySpec macKey, SendSequenceCounter newSsc) { keyEnc = cipherKey; keyMac = macKey; try { cipher = getCipher(keyEnc.getAlgorithm()); // XXX AMY use new Crypto wrappers here // According to developer consens we want to create wrapper objects that // encapsulate Cipher or Mac resp. together with the relevant key. These // objects can be passed as method parameters and encapsulate all // different behavior by overloading. Thus protocols dont need to switch // on objecttype while the OID classes work as factory for these // wrappers. // The differentiation between Cipher and Mac wrappers is intended to be // according to the JavaCryptoApi. // {@link CryptoSupport} if (CryptoUtil.getCipherNameAsString(cipher.getAlgorithm()).equals( "DESede")) { // 3DES mac = Mac.getInstance("ISO9797ALG3", Crypto.getCryptoProvider()); } else { //AES mac = Mac.getInstance(keyMac.getAlgorithm(), Crypto.getCryptoProvider()); } } catch (NoSuchAlgorithmException e) { throw new CryptoException(e); } ssc = newSsc; pendingCommandApdu = false; } public SmDataProviderTr03110(SecretKeySpec cipherKey, SecretKeySpec macKey) { this(cipherKey, macKey, new SendSequenceCounter(getCipher(cipherKey.getAlgorithm()).getBlockSize())); } private static Cipher getCipher(String algorithm) { try { return Cipher.getInstance(algorithm, Crypto.getCryptoProvider()); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new CryptoException(e); } } @Override public void init(SmDataProvider prev) { // nothing to be done here // complete initialization done within constructor, no need to know the predecessor } @Override public void nextIncoming() { if(!pendingCommandApdu) { ssc.increment(); pendingCommandApdu = true; } } @Override public void nextOutgoing() { if(pendingCommandApdu) { ssc.increment(); pendingCommandApdu = false; } } @Override public Cipher getCipher() { return cipher; } @Override public IvParameterSpec getCipherIv() { byte[] cipherIvPlain; //XXX AMY use new Crypto wrappers here (details see above) if (CryptoUtil.getCipherNameAsString(cipher.getAlgorithm()).equals("DESede")) { //3DES cipherIvPlain = new byte[8]; } else { //AES cipherIvPlain = CryptoSupport.encryptWithIvZero(cipher, ssc.toByteArray(), keyEnc); } return new IvParameterSpec(cipherIvPlain); } @Override public SecretKeySpec getKeyEnc() { return keyEnc; } @Override public Mac getMac() { return mac; } @Override public byte[] getMacAuxiliaryData() { // incrementing is already done in #nextIncoming() and #nextOutgoing() return ssc.toByteArray(); } @Override public SecretKeySpec getKeyMac() { return keyMac; } @Override public Integer getMacLength() { return 8; } @Override public SmDataProviderTr03110Generator getSmDataProviderGenerator() { return new SmDataProviderTr03110Generator(this); } public SendSequenceCounter getSsc() { return ssc; } public boolean isPendingCommandApdu() { return pendingCommandApdu; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((keyEnc == null) ? 0 : keyEnc.hashCode()); result = prime * result + ((keyMac == null) ? 0 : keyMac.hashCode()); result = prime * result + (pendingCommandApdu ? 1231 : 1237); result = prime * result + ((ssc == null) ? 0 : ssc.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SmDataProviderTr03110 other = (SmDataProviderTr03110) obj; if (keyEnc == null) { if (other.keyEnc != null) return false; } else if (!keyEnc.equals(other.keyEnc)) return false; if (keyMac == null) { if (other.keyMac != null) return false; } else if (!keyMac.equals(other.keyMac)) return false; if (pendingCommandApdu != other.pendingCommandApdu) return false; if (ssc == null) { if (other.ssc != null) return false; } else if (!ssc.equals(other.ssc)) return false; return true; } }