tangem-app-android-audited/card-common/src/main/java/com/tangem/cardcommon/reader/TLV.java
2019-02-27 22:22:06 +03:00

237 lines
7 KiB
Java

package com.tangem.cardcommon.reader;
import com.tangem.cardcommon.util.Util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* Created by dvol on 23.06.2017.
*/
public class TLV {
public enum Tag {
TAG_Unknown(0x00),
TAG_CardID(0x01),
TAG_Status(0x02),
TAG_CardPublicKey(0x03),
TAG_CardSignature(0x04),
TAG_CurveID(0x05),
TAG_HashAlgID(0x06),
TAG_SigningMethod(0x07),
TAG_MaxSignatures(0x08),
TAG_PauseBeforePIN2(0x09),
TAG_SettingsMask(0x0A),
TAG_CardData(0x0C),
TAG_NDEFData(0x0D),
TAG_Health(0x0F),
TAG_PIN(0x10),
TAG_PIN2(0x11),
TAG_NewPIN(0x12),
TAG_NewPIN2(0x13),
TAG_NewPIN_Hash(0x14),
TAG_NewPIN2_Hash(0x15),
TAG_Challenge(0x16),
TAG_Salt(0x17),
TAG_ValidationCounter(0x18),
TAG_CVC(0x19),
TAG_Session_Key_A(0x1A),
TAG_Session_Key_B(0x1B),
TAG_Pause(0x1C),
TAG_Manufacture_ID(0x20),
TAG_Manufacturer_Signature(0x21),
TAG_Issuer_Data_PublicKey(0x30),
TAG_Issuer_Transaction_PublicKey(0x31),
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),
TAG_ResetPIN(0x36),
TAG_CodePageAddress(0x40),
TAG_CodePageCount(0x41),
TAG_CodeHash(0x42),
TAG_TrOut_Hash(0x50),
TAG_TrOut_HashSize(0x51),
TAG_TrOut_Raw(0x52),
TAG_Wallet_PublicKey(0x60),
TAG_Signature(0x61),
TAG_RemainingSignatures(0x62),
TAG_SignedHashes(0x63),
TAG_Firmware(0x80),
TAG_Batch(0x81),
TAG_ManufactureDateTime(0x82),
TAG_Issuer_ID(0x83),
TAG_Blockchain_ID(0x84),
TAG_Manufacturer_PublicKey(0x85),
TAG_CardID_Manufacturer_Signature(0x86),
TAG_Token_Symbol(0xA0),
TAG_Token_Contract_Address(0xA1),
TAG_Token_Decimal(0xA2),
TAG_Denomination(0xC0),
TAG_ValidatedBalance(0xC1),
TAG_LastSign_Date(0xC2),
TAG_DenominationText(0xC3);
Tag(int Code) {
this.Code = Code;
}
public int getCode() {
return Code;
}
private int Code;
public static Tag ByCode(int Code) {
Tag[] allTags = Tag.values();
for (Tag t : allTags) if (t.getCode() == Code) return t;
return TAG_Unknown;
}
}
private Tag tag;
public Tag getTag() {
return tag;
}
public byte[] Value;
public TLV(Tag tag, byte[] value) {
this.tag = tag;
this.Value = value;
}
public void WriteToStream(ByteArrayOutputStream stream) throws IOException {
stream.write(tag.getCode());
if (Value != null) {
if (Value.length > 0xFE) {
stream.write(0xFF);
stream.write((Value.length >> 8) & 0xFF);
stream.write(Value.length & 0xFF);
} else {
stream.write(Value.length & 0xFF);
}
stream.write(Value);
} else {
stream.write(0x00);
}
}
public static TLV ReadFromStream(ByteArrayInputStream stream) throws IOException {
int code = stream.read();
if (code == -1) return null;
int len = stream.read();
if (len == -1)
throw new IOException("Can't read TLV");
if (len == 0xFF) {
int lenH = stream.read();
if (lenH == -1)
throw new IOException("Can't read TLV");
len = stream.read();
if (len == -1)
throw new IOException("Can't read TLV");
len |= (lenH << 8);
}
byte[] value = new byte[len];
if (len > 0) {
if (len != stream.read(value)) {
throw new IOException("Can't read TLV");
}
}
Tag tag = Tag.ByCode(code);
TLV result = new TLV(tag, value);
return result;
}
public int getAsInt() {
return Util.byteArrayToInt(Value);
}
public String getAsHexString() {
return Util.bytesToHex(Value);
}
public String getAsString() {
if( Value.length==0 ) return "";
if (Value[Value.length - 1] == 0) {
String s1 = new String(Arrays.copyOfRange(Value, 0, Value.length - 1), Charset.forName("utf-8"));
return s1.trim();
} else {
String s1 = new String(Value, Charset.forName("utf-8"));
return s1.trim();
}
}
@Override
public String toString() {
switch (tag) {
case TAG_CardData:
case TAG_Issuer_Data: {
try {
TLVList tlvSub = TLVList.fromBytes(Value);
return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), tlvSub.toString());
} catch (TLVException e) {
e.printStackTrace();
}
if (Value != null) {
return String.format("%s[%d]: %s (non TLV)", tag.name(), Value.length, Util.bytesToHex(Value));
} else {
return String.format("%s[]: [[NULL]]", tag.name());
}
}
case TAG_CurveID:
case TAG_HashAlgID:
case TAG_Blockchain_ID:
case TAG_Manufacture_ID:
case TAG_Firmware:
case TAG_Issuer_ID:
case TAG_Token_Symbol:
if (Value != null) {
return String.format("%s[%d]: %s(%s)", tag.name(), Value.length, Util.bytesToHex(Value), getAsString());
} else {
return String.format("%s[]: [[NULL]]", tag.name());
}
case TAG_SettingsMask: {
StringBuilder sb=new StringBuilder();
if( Value!=null ) {
try {
int iValue = Util.byteArrayToInt(Value);
return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), SettingsMask.getDescription(iValue));
}
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));
} else {
return String.format("%s[]: [[NULL]]", tag.name());
}
}
}
}