Android Question [SOLVED] How to read NFC that require KEY?

Sandman

Expert
Licensed User
Longtime User
I've read the tutorial NFC - Reading and Writing, and it seems understandable. But I have a card that require me to use a KEY to read the data on it. (I have verified this with other apps so I know for certain that the card is a Mifare Classic and that my key is correct.)

My best guess is that I should somehow supply the key in this call:
B4X:
TagTech.RunAsync("ReadNdef", "getNdefMessage", Null, 0)

The Null part is simply described as "Params - Array of parameters". I've searched the forum, and also tried the links in the tutorial (1, 2) without finding any clues on how to do this. I'm not even really sure this is where I'm supposed to give the key.

I feel I'm not able to figure this out by myself, can somebody give a hand?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Upvote 0

Sandman

Expert
Licensed User
Longtime User
That line outputs:

B4X:
Techs: [android.nfc.tech.NfcA, android.nfc.tech.MifareClassic, android.nfc.tech.NdefFormatable]

The list doesn't contant just Ndef so I made a small adjustment in your code. I made a leap of faith and thought that perhaps Ndef and NdefFormatable is the same, so this is what the code looks like at the moment:

B4X:
'        If techs.IndexOf("android.nfc.tech.Ndef") > -1 Then
        If techs.IndexOf("android.nfc.tech.NdefFormatable") > -1 Then
'            TagTech.Initialize("TagTech", "android.nfc.tech.Ndef" , si)
            TagTech.Initialize("TagTech", "android.nfc.tech.NdefFormatable" , si)
            'Connect to the tag
            TagTech.Connect
        Else
            ToastMessageShow("Tag does not support Ndef.", True)
        End If

Not sure if it means anything here, but it seems to connect just fine.
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
I think I've come a little bit further, based on what Erel wrote above. This is what I have at the moment:

B4X:
Private Sub TagTech_Connected (Success As Boolean)

    Dim key(6) As Byte ' Fake key for the forum
    key(0) = 0xA0
    key(1) = 0xA1
    key(2) = 0xA2
    key(3) = 0xA3
    key(4) = 0xA4
    key(5) = 0xA5

    TagTech.RunAsync("Authenticate", "authenticateSectorWithKeyA", Array(key), 0)
    ' TagTech.RunAsync("Authenticate", "authenticateSectorWithKeyB", Array(key), 0)

End Sub


Private Sub Authenticate_RunAsync (Flag As Int, Success As Boolean, Result As Object)
    Log($"Finished trying to auth. Success=${Success}, Flag=${Flag}"$)

    If Success Then
        ' Code to actually initiate the reading
    End If

End Sub

But I'm never able to authenticate successfully. Am I doing the whole thing right, with the key and wrapping it in an array for the RunAsync call? (I've also tried using authenticateSectorWithKeyB, but that didn't work either.)


I should also mention that I init it as MifareClassic now, which seems to be the right way as that's where I can find the auth functions. Is this correct?

B4X:
TagTech.Initialize("TagTech", "android.nfc.tech.MifareClassic", si)
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
Shouldn't it be?
B4X:
Private Sub TagTech_Connected (Success As Boolean)
   Dim key(6) As Byte = Array as Byte(0xA0,0xA1,0xA2,0xA3,0xA4,0xA5)  ' Fake key for the forum
   Dim sector as Int=0 
   TagTech.RunAsync("Authenticate", "authenticateSectorWithKeyA", Array( sector, key ), 0)
End Sub

If this doesn't help, check THIS APP to communicate with Tags for which you know the keys. It is a great tool that saved me a lot of headaches, since using it helps to double-check that your device is compatible and also the tag is "correct" (and also to make backups of its data)
I didn't go deep into it with android since it was for an embedded project with an external reader. I still have some Mifare Classic tags here with me. If the solution above does not help I can try some code with them and help you figure out the solution.
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Hi JordiCP,

Yes, that worked a lot better, thanks! Seems I hadn't entirely wrapped my head around how to use the Android docs to call from B4A. Your code certainly helped there also.

So now I can successfully authenticate, but strangely enough it reports that it works even when I supply a bad key. I wonder why that is...

Normally I'd give my best effort to handle the rest (the reading) myself, but for this I'm under quite a bit of time pressure. Would it be possible for you to also help me with code on how to actually read the sector?

Did you figure out what the difference of KeyA and KeyB is? I'm only interested in reading the sectors, never writing. Does that perhaps mean I can simply ignore KeyB?

And great app you linked to, that's the app I use - can very much recommend it! For forum readers, I can also recommend NFC Tools to easily see some metadata about the card (like techs, card type etc).
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
For Mifare Classic cards (the ones that I have worked with), there are two keys for each sector: KeyA and KeyB. Each sector has 4 blocks of 16 bytes.

These Keys, along with ACL bytes, can grant or deny you access to the different 16-bytes blocks (usually 4) in a sector.
The ACL bytes are used to define what each Key can do (read/write) with the different blocks in that sector.
As the keys (and also these ACL bytes) are stored in the fourth block of each sector, the same ACL bytes can be programmed so that theere won't be read nor write access for that block, resulting in write-once never-modifiable keys (this is what is done in some simple prepaid cards).

In your case, perhaps one of the keys is correct but the other is set to 0xFFFFFFFFFFFF and you have 'free' access to the card contents.
If you read the contents of the first sector with the app, you will see which are the current keys, and also the ACL bytes. By decoding them, you will find (I guess) the answer.
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
Normally I'd give my best effort to handle the rest (the reading) myself, but for this I'm under quite a bit of time pressure. Would it be possible for you to also help me with code on how to actually read the sector?

I would try with (not tested)
B4X:
Private Sub Authenticate_RunAsync (Flag As Int, Success As Boolean, Result As Object)
   Log($"Finished trying to auth. Success=${Success}, Flag=${Flag}"$)
   If Success Then ' Code to actually initiate the reading

      ' blocks start with 0. Now I don't remember if numbering start again for each sector. 
      ' So first block of first sector is always 0. But third block of second sector is 2 or 6, not sure. You will have to test it.
      Dim blockIndex as Int=0  '<-- read first block of current sector (we assume it is sector 0)
      TagTech.RunAsync("readBlock",Array(blockIndex),0)
   EndIf
End Sub

Private Sub readBlock_RunAsync(Flag As Int, Success As Boolean, Result As Object)
   Log($"Finished trying to read. Success=${Success}, Flag=${Flag}"$)
   If Success Then ' Code to actually initiate the reading
      if Result<>Null Then
        Dim myBlock() as byte = Result    'we are expecting a 16-byte array if everything has been ok
        '  From here you can launch the read of the second block if you need it ....
      End If
   End if
End Sub
 
Upvote 0

Similar Threads

Top