Search code examples
androidkotlinemvmastercardtlv

Remove Unknown tags (C3, BF40, C2) from TLV using TLVUtility on terminalSdk-2.0.3.jar


I am trying to remove some Unknown tags (C3, BF40, C2,.. etc) from ByteArray using TLVUtility (mastercard class from terminalSdk-2.0.3.jar), Tags was not removing from the ByteArray. I am trying like this,

Here is my TLV Data I have,

 ppseResponse = ByteUtility.hexStringToByteArray("6F54840E325041592E5359532E4444463031C30F4920414D2054484520424553542033BF4003C20101A52BBF0C28610C4F07A0000000041010870101610C4F07A0000000043060870103610A4F05B0123456788701099000")

I am trying this to remove the Unknown tags like,

"BEFORE << ${ByteUtility.byteArrayToHexString(ppseResponse)}".toLog(activity, TAG)  //To print Log

val unknownTags = byteArrayOf((0x00C3).toByte(),(0xBF40).toByte(), (0x00C2).toByte())

var removed = TLVUtility.removeTag(ppseResponse, ContentType.TLV,unknownTags)

"AFTER << ${ByteUtility.byteArrayToHexString(removed)}".toLog(activity, TAG) //To print Log

Here is the function removeTag on terminalSdk-2.0.3.jar function look likes,

public static byte[] removeTag(byte[] var0, ContentType var1, byte[] var2) {
        int var10000;
        Throwable var10001;
        String var28;
        label698: {
            var10000 = 2 % 2;
            if (var0 != null) {
                label691: {
                    var10000 = g + 85;
                    f = var10000 % 128;
                    if (var10000 % 2 == 0) {
                        byte[] var26 = var2;

                        byte var27;
                        label676: {
                            label675: {
                                try {
                                    null.hashCode();
                                    if (var26 == null) {
                                        break label675;
                                    }
                                } catch (Throwable var25) {
                                    throw var25;
                                }

                                var27 = 42;
                                break label676;
                            }

                            var27 = 74;
                        }

                        switch(var27) {
                        case 42:
                            break;
                        case 74:
                        default:
                            break label691;
                        }
                    } else if (var2 == null) {
                        break label691;
                    }

                    var10000 = f + 55;
                    g = var10000 % 128;
                    switch(var10000 % 2 != 0 ? 0 : 1) {
                    case 0:
                    default:
                        if (var2.length >= 1) {
                            break label698;
                        }
                        break;
                    case 1:
                        if (var2.length >= 1) {
                            break label698;
                        }
                    }
                }
            }

            var28 = e(31, '卆', 490).intern();

            try {
                ((Class)q.b(38, 8595, '\ue0f7')).getMethod("e", String.class).invoke((Object)null, var28);
            } catch (Throwable var22) {
                var10001 = var22.getCause();
                if (var10001 != null) {
                    throw var10001;
                }

                throw var22;
            }

            throw new LibraryUncheckedException(ExceptionCode.X6F44);
        }

        label700: {
            if (var1 == ContentType.T) {
                var10000 = g + 15;
                f = var10000 % 128;
                if (var10000 % 2 == 0) {
                    if (var0.length < 0) {
                        break label700;
                    }
                } else if (var0.length < 1) {
                    break label700;
                }
            }

            switch(var1 != ContentType.TLV ? 81 : 64) {
            case 81:
                if (var1 != ContentType.TDO) {
                    break;
                }
            case 64:
            default:
                if (var0.length < 3) {
                    var28 = e(47, '\u0000', 560).intern();

                    try {
                        ((Class)q.b(38, 8595, '\ue0f7')).getMethod("e", String.class).invoke((Object)null, var28);
                    } catch (Throwable var23) {
                        var10001 = var23.getCause();
                        if (var10001 != null) {
                            throw var10001;
                        }

                        throw var23;
                    }

                    throw new LibraryUncheckedException(ExceptionCode.X6F43);
                }
            }

            ArrayList var3 = conditionalTlvParsing(var0, var1, e(1, '\u0000', 140).intern(), true);
            Iterator var4 = var3.iterator();

            while(var4.hasNext()) {
                BerTlv var5 = (BerTlv)var4.next();
                switch(var5.getTagObject().getNTag() == ByteUtility.byteArrayToInt(var2) ? 39 : 84) {
                case 39:
                default:
                    var4.remove();
                case 84:
                }
            }

            return formByteArrayFromTlvList(var3, var1);
        }

        var28 = e(39, '\u0000', 521).intern();

        try {
            ((Class)q.b(38, 8595, '\ue0f7')).getMethod("e", String.class).invoke((Object)null, var28);
        } catch (Throwable var24) {
            var10001 = var24.getCause();
            if (var10001 != null) {
                throw var10001;
            }

            throw var24;
        }

        throw new LibraryUncheckedException(ExceptionCode.X6F43);
    }

    

