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();
}
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);
}
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();
}
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;
}
Aggregations