Skip to content

Instantly share code, notes, and snippets.

@PaoloHi
Created June 20, 2025 19:10
Show Gist options
  • Save PaoloHi/f14de6a3a45b389dbe1e28fee8d5b37c to your computer and use it in GitHub Desktop.
Save PaoloHi/f14de6a3a45b389dbe1e28fee8d5b37c to your computer and use it in GitHub Desktop.
bash Tlv decdoder ready to run on terminal, just run bash ./tlv.sh <YOU TLV TO DECODE > works as EMVlab but in your own machine
#!/usr/bin/env bash
declare -A Atags
Atags["57"]="Track 2 Equivalent Data"
Atags["4F"]="Application Identifier (AID) – card"
Atags["50"]="Application Label"
Atags["5A"]="Application Primary Account Number (PAN)"
Atags["82"]="Application Interchange Profile"
Atags["84"]="Dedicated File (DF) Name"
Atags["95"]="Terminal Verification Results"
Atags["9A"]="Transaction Date"
Atags["9B"]="Transaction Status Information"
Atags["9C"]="Transaction Type"
Atags["5F20"]="Cardholder Name"
Atags["5F24"]="Application Expiration Date"
Atags["5F25"]="Application Effective Date"
Atags["5F28"]="Issuer Country Code"
Atags["5F2A"]="Transaction Currency Code"
Atags["5F30"]="Service Code"
Atags["5F34"]="Application Primary Account Number (PAN) Sequence Number"
Atags["9F02"]="Amount, Authorised (Numeric)"
Atags["9F07"]="Application Usage Control"
Atags["9F09"]="Application Version Number"
Atags["9F0D"]="Issuer Action Code – Default"
Atags["9F0E"]="Issuer Action Code – Denial"
Atags["9F0F"]="Issuer Action Code – Online"
Atags["9F10"]="Issuer Application Data"
Atags["9F15"]="Merchant Category Code"
Atags["9F1A"]="Terminal Country Code"
Atags["9F1C"]="Terminal Identification"
Atags["9F21"]="Transaction Time"
Atags["9F26"]="Application Cryptogram"
Atags["9F27"]="Cryptogram Information Data"
Atags["9F33"]="Terminal Capabilities"
Atags["9F34"]="Cardholder Verification Method (CVM) Results"
Atags["9F35"]="Terminal Type"
Atags["9F36"]="Application Transaction Counter (ATC)"
Atags["9F37"]="Unpredictable Number"
Atags["9F39"]="Point-of-Service (POS) Entry Mode"
Atags["9F41"]="Transaction Sequence Counter"
Atags["9F03"]="Amount, Other (Numeric)"
Atags["9F53"]="Unknown tag"
Atags["9F1E"]="Interface Device (IFD) Serial Number"
tlv=$1 ;
tags=( 57 4F 50 5A 82 84 95 9A 9B 9C );
function contains {
string=$1;
substring=$2
[[ $string =~ "$substring" ]] && echo true || echo false;
}
function containsTag {
str=$1
res=false;
for tag in ${tags[@]}; do
cont=$( echo $( contains $str $tag ) )
if [[ $cont == true ]]; then
res=true;
break
fi
done
echo $res;
}
function hexToDec {
hex_value=$1;
dec=$((16#$hex_value));
echo $(( $dec*2 ))
}
function parseTlv {
tlv="$1" ;
header=${tlv:0:4}
if [[ $(echo $(containsTag $header)) = true ]]; then
head_len=4
header=${tlv:0:2}
length=$( hexToDec ${tlv:2:2} )
body=${tlv:4:$length}
else
head_len=6
header=${tlv:0:4}
length=$( hexToDec ${tlv:4:2} )
body=${tlv:6:$length}
fi
cut=$(( head_len + length ))
echo "<--------------------------->"
echo ${Atags["$header"]}
echo "tag name:$header"
echo "length: $length"
echo "body: $body"
echo "<--------------------------->"
}
function getLength {
tlv="$1" ;
header=${tlv:0:4}
if [[ $(echo $(containsTag $header)) = true ]]; then
head_len=4
length=$( hexToDec ${tlv:2:2} )
else
head_len=6
length=$( hexToDec ${tlv:4:2} )
fi
cut=$(( head_len + length ))
echo $cut
}
function cutTlv {
or_tlv=$1
parsed=0;
i=0
while [[ (( $i -lt ${#or_tlv} )) ]] do
tlv_cut=${or_tlv:$i};
parseTlv $tlv_cut
parsed=$( getLength $tlv_cut )
#parsed=$( parseTlv ${tlv:$i} | head -n 1 )
i=$(( i + parsed ))
done
}
#if [[ -z $2 ]]; then
#echo "works"
#cutTlv $tlv
#else
#parseTlv
#fi
#echo ${Atags[84]}
#echo ${!Atags[@]}
cutTlv $tlv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment