Research, development and trades concerning the powerful Proxmark3 device.
Remember; sharing is caring. Bring something back to the community.
"Learn the tools of the trade the hard way." +Fravia
You are not logged in.
Time changes and with it the technology
Proxmark3 @ discord
Users of this forum, please be aware that information stored on this site is not private.
Hi there,
I was able to recover the key and decrypt a communication, sniffed with proxmark. In the following you can see an excerpt:
Decrypted trace:
READER 30 01 8B B9
TAG 01 02 03 04 05 00 00 00 09 0A 0B 0C 0D 0E 80 79 85 A4
READER 30 02 10 8B
TAG 01 03 10 20 01 12 01 A7 43 25 9F 0A 07 66 08 E2 6C 11
READER 30 03 99 9A
TAG 00 00 00 00 00 00 63 C7 89 00 00 00 00 00 00 00 27 6C
READER 60 0C 99 B1
TAG 79 B2 27 D7
READER 9F 17 D7 DB A5 14 2D B8
TAG 10 82 30 8C
READER 8B 7B E0 D4
TAG 95 50 98 F3 9A 95 05 0C 30 D0 EF 1F AF EF 42 26 74 44
READER 90 C5 25 21
TAG A7 08 1F C6 20 6B 9A 79 4C 89 65 41 69 C0 AE 5F 9F DD
READER 9E 53 93 D4
...
One can see that block 1,2 and 3 are read. Then another authentication starts with
READER 60 0C 99 B1
and I don't know how to handle it.
I just tried to treat the following messages as tag nonce, reader response (including reader challenge) and tag response to compute the key. I have taken the decrypted messages which you see here as well as the encrypted messages from the original trace to reveal the key.
Using crapto1 I get something which could be the key, but if I replay the authentication phase with henryk's crypto1 implementation the mutual2 authentication fails.
Maybe you have some ideas?
Offline
Well, this is a typical case of nested authentication. So I had a look at the forum and a bunch of documents which didn't reveal the answer to my question: "how does it work?"
What I got:
1. during an encrypted data transfer the 60 auth request is sent following
2. the encrypted tag nonce
So, now there is the problem that I try to recover the key with the following code:
struct Crypto1State *revstate;
uint64_t lfsr;
unsigned char* plfsr = (unsigned char*) &lfsr;
uint32_t ks2 = reader_response ^ prng_successor(tag_challenge, 64);
uint32_t ks3 = tag_response ^ prng_successor(tag_challenge, 96);
revstate = lfsr_recovery64(ks2, ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, nr_enc, 1);
lfsr_rollback_word(revstate, uid ^ tag_challenge, 0);
crypto1_get_lfsr(revstate, &lfsr);
uint64_t key = plfsr[5];
key = (key << 8) | plfsr[4];
key = (key << 8) | plfsr[3];
key = (key << 8) | plfsr[2];
key = (key << 8) | plfsr[1];
key = (key << 8) | plfsr[0];
where nr_enc is the encoded reader nonce and the rest of the variables should be self-explaining.
This code expects uid, tag challenge, reader challenge, reader response and tag response to be fed in.
Are reader challenge, reader response and tag response sent in plaintext?
Offline
>>Are reader challenge, reader response and tag response sent in plaintext?
no.
reader response and tag response are poorly named. it requires the encypted versions of the reader respone and tag response. as they are "on the metaphorical" wire.
the tag challenge however is a different matter.
the tag challenge is unknown. we have to brute force it.
since there are only 2^16 minus 1 valid nonces. and you can execute the code you provided several times per second, it would only take a matter of hours.
for(tagchal = 1; ;tagchal=prng_successor(tagchal)){ try it}
you can however do better. using the parity bits. however your log doesn't seem to include them (those are the exclamation marks you see in the standard output of some tools). more details on that are in the documents. however iirc there are about 10 usable parity bits which each half the search space leaving you with only 64 tag challenges to try. iirc2 the latest crapto releases have code that does that.
Offline
Hi,
Do anyone wrote code to decode nested authentication?
Or it needs to write from scratch?
if (!traceCrypto1) {
// here all ok
ks2 = ar_enc ^ prng_successor(nt, 64);
ks3 = at_enc ^ prng_successor(nt, 96);
revstate = lfsr_recovery64(ks2, ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, nr_enc, 1);
lfsr_rollback_word(revstate, uid ^ nt, 0);
}else{
// here nt_enc instead of nt
ks2 = ar_enc ^ prng_successor(nt, 64);
ks3 = at_enc ^ prng_successor(nt, 96);
revstate = lfsr_recovery64(ks2, ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, nr_enc, 1);
lfsr_rollback_word(revstate, uid ^ nt, 0);
}
crypto1_get_lfsr(revstate, &lfsr);
printf("\nFound Key: [%02x %02x %02x %02x %02x %02x]\n\n",plfsr[5],plfsr[4],plfsr[3],plfsr[2],plfsr[1],plfsr[0]);
Offline