Updated on 2026-08-14

This commit is contained in:
Tangem 2018-06-28 12:03:18 +03:00
parent 0fab3ec90e
commit 4e42025453
9 changed files with 123 additions and 8 deletions

Binary file not shown.

View file

@ -72,6 +72,7 @@ public class PurgeTask extends Thread {
} finally {
mNfcManager.ignoreTag(mIsoDep.getTag());
mNotifications.OnReadWait(0);
}
} catch (Exception e) {
e.printStackTrace();

View file

@ -118,6 +118,7 @@ public class SignPaymentTask extends Thread {
} finally {
mNfcManager.ignoreTag(mIsoDep.getTag());
mNotifications.OnReadWait(0);
}
} catch (CardProtocol.TangemException_InvalidPIN e) {
e.printStackTrace();

View file

@ -76,6 +76,7 @@ public class SwapPINTask extends Thread {
} finally {
mNfcManager.ignoreTag(mIsoDep.getTag());
mNotifications.OnReadWait(0);
}
} catch (Exception e) {
e.printStackTrace();

View file

@ -280,6 +280,62 @@ public class CardProtocol {
// send command APDU, get response APDU, and display HEX data to user
// private ResponseApdu SendAndReceive(CommandApdu cmdApdu, boolean breakOnNeedPause) throws Exception {
// if (mCard.encryptionMode != TangemCard.EncryptionMode.None) {
// if (sessionKey == null) {
// run_OpenSession(mCard.encryptionMode);
// }
// cmdApdu.Crypt(sessionKey);
// }
// cmdApdu.setP1(mCard.encryptionMode.getP());
// byte[] cmdBytes = cmdApdu.toBytes();
// String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc());
// Log.v("NFC", String.format("<< [%s]: %s", cmdApdu.getCommandName(), cmdStr));
// byte[] rsp;
// ResponseApdu rspApdu;
// try {
// do {
// try {
// mNotifications.OnReadBeforeRequest(mIsoDep.getTimeout());
// try {
// rsp = mIsoDep.transceive(cmdBytes);
// } finally {
// mNotifications.OnReadAfterRequest();
// }
// } catch (IOException e) {
// if (e.getMessage().contains("length exceeds supported maximum") && mIsoDep.isExtendedLengthApduSupported()) {
// throw new TangemException_ExtendedLengthNotSupported(e.getMessage());
// }
// throw e;
// }
// if (mCard.encryptionMode != TangemCard.EncryptionMode.None) {
// rspApdu = ResponseApdu.Decrypt(rsp, sessionKey);
// } else {
// rspApdu = new ResponseApdu(rsp);
// }
//
// if (rspApdu.isParsedWithError()) {
// Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp)));
// throw new TangemException(rspApdu.getParseErroMessage());
// } else if (rspApdu.getSW1SW2() == SW.NEED_PAUSE && mNotifications != null) {
// int remainingPause = rspApdu.getTLVs().getTagAsInt(TLV.Tag.TAG_Pause) * 10;
// Log.v("NFC", String.format(">> Security delay, remaining %f s", remainingPause / 1000.0));
// if (breakOnNeedPause) {
// break;
// } else {
// mNotifications.OnReadWait(remainingPause);
// }
// } else {
// Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp)));
// }
// } while (rspApdu.getSW1SW2() == SW.NEED_PAUSE);
// } finally {
// mNotifications.OnReadWait(0);
// }
//
// return rspApdu;
// }
private ResponseApdu SendAndReceive(CommandApdu cmdApdu, boolean breakOnNeedPause) throws Exception {
if (mCard.encryptionMode != TangemCard.EncryptionMode.None) {
if (sessionKey == null) {
@ -308,7 +364,7 @@ public class CardProtocol {
}
throw e;
}
if (mCard.encryptionMode != TangemCard.EncryptionMode.None) {
if (mCard.encryptionMode != TangemCard.EncryptionMode.None && !ResponseApdu.isStatusWord(rsp, SW.NEED_PAUSE)) {
rspApdu = ResponseApdu.Decrypt(rsp, sessionKey);
} else {
rspApdu = new ResponseApdu(rsp);
@ -318,7 +374,12 @@ public class CardProtocol {
Log.v("NFC", String.format(">> [%s]: %s", cmdApdu.getCommandName(), Util.bytesToHex(rsp)));
throw new TangemException(rspApdu.getParseErroMessage());
} else if (rspApdu.getSW1SW2() == SW.NEED_PAUSE && mNotifications != null) {
int remainingPause = rspApdu.getTLVs().getTagAsInt(TLV.Tag.TAG_Pause) * 10;
int remainingPause = 60000;
TLV tlvPause = rspApdu.getTLVs().getTLV(TLV.Tag.TAG_Pause);
if (tlvPause != null) {
remainingPause = rspApdu.getTLVs().getTagAsInt(TLV.Tag.TAG_Pause) * 10;
}
Log.v("NFC", String.format(">> Security delay, remaining %f s", remainingPause / 1000.0));
if (breakOnNeedPause) {
break;

View file

@ -20,12 +20,7 @@ public enum INS {
Sign(0xFB),
PurgeWallet(0xFC),
Activate(0xFE),
OpenSession(0xFF),
ReadBlockedData(0xE4),
CreateTestWallet(0xE0),
ExtractWalletKey(0xE1),
Test(0xE2),
Depersonalize(0xE3);
OpenSession(0xFF);
INS(int Code) {
this.Code = Code;

View file

@ -34,12 +34,22 @@ public class ResponseApdu {
parseError = e.getMessage();
}
}else{
tlvList=new TLVList();
parseError=null;
}
mSw1 = 0x00FF & respApdu[respApdu.length - 2];
mSw2 = 0x00FF & respApdu[respApdu.length - 1];
mBytes = respApdu;
}
public static boolean isStatusWord(byte[] respApdu, int SW)
{
int mSw1 = 0x00FF & respApdu[respApdu.length - 2];
int mSw2 = 0x00FF & respApdu[respApdu.length - 1];
return ((mSw1 << 8) | mSw2)==SW;
}
public static ResponseApdu Decrypt(byte[] data, byte[] key) throws Exception{
if( data.length==2 )

View file

@ -22,4 +22,6 @@ public class SettingsMask {
public static final int Protocol_AllowUnencrypted = 0x1000;
public static final int Protocol_AllowStaticEncryption = 0x2000;
public static final int ProtectIssuerDataAgainstReplay = 0x4000;
}

View file

@ -53,6 +53,7 @@ public class TLV {
TAG_Issuer_Data(0x32),
TAG_Issuer_Data_Signature(0x33),
TAG_Issuer_Transaction_Signature(0x34),
TAG_Issuer_Data_Counter(0x35),
TAG_IsActivated(0x3A),
TAG_ActivationSeed(0x3B),
@ -213,6 +214,49 @@ public class TLV {
} else {
return String.format("%s[]: [[NULL]]", tag.name());
}
case TAG_SettingsMask: {
StringBuilder sb=new StringBuilder();
if( Value!=null ) {
try {
int iValue = Util.byteArrayToInt(Value);
sb.append("[");
if ((iValue & SettingsMask.AllowSwapPIN) != 0) sb.append("AllowSwapPIN, ");
if ((iValue & SettingsMask.AllowSwapPIN2) != 0)
sb.append("AllowSwapPIN2, ");
if ((iValue & SettingsMask.ForbidDefaultPIN) != 0)
sb.append("ForbidDefaultPIN, ");
if ((iValue & SettingsMask.IsReusable) != 0) sb.append("IsReusable, ");
if ((iValue & SettingsMask.Protocol_AllowStaticEncryption) != 0)
sb.append("Protocol_AllowStaticEncryption, ");
if ((iValue & SettingsMask.Protocol_AllowUnencrypted) != 0)
sb.append("Protocol_AllowUnencrypted, ");
if ((iValue & SettingsMask.SmartSecurityDelay) != 0)
sb.append("SmartSecurityDelay, ");
if ((iValue & SettingsMask.UseActivation) != 0)
sb.append("UseActivation, ");
if ((iValue & SettingsMask.UseBlock) != 0) sb.append("UseBlock, ");
if ((iValue & SettingsMask.UseCVC) != 0) sb.append("UseCVC, ");
if ((iValue & SettingsMask.UseDynamicNDEF) != 0)
sb.append("UseDynamicNDEF, ");
if ((iValue & SettingsMask.UseNDEF) != 0) sb.append("UseNDEF, ");
if ((iValue & SettingsMask.UseOneCommandAtTime) != 0)
sb.append("UseOneCommandAtTime, ");
if ((iValue & SettingsMask.ProtectIssuerDataAgainstReplay) != 0)
sb.append("ProtectIssuerDataAgainstReplay, ");
if (sb.length() > 1) sb.delete(sb.length() - 2, sb.length());
sb.append("]");
return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), sb.toString());
}
catch (Exception e)
{
e.printStackTrace();
return String.format("%s[%d]: %s", tag.name(), Value.length, Util.bytesToHex(Value));
}
}else{
return String.format("%s[]: [[NULL]]", tag.name());
}
}
default:
if (Value != null) {
return String.format("%s[%d]: %s", tag.name(), Value.length, Util.bytesToHex(Value));