vrijdag 31 mei 2013

getChallengeResponse.sh script

#!/bin/sh
# getChallengeResponse.sh - login to my online banking website using the challenge-reponse mechanism
# Purpose of this script (work in progress) is to further automate online banking.
# More info: http://globalblindspot.blogspot.be/2010/07/getting-emvcap-challengeresponse-to.html
# Author: Tom Van Braeckel 

pin="$1"
challenge="$2"

if [ -z "$pin" -o `expr length "$pin"` -ne 4 -o -z "$challenge" -o `expr length "$challenge"` -ne 8 ]; then
 echo "Usage: $0  "
 echo "Example: $0 3117 12345678"
 exit 1
fi

# Can you guess what this method does ?
bintodec() {
 bin="$1"
 echo "obase=10; ibase=2; $bin" | bc
}

# remove < and " "
compact() {
 while read line; do
  echo "$line" | tr -d '<' | tr -d ' '
 done
}

# args: command to execute on the card
execOnCard() {
 cla="$1"
 ins="$2"
 p1="$3"
 p2="$4"
 le="$5"
 data="$6"
 tosend="${cla}${ins}${p1}${p2}${le}${data}"
 #echo "Sending $tosend" >&2
 echo "$tosend" | scriptor 2>/dev/null | grep -A 10000 "<"
  # does not work:
# echo "$cla $ins $p1 $p2 $le $data" | scriptor 2>/dev/null | grep "<"
}

execOnCardRespond() {
 cla="$1"
 ins="$2"
 p1="$3"
 p2="$4"
 le="$5"
 data="$6"
 result=$(execOnCard $cla $ins $p1 $p2 $le $data) ; echo "result = $result" >&2
 # get length in hex
 length=$(echo "$result" | cut -d ' ' -f 3); #echo "length = $length"
 execOnCard 00 c0 00 00 $length | compact
}

# Can you guess what this method does ?
hextobin() {
 hex="$1"
 echo "ibase=16; obase=2; $hex" | bc
}

# do a read data with the correct length...
readData() {
 p2="$1"
 recordLength=$(execOnCard 80 ca 9f $p2 00 | cut -d ' ' -f 3)
 #echo "recordLength = $recordLength" >&2
 # cut off first bytes (status code, length)
 # cut off last bytes (9000Normalprocessing)
 # for some reason we NEED CLA 80 here, 00 doesn't work...
 execOnCard 80 ca 9f $p2 $recordLength | compact | tail -c +7 | head -c -23
 echo
}

readRecord() {
 p1="$1"
 p2="$2"
 errorWithLength=$(execOnCard 00 b2 $p1 $p2 00)
 #echo "errorWithLength = $errorWithLength"
 recordLength=$(echo "$errorWithLength" | cut -d ' ' -f 3)
 #echo "recordLength = $recordLength"
 execOnCard 00 b2 $p1 $p2 $recordLength | compact
}

readRecords() {
 SFI="$1" # five most significant bits
 recNr="$2" # second byte
 lastRecNr="$3" # third byte
 if [ "$SFI" = "1" ]; then
  p2=0c # (sfi << 3) + 4
 else
  echo "I don't know p2 !"
  sleep 3
 fi
 # READ RECORD(s)
 for i in `seq $recNr $lastRecNr`; do
  readRecord 0$i $p2
 done
}

zeropadfront() {
 targetLength="$1"
# echo "targetLength = $targetLength"
 while read line; do
#  echo "got line $line"
  length=$(expr length "$line")
  while [ $length -lt $targetLength ]; do
   line="0${line}"
   length=$(expr length "$line")
  done
  echo "$line"
 done
}

#################################################################
###################### EXECUTION STARTS HERE ####################
#################################################################

# reset
execOnCard reset

#select file/application
aid=A0000000048002 # securecode aut
#aid=A0000000043060 # maestro (debit)
response=$(execOnCardRespond 00 a4 04 00 07 ${aid})
echo $response

# this is needed, otherwise the commands below fail...
PDOL=$(echo "$response" | grep -o -E "9F38........" | tail -c +7)
echo "PDOL = $PDOL"
# for securecode get a PDOL of "9F3501" (eg "9F38039F3501")
# this is the "Terminal Type" - don't know the value, but I use 00...

# get processing options:
# - Application Interchange Profile (AIP)
# - Application File Locator (AFL)
if [ -z "$PDOL" ]; then
 response=$(execOnCardRespond 80 a8 00 00 02 8300); echo $response
 # eg: ...94080801030110010201
 AIP=3800 # this means "initiate", "data auth", RFU
 AFLs="08010301 10010201"
else
 # PDOL specifies one tag with value of 1 byte, but I don't know which value...
 response=$(execOnCardRespond 80 a8 00 00 03 830100); echo $response
 # 770E82021000940808010100080404009000:Normalprocessing.
 AIP=1000 # this means "initiate"
 AFLs="08010100 08040400"
