tangem-app-android-audited/app/src/main/java/com/tangem/domain/cardReader/CommandApdu.java
2018-05-29 21:45:37 +03:00

276 lines
6.7 KiB
Java

package com.tangem.domain.cardReader;
import com.tangem.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class CommandApdu {
public static final byte ISO_CLA = (byte) 0x00;
protected String mCmdName;
protected int mCla = 0x00;
protected int mIns = 0x00;
protected int mP1 = 0x00;
protected int mP2 = 0x00;
protected int mLc = 0x00;
protected byte[] mData = new byte[0];
protected int mLe = 0x00;
protected boolean mLeUsed = false;
protected TLVList tlvList = new TLVList();
public CommandApdu() {
}
public CommandApdu(int cla, int ins, int p1, int p2) {
setCommandName(ins);
mCla = cla;
mIns = ins;
mP1 = p1;
mP2 = p2;
}
public CommandApdu(int cla, int ins, int p1, int p2, byte[] data) {
setCommandName(ins);
mCla = cla;
mIns = ins;
mLc = data.length;
mP1 = p1;
mP2 = p2;
mData = data;
}
public CommandApdu(INS ins) {
setCommandName(ins.name());
mCla = ISO_CLA;
mIns = ins.Code;
mP1 = 0;
mP2 = 0;
}
public CommandApdu(int cla, int ins, int p1, int p2, byte[] data, int le) {
setCommandName(ins);
mCla = cla;
mIns = ins;
mLc = data.length;
mP1 = p1;
mP2 = p2;
mData = data;
mLe = le;
mLeUsed = true;
}
public CommandApdu(int cla, int ins, int p1, int p2, int le) {
setCommandName(ins);
mCla = cla;
mIns = ins;
mP1 = p1;
mP2 = p2;
mLe = le;
mLeUsed = true;
}
public void setCommandName(String cmdName) {
mCmdName = cmdName;
}
private void setCommandName(int ins) {
INS ins1 = INS.ByCode(ins);
if (ins1 != null) {
mCmdName = ins1.toString();
} else {
mCmdName = String.format("INS[%2X]", ins);
}
}
public String getCommandName() {
return mCmdName;
}
public void setP1(int p1) {
mP1 = p1;
}
public void setP2(int p2) {
mP2 = p2;
}
public void setData(byte[] data) {
mLc = data.length;
mData = data;
}
public void addTLV(TLV.Tag tag, byte[] value) {
tlvList.add(new TLV(tag, value));
}
public void addTLV_U8(TLV.Tag tag, int U8) {
addTLV(tag, new byte[]{(byte) U8});
}
public void addTLV_U16(TLV.Tag tag, int U16) {
addTLV(tag, Util.intToByteArray2(U16));
}
public void addTLV_U32(TLV.Tag tag, int U32) {
addTLV(tag, Util.intToByteArray4(U32));
}
public void setLe(int le) {
mLe = le;
mLeUsed = true;
}
public int getP1() {
return mP1;
}
public int getP2() {
return mP2;
}
public int getLc() {
return mLc;
}
public byte[] getData() {
return mData;
}
public TLVList getTLVs() {
return tlvList;
}
public int getLe() {
return mLe;
}
public static String toString(byte[] cmdApdu, int Lc) {
String cmd = Util.bytesToHex(cmdApdu);
if (Lc == 0) return cmd;
return cmd.substring(0, 8) + " " + cmd.substring(8, 10) + " " +
cmd.substring(10, 10 + Lc * 2) + " " + cmd.substring(10 + Lc * 2, cmd.length());
}
public void Crypt(byte[] key) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException {
if (tlvList.size() != 0) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
for (TLV tlv : tlvList) {
try {
tlv.WriteToStream(stream);
} catch (IOException e) {
e.printStackTrace();
break;
}
}
mData = stream.toByteArray();
byte[] crc = Util.calculateCRC16(mData);
stream = new ByteArrayOutputStream();
stream.write(Util.intToByteArray2(mData.length));
stream.write(crc);
stream.write(mData);
mData = stream.toByteArray();
byte[] mEncryptedData = CardCrypto.Encrypt(key, mData);
mData = mEncryptedData;
mLc = mData.length;
tlvList.clear();
}
}
public byte[] toBytes() {
int length = 4; // CLA, INS, P1, P2
if (tlvList.size() != 0) {
mData = tlvList.toBytes();
mLc = mData.length;
}
if (mData.length != 0) {
length += 1; // LC
if (mLc >= 256)
length += 2;
length += mData.length; // DATA
}
if (mLeUsed) {
length += 1; // LE
if (mLc >= 256)
length += 2;
}
byte[] apdu = new byte[length];
int index = 0;
apdu[index] = (byte) mCla;
index++;
apdu[index] = (byte) mIns;
index++;
apdu[index] = (byte) mP1;
index++;
apdu[index] = (byte) mP2;
index++;
if (mLc != 0) {
if (mLc < 256) {
apdu[index] = (byte) mLc;
index++;
} else {
apdu[index] = 0;
index++;
apdu[index] = (byte) (mLc >> 8);
index++;
apdu[index] = (byte) (mLc & 0xFF);
index++;
}
System.arraycopy(mData, 0, apdu, index, mData.length);
index += mData.length;
}
if (mLeUsed) {
if (mLc < 256) {
apdu[index] += (byte) mLe; // LE
} else {
apdu[index] = 0;
index++;
apdu[index] = (byte) (mLe >> 8);
index++;
apdu[index] = (byte) (mLe & 0xFF);
index++;
}
}
return apdu;
}
public CommandApdu clone() {
CommandApdu apdu = new CommandApdu();
apdu.setCommandName(mCmdName);
apdu.mCla = mCla;
apdu.mIns = mIns;
apdu.mP1 = mP1;
apdu.mP2 = mP2;
apdu.mLc = mLc;
apdu.mData = new byte[mData.length];
System.arraycopy(mData, 0, apdu.mData, 0, mData.length);
apdu.mLe = mLe;
apdu.mLeUsed = mLeUsed;
apdu.tlvList = new TLVList(tlvList);
return apdu;
}
}