Search in sources :

Example 1 with CMac

use of org.openecard.bouncycastle.crypto.macs.CMac in project open-ecard by ecsec.

the class SecureMessaging method decrypt.

/**
 * Decrypt the APDU.
 *
 * @param response the response
 * @param secureMessagingSSC the secure messaging ssc
 * @return the byte[]
 * @throws Exception the exception
 */
private byte[] decrypt(byte[] response, byte[] secureMessagingSSC) throws Exception {
    ByteArrayInputStream bais = new ByteArrayInputStream(response);
    ByteArrayOutputStream baos = new ByteArrayOutputStream(response.length - 10);
    // Status bytes of the response APDU. MUST be 2 bytes.
    byte[] statusBytes = new byte[2];
    // Padding-content indicator followed by cryptogram 0x87.
    byte[] dataObject = null;
    // Cryptographic checksum 0x8E. MUST be 8 bytes.
    byte[] macObject = new byte[8];
    /*
	 * Read APDU structure
	 * Case 1: DO99|DO8E|SW1SW2
	 * Case 2: DO87|DO99|DO8E|SW1SW2
	 * Case 3: DO99|DO8E|SW1SW2
	 * Case 4: DO87|DO99|DO8E|SW1SW2
	 */
    byte tag = (byte) bais.read();
    // Read data object (OPTIONAL)
    if (tag == (byte) 0x87) {
        int size = bais.read();
        if (size > 0x80) {
            byte[] sizeBytes = new byte[size & 0x0F];
            bais.read(sizeBytes, 0, sizeBytes.length);
            size = new BigInteger(1, sizeBytes).intValue();
        }
        // Skip encryption header
        bais.skip(1);
        dataObject = new byte[size - 1];
        bais.read(dataObject, 0, dataObject.length);
        tag = (byte) bais.read();
    }
    // Read processing status (REQUIRED)
    if (tag == (byte) 0x99) {
        if (bais.read() == (byte) 0x02) {
            bais.read(statusBytes, 0, 2);
            tag = (byte) bais.read();
        }
    } else {
        throw new IOException("Malformed Secure Messaging APDU");
    }
    // Read MAC (REQUIRED)
    if (tag == (byte) 0x8E) {
        if (bais.read() == (byte) 0x08) {
            bais.read(macObject, 0, 8);
        }
    } else {
        throw new IOException("Malformed Secure Messaging APDU");
    }
    // Only 2 bytes status should remain
    if (bais.available() != 2) {
        throw new IOException("Malformed Secure Messaging APDU");
    }
    // Calculate MAC for verification
    CMac cmac = getCMAC(secureMessagingSSC);
    byte[] mac = new byte[16];
    synchronized (cmac) {
        ByteArrayOutputStream macData = new ByteArrayOutputStream();
        // Write padding-content
        if (dataObject != null) {
            TLV paddedDataObject = new TLV();
            paddedDataObject.setTagNumWithClass((byte) 0x87);
            paddedDataObject.setValue(ByteUtils.concatenate((byte) 0x01, dataObject));
            macData.write(paddedDataObject.toBER());
        }
        // Write status bytes
        TLV statusBytesObject = new TLV();
        statusBytesObject.setTagNumWithClass((byte) 0x99);
        statusBytesObject.setValue(statusBytes);
        macData.write(statusBytesObject.toBER());
        byte[] paddedData = pad(macData.toByteArray(), 16);
        cmac.update(paddedData, 0, paddedData.length);
        cmac.doFinal(mac, 0);
        mac = ByteUtils.copy(mac, 0, 8);
    }
    // Verify MAC
    if (!ByteUtils.compare(mac, macObject)) {
        throw new GeneralSecurityException("Secure Messaging MAC verification failed");
    }
    // Decrypt data
    if (dataObject != null) {
        Cipher c = getCipher(secureMessagingSSC, Cipher.DECRYPT_MODE);
        byte[] data_decrypted = c.doFinal(dataObject);
        baos.write(unpad(data_decrypted));
    }
    // Add status code
    baos.write(statusBytes);
    return baos.toByteArray();
}
Also used : CMac(org.openecard.bouncycastle.crypto.macs.CMac) ByteArrayInputStream(java.io.ByteArrayInputStream) GeneralSecurityException(java.security.GeneralSecurityException) BigInteger(java.math.BigInteger) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) Cipher(javax.crypto.Cipher) TLV(org.openecard.common.tlv.TLV)

Example 2 with CMac

use of org.openecard.bouncycastle.crypto.macs.CMac in project open-ecard by ecsec.

the class AuthenticationToken method generateToken.

/**
 * Generate an authentication token.
 *
 * @param keyMac Key for message authentication
 * @param key Key
 * @throws GeneralSecurityException
 */
public void generateToken(byte[] keyMac, byte[] key) throws GeneralSecurityException {
    byte[] tmp = new byte[16];
    byte[] macData = getMACObject(key);
    CMac cMAC = new CMac(new AESEngine());
    cMAC.init(new KeyParameter(keyMac));
    cMAC.update(macData, 0, macData.length);
    cMAC.doFinal(tmp, 0);
    System.arraycopy(tmp, 0, token, 0, 8);
}
Also used : AESEngine(org.openecard.bouncycastle.crypto.engines.AESEngine) CMac(org.openecard.bouncycastle.crypto.macs.CMac) KeyParameter(org.openecard.bouncycastle.crypto.params.KeyParameter)

