问题
I'm trying to emulate a PoS, point of sale :), system and complete a transaction with Google wallet running on a 2013 Nexus 7 (no secure element) v4.4.2.
My PoS prototype is also running on a 2013 Nexus 7 v4.4.2.
I'm able to get NFC responses from the 2PAY_SYS_DDF01 request. I'm able to select the MasterCard application ID. I'm able to get Processing Options. When I Read Records it doesn't look like Google wallet is returning all the mandatory EMV fields. And finally when I request the Generate AC command it always returns 6D00 unsupported.
Area of the code that is a problem:
//set P1 to '40', to request an Transaction Certificate (offline transaction)
//and execute the Generate AC command.
byte[] generateAC = new byte[] {(byte)0x80, (byte)0xAE, 0x40, 0x00,
0x1D, //data length
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, //amount1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //amount2
0x08, 0x40, //term country
0x00, 0x00, 0x00, 0x00, 0x00, //tvr
0x09, 0x62, //tx curr
0x14, 0x04, 0x1B, //tx date
0x00, //tx type
0x12, 0x34, 0x56, 0x78, //random
0x00}; //le
response = isoDep.transceive(generateAC);
I was following Tim Beckers video https://www.youtube.com/watch?v=qqobg1-HrfY approx. 46 minutes in. and Tim Beckers code sample: https://github.com/a2800276/29c3/blob/master/smartshell.rb
UPDATE:
The response to the GPO command (80 a8 00 00 02 83 00 00
) is
770a820200009404080101009000
77 Response Message Template Format 2
82 Application Interchange Profile
0000
94 Application File Locator (AFL)
08010100
UPDATE:
I tried:
byte[] computeCC = new byte[] {
(byte)0x80, // CLA = proprietary
(byte)0x2A, // INS = COMPUTE CRYPTOGRAPHIC CHECKSUM
(byte)0x8E, // P1
(byte)0x80, // P2
(byte)0x04, // Lc
(byte)0x00, 0x00, (byte)0x00, (byte)0x99, // Unpredicatable Number (numeric)
(byte)0x00, // Le
};
response = isoDep.transceive(computeCC);
hoping to at least get an error that indicated the wrong unpredictable number but I got 6700 incorrect length returned.
Earlier I got a response to Read Record 00 B2 01 0C 00 Part of that response is Card Authentication Related Data [9F69]: Data (Binary): XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX fDDA Version Number: 9F (Card) Unpredictable Number: 6A 04 9F 7E
So I tried that Unpredictable number
byte[] computeCC = new byte[] {
(byte)0x80, // CLA = proprietary
(byte)0x2A, // INS = COMPUTE CRYPTOGRAPHIC CHECKSUM
(byte)0x8E, // P1
(byte)0x80, // P2
(byte)0x04, // Lc
(byte)0x6A, 0x04, (byte)0x9F, (byte)0x7E, // Unpredicatable Number (numeric)
(byte)0x00, // Le
};
response = isoDep.transceive(computeCC);
But I still get 6700 wrong length
UPDATE:
The response to READ RECORD (Record = 1, SFI = 1) command (00 B2 01 0C 00) is:
70 7c 9f 6c 02
00 01 9f 62 06
00 00 00 00 00
38 9f 63 06 00
00 00 00 03 c6
56 29 42 35 33
39 36 XX XX XX
XX 31 XX XX 39
XX XX XX XX 5e
20 2f 5e 31 34
30 37 31 30 31
34 30 31 30 30
30 30 30 30 30
30 30 30 9f 64
01 04 9f 65 02
00 38 9f 66 02
03 c6 9f 6b 13
53 96 XX XX 1X
X9 XX XX d1 40
71 01 40 10 00
00 00 00 0f 9f
67 01 04 9f 69
0f 9f 6a 04 9f
7e 01 9f 02 06
5f 2a 02 9f 1a
02 90 00
--------------------------TLV-------------------------------
Output:
READ RECORD Response Message Template [70]:
Card Transaction Qualifiers (CTQ) [9F6C]:
Data (Binary): 00 01
Bit flags set:
1Bxb8: 0 - Online PIN not Required
1Bxb7: 0 - Signature Not Required
1Bxb6: 0 - Not applicable: Go Online if Offline Data Authentication Fails and Reader is online capable.
1Bxb5: 0 - Not applicable: Switch Interface if Offline Data Authentication fails and Reader supports VIS.
1Bxb4: 0 - Not applicable: Go Online if Application Expired
1Bxb3: 0 - Not applicable: Switch Interface for Cash Transactions
1Bxb2: 0 - Not applicable: Switch Interface for Cashback Transactions
1Bxb1: 0 - RFU
2Bxb8: 0 - Consumer Device CVM not Performed
2Bxb7: 0 - Card doesn't support Issuer Update Processing at the POS
2Bxb6: 0 - RFU
2Bxb5: 0 - RFU
2Bxb4: 0 - RFU
2Bxb3: 0 - RFU
2Bxb2: 0 - RFU
2Bxb1: 1 - RFU
PCVC3 (Track1) [9F62]:
Data (Binary): 00 00 00 00 00 38
Offline Counter Initial Value [9F63]:
Data (Binary): 00 00 00 00 03 C6
Track 1 Data [56]:
Data (ASCII): B5396XXXXXXXXXXXX^ /^14071014010000000000
NATC (Track1) [9F64]:
Data (Binary): 04
PCVC3 (Track2) [9F65]:
Data (Binary): 00 38
Terminal Transaction Qualifiers (TTQ) [9F66]:
Data (Binary): 03 C6
Card CVM Limit [9F6B]:
Data (Binary): 53 96 48 50 17 69 62 32 D1 40 71 01 40 10 00 00 00 00 0F
MSD Offset [9F67]:
Data (Binary): 04
Card Authentication Related Data [9F69]:
Data (Binary): 9F 6A 04 9F 7E 01 9F 02 06 5F 2A 02 9F 1A 02
fDDA Version Number: 9F
(Card) Unpredictable Number: 6A 04 9F 7E
Card Transaction Qualifiers: 01 9F
----------------------------------------
回答1:
The response to the GET PROCESSING OPTIONS command indicates the following Application Interchange Profile (AIP):
82 Application Interchange Profile
0000
Google Wallet is basically a MasterCard (EMV contactless kernel 2), so decoding the AIP according to the rules of Kernel 2 results in the following:
Byte 1, b7 = 0: no SDA supported
b6 = 0: no DDA supported
b5 = 0: no cardholder verification supported
b4 = 0: no terminal risk management to be performed
b3 = 0: no issuer authentication supported
b2 = 0: no on-device cardholder verification supported
b1 = 0: no CDA supported
Byte 2, b8 = 0: no EMV mode supported
The important part is byte 2, bit 8: It indicates that your card does not support EMV mode. Hence, your card/Google Wallet is a PayPass card that supports only Mag-Stripe mode. Therefore, you cannot authenticate transactions using GENERATE AC. Instead, you can only let the card generate dynamic card verification codes (CVC3) using COMPUTE CRYPTOGRAPHIC CHECKSUM:
byte[] computeCC = new byte[] {
(byte)0x80, // CLA = proprietary
(byte)0x2A, // INS = COMPUTE CRYPTOGRAPHIC CHECKSUM
(byte)0x8E, // P1
(byte)0x80, // P2
(byte)0x04, // Lc
(byte)0xWW, (byte)0xXX, (byte)0xYY, (byte)0xZZ, // Unpredicatable Number (numeric)
(byte)0x00, // Le
};
response = isoDep.transceive(computeCC);
Note that the data field of the COMPUTE CRYPTOGRAPHIC CHECKSUM command must be filled with values according to the UDOL (in case there is no UDOL, the default UDOL is 9F6A04
, indicating the unpredictable number, numeric).
The unpredictable number (numeric) is a BCD coded number in the range that is defined by the mag-stripe data file (see the AFL). In the past, for Google Wallet, this was a value between 0 and 99 (i.e. WW='00'
, XX='00'
, YY='00'
, ZZ='00'..'99'
).
UPDATE:
The data read from the card decodes as follows:
70 7c
9f6c 02 Mag-stripe application version number = Version 1
00 01
9f62 06 Track 1 bit map for CVC3
00 00 00 00 00 38
9f63 06 Track 1 bit map for UN and ATC
00 00 00 00 03 c6
56 29 Track 1 data
42 ISO/IEC 7813 structure "B" format
35333936 XXXXXXXX 31XXXX39 XXXXXXXX PAN (ASCII)
5e Field separator "^"
202f Cardholder name " /" (empty, see MC requirements)
5e Field separator "^"
31343037 Expiry date "14"/"07"
313031 Service code "101"
34303130303030303030303030 Track 1 discretionary data
9f64 01 Track 1 number of ATC digits
04
9f65 02 Track 2 bit map for CVC3
00 38
9f66 02 Track 2 bit map for UN and ATC
03 c6
9f6b 13 Track 2 data
5396 XXXX 1XX9 XXXX PAN (BCD)
d Field separator
1407 Expiry date
101 Service code
4010000000000 Track 2 discretionary data
f Padding
9f67 01 Track 2 number of ATC digits
04
9f69 0f UDOL
9f6a 04 Unpredictable number (numeric)
9f7e 01 Mobile support indicator
9f02 06 Amount authorized (numeric)
5f2a 02 Transaction currency code
9f1a 02 Terminal country code
So the card does provide a UDOL. Therefore, the COMPUTE CRYPTOGRAPHIC CHECKSUM command has to be adapted accordingly:
byte[] computeCC = new byte[] {
(byte)0x80, // CLA = proprietary
(byte)0x2A, // INS = COMPUTE CRYPTOGRAPHIC CHECKSUM
(byte)0x8E, // P1
(byte)0x80, // P2
(byte)0x0F, // Lc
// 9f6a 04 Unpredictable number (numeric)
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x12, // two digits according to UN/ATC bit map and number of ATC digits: 6 - 4 = 2
// 9f7e 01 Mobile support indicator
(byte)0x00, // no offline PIN required, no mobile support
// 9f02 06 Amount authorized (numeric)
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, // 1.00
// 5f2a 02 Transaction currency code
(byte)0x09, (byte)0x78, // Euro
// 9f1a 02 Terminal country code
(byte)0x00, (byte)0x40, // Austria
(byte)0x00, // Le
};
response = isoDep.transceive(computeCC);
来源:https://stackoverflow.com/questions/23329585/android-isodep-transceive-on-generate-ac-command-always-returns-6d00-unsupported