Solution

  • I fixed this issue by creating new custom function. Here is the function. Now on this function I am removing all the Unknown Tags and its Skipping all Known Tags and Third party data and Optional Tags Tags

    First we need to define optional Tag,

    private var optionalTags: ArrayList<ByteArray> = getOptionalTags()
    

    Here is the function I am adding Optional Tags,

    private fun getOptionalTags(): ArrayList<ByteArray> {
            optionalTags = ArrayList()
            optionalTags.add(ByteUtility.hexStringToByteArray("9F3E"))   //Terminal Categories Supported List
            optionalTags.add(ByteUtility.hexStringToByteArray("9F3F"))   //Selection Data Object List
            optionalTags.add(ByteUtility.hexStringToByteArray("9F2A"))   //Kernel Identifier
            optionalTags.add(ByteUtility.hexStringToByteArray("9F0A"))   //Application Selection Registered Proprietary Data
            return optionalTags
        }
    

    Here is the function to remove the Unknown tags,

     private fun removeUnknownTags(ppseResponse: ByteArray): ByteArray {
            var parentTags: MutableMap<ByteArray, Int> = LinkedHashMap()
    
            var ppseResp = ppseResponse;
            var i = 0
            "PPSE (Length: ${ppseResp.size}) : HexString: ${ByteUtility.byteArrayToHexString(ppseResp)} \n ByteArray: ${ppseResp.toList()}".toLog()
            while (i < ppseResp.size - 1) {
                var removeTag = false;
                var currentTag = TLVUtility.getCurrentTag(ppseResp, i);
                var nextIndex = i + currentTag.size;
                var tLVLengthInfo = TLVUtility.getTLVLengthInfo(ppseResp, nextIndex);
                val tagLength = tLVLengthInfo.expectedNumberOfBytes
                var tagValueSize = tLVLengthInfo.lengthBytes.size
                var tagValue = ByteUtility.getSubByteArray(ppseResp, nextIndex + tagValueSize, tagLength)
                "<==- ${i} :  ${ByteUtility.byteArrayToHexString(currentTag)} (${TLVUtility.getReferenceTagDetails(currentTag).name}) , Length:${tagLength} (${tLVLengthInfo.lengthBytes.toList()} : ${ByteUtility.byteArrayToHexString(tLVLengthInfo.lengthBytes)}) , Max:${TLVUtility.getReferenceTagDetails(currentTag).maxLen} , Min:${TLVUtility.getReferenceTagDetails(currentTag).minLen} -==>".toLog()
                "Value  : ${ByteUtility.byteArrayToHexString(tagValue)} , Bytes:${tagValue.toList()}".toLog()
                var tagNameLengthValue = ByteUtility.getSubByteArray(ppseResp, i, currentTag.size + tagValueSize + tagLength)
    
                if (TLVUtility.getReferenceTagDetails(currentTag).name.contentEquals("Unknown Tag")) {
                    var optionalTag = false;
                    for (optTag in optionalTags) {
                        if (currentTag.contentEquals(optTag)) {
                            "${ByteUtility.byteArrayToHexString(currentTag)} is Optional Tag".toLog()
                            i = nextIndex + tagValueSize + tagLength;
                            optionalTag = true;
                            break
                        }
                    }
                    if (!optionalTag)
                        removeTag = true
                } else if (TLVUtility.getReferenceTagDetails(currentTag).name.contentEquals("Third Party Data")) {
                    i = nextIndex + tagValueSize + tagLength;
                } else {
                    if (!removeTag) {
                        if (TLVUtility.isTLVEncoded(tagValue)) {
                            parentTags.put(currentTag, i)
                            parentTags.entries.stream()
                                .sorted(Map.Entry.comparingByValue<ByteArray, Int>().reversed())
                                .forEachOrdered { x -> parentTags.put(x.key, x.value) }
                            if (tagValue.contentEquals(ByteUtility.hexStringToByteArray("00"))) {
                               i = nextIndex + tagValueSize + tagLength;
                            } else
                                i = nextIndex + tagValueSize
                        } else {
                            i = nextIndex + tagValueSize + tagLength;
                        }
                    }
                }
    
                if (removeTag) {
                    "-*-*-*-Removing TAG ${ByteUtility.byteArrayToHexString(currentTag)}-*-*-*-".toLog()
                    ppseResp = ByteUtility.getSubByteArray(ppseResp, 0, i) + ByteUtility.getSubByteArray(ppseResp, i + tagNameLengthValue.size)
                    var byteDiff = tagNameLengthValue.size
    
                    "--Updating Tag Length (Removed Bytes ${byteDiff})--".toLog()
                    for (tag in parentTags.entries.reversed()) {
                        var parentBytes = tag.key
                        var index = tag.value
                        var sizeIndex = index + parentBytes.size
                        var unknownTLVLengthInfo = TLVUtility.getTLVLengthInfo(ppseResp, sizeIndex);
                        val length = unknownTLVLengthInfo.expectedNumberOfBytes
                        if (i > index && i <= index + length) {  //To Check is Parent Tag
                            "Parent Tag ${ByteUtility.byteArrayToHexString(tag.key)} (Bytes:${tag.key.toList()}) , Position:${tag.value}".toLog()
                            var lengthByteArray = unknownTLVLengthInfo.lengthBytes
                            var newLengthByteArray = ByteUtility.intToBerEncodedLength(length - byteDiff).bytes
                            var lengthDiff = lengthByteArray.size - newLengthByteArray.size;
                            byteDiff = byteDiff + lengthDiff
                            ppseResp = ByteUtility.getSubByteArray(ppseResp, 0, sizeIndex) + newLengthByteArray + ByteUtility.getSubByteArray(ppseResp, sizeIndex + lengthByteArray.size)
                            if (lengthDiff > 0) {
                                i = i - lengthDiff
                                for (child in parentTags.entries) {
                                    if (child.value > tag.value) {
                                       parentTags.replace(child.key, child.value - lengthDiff)
                                    }
                                }
                            }
                            // "PPSE After (Length: ${ppseResp.size}):  ${ByteUtility.byteArrayToHexString(ppseResp)} \n ByteArray: ${ppseResp.toList()}".toLog()
                        }
                    }
                }
    
            }
            return ppseResp;
        }