Example 3 with CMac

use of org.openecard.bouncycastle.crypto.macs.CMac in project open-ecard by ecsec.

the class SecureMessaging method encrypt.

/**
 * Encrypt the APDU.
 *
 * @param apdu APDU
 * @param secureMessagingSSC Secure Messaging Send Sequence Counter
 * @return Encrypted APDU
 * @throws Exception
 */
private byte[] encrypt(byte[] apdu, byte[] secureMessagingSSC) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    CardCommandAPDU cAPDU = new CardCommandAPDU(apdu);
    if (cAPDU.isSecureMessaging()) {
        throw new IllegalArgumentException("Malformed APDU.");
    }
    byte[] data = cAPDU.getData();
    byte[] header = cAPDU.getHeader();
    int lc = cAPDU.getLC();
    int le = cAPDU.getLE();
    if (data.length > 0) {
        data = pad(data, 16);
        // Encrypt data
        Cipher c = getCipher(secureMessagingSSC, Cipher.ENCRYPT_MODE);
        byte[] dataEncrypted = c.doFinal(data);
        // Add padding indicator 0x01
        dataEncrypted = ByteUtils.concatenate((byte) 0x01, dataEncrypted);
        TLV dataObject = new TLV();
        dataObject.setTagNumWithClass((byte) 0x87);
        dataObject.setValue(dataEncrypted);
        baos.write(dataObject.toBER());
    }
    // Write protected LE
    if (le >= 0) {
        TLV leObject = new TLV();
        leObject.setTagNumWithClass((byte) 0x97);
        if (le == 0x100) {
            leObject.setValue(NULL);
        } else if (le > 0x100) {
            leObject.setValue(new byte[] { (byte) ((le >> 8) & 0xFF), (byte) (le & 0xFF) });
        } else {
            leObject.setValue(new byte[] { (byte) le });
        }
        baos.write(leObject.toBER());
    }
    // Indicate Secure Messaging
    // note: must be done before mac calculation
    header[0] |= 0x0C;
    /*
	 * Calculate MAC
	 */
    byte[] mac = new byte[16];
    CMac cmac = getCMAC(secureMessagingSSC);
    byte[] paddedHeader = pad(header, 16);
    cmac.update(paddedHeader, 0, paddedHeader.length);
    if (baos.size() > 0) {
        byte[] paddedData = pad(baos.toByteArray(), 16);
        cmac.update(paddedData, 0, paddedData.length);
    }
    cmac.doFinal(mac, 0);
    mac = ByteUtils.copy(mac, 0, 8);
    // 
    // Build APDU
    TLV macStructure = new TLV();
    macStructure.setTagNumWithClass((byte) 0x8E);
    macStructure.setValue(mac);
    byte[] secureData = ByteUtils.concatenate(baos.toByteArray(), macStructure.toBER());
    CardCommandAPDU secureCommand = new CardCommandAPDU(header[0], header[1], header[2], header[3], secureData);
    // set LE explicitely to 0x00 or in case of extended length 0x00 0x00
    if ((lc > 0xFF) || (le > 0x100)) {
        secureCommand.setLE(65536);
    } else {
        secureCommand.setLE(256);
    }
    return secureCommand.toByteArray();
}
Also used : CardCommandAPDU(org.openecard.common.apdu.common.CardCommandAPDU) CMac(org.openecard.bouncycastle.crypto.macs.CMac) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Cipher(javax.crypto.Cipher) TLV(org.openecard.common.tlv.TLV)

Example 4 with CMac

use of org.openecard.bouncycastle.crypto.macs.CMac in project open-ecard by ecsec.

the class SecureMessaging method getCMAC.

/**
 * Gets the CMAC.
 *
 * @param smssc Secure Messaging Send Sequence Counter
 * @return CMAC
 */
private CMac getCMAC(byte[] smssc) {
    CMac cmac = new CMac(new AESFastEngine());
    cmac.init(new KeyParameter(keyMAC));
    cmac.update(smssc, 0, smssc.length);
    return cmac;
}
Also used : CMac(org.openecard.bouncycastle.crypto.macs.CMac) KeyParameter(org.openecard.bouncycastle.crypto.params.KeyParameter) AESFastEngine(org.openecard.bouncycastle.crypto.engines.AESFastEngine)

Aggregations

CMac (org.openecard.bouncycastle.crypto.macs.CMac)4 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 Cipher (javax.crypto.Cipher)2 KeyParameter (org.openecard.bouncycastle.crypto.params.KeyParameter)2 TLV (org.openecard.common.tlv.TLV)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 BigInteger (java.math.BigInteger)1 GeneralSecurityException (java.security.GeneralSecurityException)1 AESEngine (org.openecard.bouncycastle.crypto.engines.AESEngine)1 AESFastEngine (org.openecard.bouncycastle.crypto.engines.AESFastEngine)1 CardCommandAPDU (org.openecard.common.apdu.common.CardCommandAPDU)1