fi
echo "Found AIP = $AIP and AFLs = $AFLs"

# Read SecureCode records and extract valueable info
cardinfo=$(readRecords 1 1 1)
PAN=$(expr substr "$cardinfo" 9 18)
echo "Application Primary Account Number (PAN) = $PAN"
authinfo=$(readRecords 1 4 4)
bitmap=$(expr substr "$authinfo" 11 22)
echo "Proprietary Authentication Challenge-Reponse Bitmap = $bitmap"

# This works for maestro:
if false; then
 readRecords 1 1 3

 # second group in AFL
 SFI=10 # five most significant bits
 recNr=1 # second byte
 lastRecNr=2 # third byte
 offlineDataRec=1 # fourth byte
 # p2=binary(firstbyte)100 left shift 3 OR 100 ???
 # p2=binary(firstbyte) shift right 3
 # I calculated 84, but it seems to be (13) 14 / (1B) 1C / (23) 24
 # and also 03 04 0B 0C but we found those above
 p2s="14 1C 24"
 # READ RECORD(s)
 for p2 in $p2s; do
  for i in `seq $recNr $lastRecNr`; do
   echo -n "p2 = $p2, recordNr = $i: "
   readRecord 0$i $p2
  done
 done
fi

# get pin try counter length
pinTry=$(readData 17)
echo "pinTry = $pinTry"
if [ "$pinTry" != "02" -a "$pinTry" != "03" ]; then
 echo "WARNING: pinTry < 2 !"
 sleep 15
fi

# get Application Transaction Counter
echo -n "Application Transaction Counter = "
readData 36

# get Last Online ATC Register
echo -n "Last Online ATC Register = "
readData 13

echo -n "Log Entry = "
readData 4D

echo -n "Log Format = "
readData 4F

# submit pin
execOnCard 00 20 00 80 08 24${pin}FFFFFFFFFF

# generate Application RQ Cryptogram
# p1=80=Authorisation Request Cryptogram
countrycode=0056 # OTF mentions 0000, chip&pin uses 0826
currencycode=0978 # OTF mentions 0000, chip&pin uses 0826
date=$(date +"%y%m%d")
CardholderVerificationMethodResults=010002
# 8000000000 = Terminal Verification Codes: Data authentication was not performed (recommended by optimized to fail)
# 00 = transaction type
# 0000 = ICC Dynamic Number
ARQC_response=$(execOnCardRespond 80 AE 80 00 22 000000000000000000000000${countrycode}8000000000${currencycode}${date}00${challenge}0000${CardholderVerificationMethodResults})
echo "ARQC_response = $ARQC_response"
CID=$(expr substr "$ARQC_response" 11 2)
ATC=$(expr substr "$ARQC_response" 19 4)
AC=$(expr substr "$ARQC_response" 29 16)
#IAD=$(expr substr "$ARQC_response" 51 15)
# testing to see if we get the same response as in chip&pin - we do, so this is OK.
# CID=80; ATC=A52D; AC=AD452EF6BA769E4A; IAD=06770A03A48000; bitmap=00001F00000000000FFFFF00000000008000


# generate Application Cryptogram for challenge 12345678
# 5a33 = Authorisation Response Code, generated by terminal or bank (for online stuff)
IAuthData=0000000000000000000000000000000000000000 # Issuer Authentication Data (NOT Issuer Application Data !)
AC_response=$(execOnCardRespond 80 AE 00 00 2e 5a33000000000000000000000000${countrycode}8000000000${currencycode}${date}00${challenge}0000${CardholderVerificationMethodResults}${IAuthData})
echo "AC_response = $AC_response"
#AC_response="$ARQC_response" # Testing which response we need - normally the second one, but let's try this for a laugh
CID=$(expr substr "$AC_response" 11 2)
ATC=$(expr substr "$AC_response" 19 4)
AC=$(expr substr "$AC_response" 29 16)

# extract response
echo "CID=$CID, ATC=$ATC, AC=$AC, IAD=$IAD"

# length of bitmap is used as the target length for the response
bitmap_hex_length=$(expr length "$bitmap")
bitmap_bin_length=$(expr "$bitmap_hex_length" \* 4)
echo bitmap_hex_length=$bitmap_hex_length, bitmap_bin_length=$bitmap_bin_length

# Do logical AND with bitmap
CIDATCAC_bin=$(hextobin "${CID}${ATC}${AC}${IAD}" | zeropadfront "$bitmap_bin_length")
echo "CIDATCAC_bin = $CIDATCAC_bin"
bitmap_bin=$(hextobin "$bitmap" | zeropadfront "$bitmap_bin_length")
echo "  bitmap_bin = $bitmap_bin"

# if a bit of bitmap = 1, then we add the bit from CIDATCAC_bin to filtered_bin
filtered_bin=
for bitpos in `seq 1 $bitmap_bin_length`; do
 bitmap_bit=$(expr substr "$bitmap_bin" "$bitpos" 1)
 if [ $bitmap_bit -eq 1 ]; then
  CIDATCAC_bin_bit=$(expr substr "$CIDATCAC_bin" "$bitpos" 1)
  filtered_bin=${filtered_bin}${CIDATCAC_bin_bit}
 fi
done
echo "filtered_bin = $filtered_bin"
# Note: if ATC>0x26(38) then response = 8 characters
# if ATC=0xFFFF(65536) then response = 12 characters !!! is this correct ?

filtered_dec=$(bintodec $filtered_bin)
echo "RESPONSE = $filtered_dec"

exit


# this is never executed

if false; then
# Make AND of ARQC and Cap bit Filter:
fortis: 77269F2701 00 9F3602 00B7 9F260886F857BEB767E8FB 9F100F 0601560384B0A80701030000000000
kbc:    77269F2701 00 9F3602 0004 9F260831F94BDAB5DF0F38 9F100F 0601560384B0400701030000000000
kbc: 77269F2701 00 9F3602 0005 9F2608B29D6D20BFE004AD 9F100F 0601560384B0400701030000000000
# extracted values
output 00 00B7 86F857BEB767E8FB 0601560384B0A80701030000000000
output 00 0004 31F94BDAB5DF0F38 0601560384B0A80701030000000000
bitmask 00 00FF 000000000003FFFF
filter .. ..04 ...........30F38
binary     0100 110000111100111000
decimal 1249080
fi




Example protocol log:

Collected from a NatWest reader and card performing a respond computation
(ISO 7816, T=0 protocol). Personal details have been redacted.

Command:   00a4040007 (select application)
Proc:      a4
Data:      a0000000048002
Proc:      61
Status:    6112 (more data available)

Command:   00c0000012 (application selected)
Proc:      c0
Data:      6f108407a0000000048002a5055f2d02656e
Proc:      90
Status:    9000 (OK)

Command: 80a8000002 (initiate transaction)
Proc:    a8
Data:    8300
Proc:    61
Status:  6108 (more data available)

Command: 00c0000008 (transaction initiated)
Proc:    c0
Data:    8006100008010100
Proc:    90
Status:  9000 (OK)

Command: 00b2010c00 (get static data length)
Proc:    6c
Status: 6c57 (wrong length)

Command: 00b2010c57 (read static data)
Proc:    b2
Data:    7055
          8e0a 00000000000000000100 (CVM list)
          9f5501 a0 (unknown)
          9f5612 00001f00000000000fffff00000000008000 (bit filter)
          8c15 9f02069f03069f1a0295055f2a029a039c019f3704 (CDOL1)
          8d17 8a029f02069f03069f1a0295055f2a029a039c019f3704 (CDOL2)
Proc:    90
Status: 9000 (OK)

Command: 80ca9f1700 (get PIN try counter length)
Proc:    6c
Status: 6c04 (wrong length)

Command: 80ca9f1704 (get PIN try counter)
Proc:    ca
Data:    9f170103 (3 remaining tries)
Proc:    90
Status:  9000 (OK)

PIN entered: ?

Command: 0020008008 (verify PIN)
Proc:    20
Data:    24xxxxffffffffff
Proc:    90
Status:  9000 (OK)

Challenge entered: 12345678

Command: 80ae80001d (generate ARQC)
Proc:    ae
Data:    0000000000000000000000000000800000000000000000000012345678
Proc:    61
Status:  6114 (more data available)

Command: 00c0000014 (return ARQC)
Proc:    c0
Data:    80 1280 0042b7f9a572da74caff 06770a03a48000
Proc:    90
Status:  9000 (OK)

Command: 80ae00001f (generate AC)
Proc:    ae
Data:    5a330000000000000000000000000000800000000000000000000012345678
Proc:    61
Status:  6114 (more data available)

Command: 00c0000014 (return AAC)
Proc:    c0
Data:    80 1200 00424f1c597723c97d78 06770a03258000
Proc:    90
Status:  9000 (OK)

Response returned: 4822527



donderdag 31 januari 2013

Love is Math As Well


We don't remember what it was like
that first time
what we talked about 
whether we showed each other things 
which we didn't yet have
the stale wines
in the polished vases
warm bodies in winter
whether we read
from closed books
added ourselves together and 
knew we never
would have to divide
together exponential
a multiplication with
in the cross that we
no longer wanted to carry
a conclusive casting out of nines.

[I translated "Liefde is ook Wiskunde" by Bart Plouvier from Dutch to English for the national poetry day in Belgium.]