Proxmark3 community

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.

Announcement

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.

#1 2009-08-13 21:44:51

rich
Member
Registered: 2009-07-07
Posts: 14

Multi-section Authentication with Card-Only attack

Any body knows the detailed the atuthentication about multi-section?? The card sends encrypted tag-nonce to reader, 2008-esorics.pdf said that "The difference is that now the tag nonce NT is sent encrypted with K' while it is fed into the LFSR (resembling the way the reader nonce is fed in).", K' is the new KEY for next section. But the Reader how to decrypt it to get uncrypted NT? Do the Crypto1 need reset and load new KEY for next section then to decrypt it??

Any advertise, Thanks~~~

Offline

#2 2009-08-14 03:39:28

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Thanks for your detailed explanation. I will try it again.

Offline

#3 2009-08-14 22:35:28

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Hi, Dear hat, another question:

When load new key, what is the prng's state? Does it need to reset too or remain it's state??
I try to trace with tow consecutive authentication for same block, but get below:
1.
14443A REQA.
(0400)(1E2D386F64)[1E2D386F64]Request mode.
[]14443A Select.
(0400)[08]Set KEY OK : FFFFFFFFFFFF
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
NT: 79A5A325. OK!
Crypto1 Auth step 2.
NT': ABCD1949
Authentication OK.
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
Set KEY OK : FFFFFFFFFFFF
!! 04 bytes and 00 bits received.
[01 A8 00 66 01 67 01 93 ]
!! Wrong parity on card nonce. Abort


2.
14443A REQA.
(0400)(1E2D386F64)[1E2D386F64]Request mode.
[]14443A Select.
(0400)[08]Set KEY OK : FFFFFFFFFFFF
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
NT: B9567503. OK!
Crypto1 Auth step 2.
NT': ABCD1949
Authentication OK.
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
Set KEY OK : FFFFFFFFFFFF
!! 04 bytes and 00 bits received.
[01 70 01 D3 01 89 00 90 ]
NT: 90D9A81F. OK!
REV NT: 099B15F8. OK!
Crypto1 Auth step 2.
NT': ABCD1949
!! 00 bytes and 00 bits received. Abort2


The second NT: 90D9A81F and revert NT: 099B15F8 both are not correct prng. How it happen??

Would you give some advertise??

Thanks~~~

Offline

#4 2009-08-15 08:19:09

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Ha~~, sorry for my mistakes.

But really thanks for you~~.

I received the encrypted NT with parity is [01 70 01 D3 01 89 00 90 ] and then decrypt it to get the uncrypted NT: 90D9A81F.
But the NT: 90D9A81F is not a correct prng, so I adjusted the byte order and bit order, It still is not a correct prng.

So I have no idea for this currently.

Offline

#5 2009-08-15 13:06:59

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Hi, hat, thanks for your care. You are very nice guy.

Below is the my two new trace:
1.
14443A REQA.
(0400)(1E2D386F64)[1E2D386F64]Request mode.
[]14443A Select.
(0400)[08]Set KEY OK : FFFFFFFFFFFF        // Initialize Crypto1 and load key
UID+CRC : 1E2D386F64
Crypto1 Auth step 1.                         // Start first authentication
Auth: 60 | Block: 3C
NT: D890739A. OK!
Crypto1 Auth step 2.
NT': ABCD1949
Authentication OK.                         // first authentication success.
UID+CRC : 1E2D386F64
Crypto1 Auth step 1.                      // start second authentication for same section with same key
Auth: 60 | Block: 3C
Set KEY OK : FFFFFFFFFFFF              // reset Crypto1 and reload key
!! 04 bytes and 00 bits received.
[00 E1 00 71 01 FB 00 E9 ]                 // encrypted tag nonce with parity.
UID: 1E2D386F. OK!                           // UID.
Decrypt received data.
[01 4C 00 CC 01 9B 01 17 ]                // decrypted tag nonce with parity.
!! Wrong parity on card nonce. Abort

2.
14443A REQA.
(0400)(1E2D386F64)[1E2D386F64]Request mode.
[]14443A Select.
(0400)[08]Set KEY OK : FFFFFFFFFFFF
UID+CRC : 1E2D386F64
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
NT: 0024A028. OK!
Crypto1 Auth step 2.
NT': ABCD1949
Authentication OK.
UID+CRC : 1E2D386F64
Crypto1 Auth step 1.
Auth: 60 | Block: 3C
Set KEY OK : FFFFFFFFFFFF
!! 04 bytes and 00 bits received.
[01 F1 00 26 01 7F 01 F6 ]
UID: 1E2D386F. OK!
Decrypt received data.
[00 7E 01 31 01 D4 01 7C ]
!! Wrong parity on card nonce. Abort

I tested reading block after the first authentication, I got the right block data.
So It seems that the Crypto1 reset incorrectly when second authencation. I am checking.
Thanks for your help and information again.

Offline

#6 2009-08-15 15:27:05

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Oh, yeah, I am very lucky.

I have gotten the correct nonce with the modified test.c according to your idea.

Thanks a lot.

But whether or not one can recovery the KEY just with KS1?
I used below code to test, get a wrong KEY:

struct Crypto1State *state, *revstate;
uint64_t key;
uint32_t ks1 = 0xFF7F897D;
revstate = lfsr_recovery32(ks1, 0);
lfsr_rollback(revstate, 0, 0);
crypto1_get_lfsr(revstate, &key);

I get the KEY[0x92B0E8F5F75F], but the real KEY is 0xFFFFFFFFFFFF.

Offline

#7 2009-08-15 18:40:30

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

I test the my result with below code:

  1 #include "crapto1.h"
  2 #include <stdio.h>
  3 struct TestCase{
  4     uint64_t key;
  5     uint32_t uid, tag_challenge, reader_challenge;
  6 } tc[] = {{0xffffffffffffULL, 0x1E2D386F, 0x2220A664, 0x12345678},
  7           {0xffffffffffffULL, 0x1E2D386F, 0x7FC9BB6B, 0x851E2949}};
  8 
  9 int main (void)
 10 {
 11     struct Crypto1State *state, *revstate;
 12     uint32_t k, ks1, nonce, ks3;
 13     uint64_t lfsr;
 14     uint64_t key;
 15 
 16         printf("Get NT:\n");
 17     for(k = 0; k < 2; k++)
 18     {
 19         state = crypto1_create(tc[k].key);
 20         ks1 = crypto1_word(state, tc[k].uid ^ tc[k].tag_challenge, 1);
 21 
 22         printf("Case %d : UID=[0x%08X], NT_ENC=[0x%08X]\n", k, tc[k].uid, tc[k].tag_challenge);
 23         printf("ks1: 0x%08X\n", ks1);
 24         nonce = ks1 ^ tc[k].tag_challenge;
 25         printf("NT: 0x%08X\n", nonce);
 26         printf("\n");
 27         printf("Guess KEY:");
 28         revstate = lfsr_recovery32(ks1, 0);
 29         do{
 30         lfsr_rollback(revstate, tc[k].uid^nonce, 0);
 31         crypto1_get_lfsr(revstate,&key);
 32         if(key == (uint64_t)0xFFFFFFFFFFFFULL)
 33         {
 34             printf("[0x%012LX]\n",key);
 35             break;
 36         }
 37         revstate++;
 38         }while((revstate->odd != 0x0) || (revstate->even != 0x0));
 39     }
 40 
 41     return 0;
 42 }

I still can not get the real KEY 0xFFFFFFFFFFFF, I think the KS1 is wrong. I will continue checking.

Offline

#8 2009-08-18 10:08:29

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Oh, yeah...
I find my mistake.

But I get a new question about nested authentication.

In page 16 of 2008-esorics.pdf, it states:

Using the parity bits, however, the number of possible tag nonces can be
drastically reduced. The first three parity bits, say p0 , p1 , p2 , of the tag nonce
nT are encrypted with the keystream bits that are also used to encrypt bits n8 ,
n16 , and n24 of nT . That is, from the communication we can observe p0 ⊕ b8 ,
n8 ⊕ b8 , where b8 is the keystream bit that is used to encrypt n8 , and similarly
for the other two parity bits. From this we can see whether or not p0 , the parity
of the first byte of nT , is equal to n8 , the first bit of the second byte of nT .
This information decreases the number of potential nonces by a factor of 2.
The same holds for the other 2 parity bits in nT and for the 7 parity bits in
suc2 (nT ) and suc3 (nT )
. In total, the search space is reduced from 216 nonces to
only 216 /210 = 64 nonces.

I can understand the first three paritiy of NT, but I can not understand the blue text states about 7 parity suc2(NT) and suc3(NT).
How to use them?
Cause after the first authentication known key sector, we will authenticate a unknown key sector. For the second authentication,
we just get a encrypted tag nonce {NT}, we can not get the encrypted parity of suc2(NT) and suc3(NT).
So, what relation about 7 parity of suc2(NT) and suc3(NT) to {NT}?

I am confusing.....

Hi, hat, could you give help?

Last edited by rich (2009-08-18 16:03:25)

Offline

#9 2009-08-20 20:15:27

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

I get another problem~~
I use traced data to verify the thoery 2008-esorics.pdf indicated that b0^b1^b2^b3^b4^b5^b6^b7^b8={p0}^{b8}^1.
I tested some data, but some is ok, some is fail.
I don't know why.
Below is my trace data and code:
TRACE:

Red: [ 60 3C ]                                                        //start first authentication
Tag: DD 1 85 0 3F 1 68 0 
Red: [ AB 0 CD 0 19 0 49 0  23 0 5F 1 F6 1 B1 1 ]
Enc: { BD 1 16 0 65 1 D6 0  D1 1 1C 0 F9 1 C7 1 }
Tag: { 60 0 03 0 70 0 CF 1 }
Authentication OK.                                             //first authentication ok
Red: [ 60 3C ]  { EA AE }                                //start second authentication immediatly,send encrypted command
Tag: { 1B 0 AB 0 D4 1 3F 1 }                             // encrypted card nonce
Dec: [ E4 1 F4 0 E6 0 A0 1 ]                                // decrypted card nonce
Red: [ AB 0 CD 0 19 0 49 0  71 1 56 1 90 1 CB 0 ]
Enc: { E3 0 DD 1 8A 0 6B 0  05 1 FE 1 F0 1 BF 1 }
Tag: { 97 1 CC 1 C3 1 57 1 }
Authentication OK.                                                //second authentication ok

Red: [ 60 3C ]
Tag: BF 0 DB 1 FA 1 E0 0 
Red: [ AB 0 CD 0 19 0 49 0  C6 1 E0 0 E9 0 EB 1 ]
Enc: { 8A 0 9D 0 2B 1 70 0  E2 1 DE 0 8B 1 1A 0 }
Tag: { C8 0 2D 0 66 0 85 0 }
Authentication OK.
Red: [ 60 3C ]  { 26 32 }
Tag: { 9B 1 3B 1 F5 1 D8 0 }
Dec: [ 64 0 64 0 D2 1 22 1 ]
Red: [ AB 0 CD 0 19 0 49 0  0B 0 39 1 A0 1 31 0 ]
Enc: { E2 1 D2 1 14 0 6F 0  3D 0 8F 1 2E 1 65 0 }
Tag: { 6F 0 81 1 2E 0 49 0 }
Authentication OK.

Red: [ 60 3C ]
Tag: 0A 1 31 0 E1 1 52 0 
Red: [ AB 0 CD 0 19 0 49 0  06 1 DB 1 7F 0 28 1 ]
Enc: { D0 0 9D 1 FA 0 29 0  40 1 27 1 B1 0 2A 1 }
Tag: { 54 1 25 0 1E 1 E5 1 }
Authentication OK.
Red: [ 60 3C ]  { A4 F1 }
Tag: { 8B 0 6B 0 F5 0 7E 1 }
Dec: [ 74 1 14 1 44 1 B3 0 ]
Red: [ AB 0 CD 0 19 0 49 0  15 0 1F 0 CA 1 8B 1 ]
Enc: { 3A 0 CF 1 72 0 29 0  95 1 74 0 48 1 25 1 }
Tag: { C1 0 AE 0 15 0 DB 1 }
Authentication OK.

Red: [ 60 3C ]
Tag: C3 1 EB 1 15 0 83 0 
Red: [ AB 0 CD 0 19 0 49 0  47 1 67 0 44 1 D1 1 ]
Enc: { 5E 1 1C 1 DE 1 70 1  FA 0 A2 0 E0 0 8E 0 }
Tag: { 6C 1 C3 1 D2 1 E8 0 }
Authentication OK.
Red: [ 60 3C ]  { 59 90 }
Tag: { CB 1 6A 1 B5 1 49 0 }
Dec: [ 34 0 15 0 76 0 E2 1 ]
Red: [ AB 0 CD 0 19 0 49 0  67 0 2A 0 E1 1 4C 0 ]
Enc: { EC 0 CB 1 1A 1 90 0  C3 0 22 1 B0 1 8E 0 }
Tag: { CC 1 AC 0 0C 0 4B 1 }
Authentication OK.

Red: [ 60 3C ]
Tag: E8 1 A1 0 A0 1 98 0 
Red: [ AB 0 CD 0 19 0 49 0  C9 1 12 1 B4 1 34 0 ]
Enc: { 3B 0 77 0 F7 0 99 0  E1 0 75 1 48 0 9B 0 }
Tag: { 8C 1 0C 0 CA 0 E8 1 }
Authentication OK.
Red: [ 60 3C ]  { 28 0E }
Tag: { 55 0 CC 1 A6 0 58 1 }
Dec: [ AA 1 BB 1 E8 1 C7 0 ]
Red: [ AB 0 CD 0 19 0 49 0  E4 1 21 1 AE 0 1C 0 ]
Enc: { FE 0 6B 1 4C 0 B9 1  97 0 62 1 54 1 F1 1 }
Tag: { 38 0 35 0 FC 0 EA 0 }
Authentication OK.

Red: [ 60 3C ]
Tag: 0E 0 19 0 A4 0 BC 0 
Red: [ AB 0 CD 0 19 0 49 0  9C 1 BC 0 CC 1 61 0 ]
Enc: { BE 0 81 0 61 0 DF 1  77 0 37 0 9E 1 B1 1 }
Tag: { 89 1 02 1 D7 1 FB 0 }
Authentication OK.
Red: [ 60 3C ]  { DE 23 }
Tag: { 9D 1 EB 0 2E 1 0E 1 }
Dec: [ 62 0 CC 1 95 1 A8 0 ]
Red: [ AB 0 CD 0 19 0 49 0  7B 1 BA 0 79 0 2E 1 ]
Enc: { EC 0 BD 1 1A 0 4D 0  11 0 8F 1 FC 0 00 0 }
Tag: { E4 0 C1 0 83 0 DA 0 }
Authentication OK.

Red: [ 60 3C ]
Tag: 8D 1 3D 0 B3 0 0C 1 
Red: [ AB 0 CD 0 19 0 49 0  48 1 85 0 99 1 18 1 ]
Enc: { E3 1 80 1 2C 0 27 0  44 0 D8 1 60 0 1D 1 }
Tag: { D0 1 B8 1 49 0 5A 0 }
Authentication OK.
Red: [ 60 3C ]  { 79 5F }
Tag: { 6D 1 A8 1 0C 1 FD 0 }
Dec: [ 92 0 6F 1 F8 0 BA 0 ]
Red: [ AB 0 CD 0 19 0 49 0  D4 1 D3 0 C5 1 33 1 ]
Enc: { 01 1 F0 0 BF 1 26 1  49 0 82 0 A9 0 8A 0 }
Tag: { 03 0 D1 1 03 0 EE 1 }
Authentication OK.

CODE:

uint8_t Parity_Byte(uint8_t byte)
{
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  byte ^= byte >> 1;
  return ((byte&0x01)^0x01);
}
    
uint8_t isRight(uint32_t nt, uint32_t nt_enc, uint8_t parity)
{
  int i = 0;
  uint8_t r0 = 0;
  printf("Verifying : 0x%08X, 0x%08X, 0x%X\n", nt, nt_enc, parity);
  for( i = 3; i >0; i--)
  {
    r0 ^= Parity_Byte((nt>>(i*8))&0xFF) ^ ((nt_enc>>(i*8-1))&0x01) ^ ((parity>>i)&0x01) ^ ((nt>>(i*8-1))&0x01);
  }
  printf("Verify Result (r0 = %x)\n", r0);
  if( r0 == 0 )
  {
    return 1;
  }
  return 0;
}
int main (int argc, char **argv)
{
  uint32_t nt_to = 0;
  uint32_t nt_enc = 0;
  uint8_t parity = 0;
  nt_to = (uint32_t)strtoll(argv[1],NULL,16)&0xFFFFFFFF;
  nt_enc = (uint32_t)strtoll(argv[2],NULL,16)&0xFFFFFFFF;
  parity = (uint32_t)strtol(argv[3],NULL,2)&0xFF;
  

    printf("0x%08X\n", nt_to);
    if(isRight(nt_to, nt_enc, parity))
        printf( "Verify Ok.\n");
    else
      printf("Verify Error.\n");
  }

  return 0;
}

I compile it to guessnt, then run it with ./guessnt nt enc_nt enc_parity, like this ./guessnt E4F4E6A0 1BABD43F 0011

I tested traced data, but get strange results.

Last edited by rich (2009-08-20 20:22:31)

Offline

#10 2009-08-21 19:31:54

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Yeah, hat, you are right.

I verified my trace use your code. It is perfect! I make too many mistakes.

Thanks a lot.

Offline

#11 2009-08-21 19:50:27

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

In Crapto1-2.3, the function

struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in)

should return a state list.
The length of returned state list should be 65536(2^16) exactly, right?

If we feed any 32bits ks2, it should always get 65536 different states.
But I get many different numbers, some more than 65536, some less. Why?

And it said that

* recover the state of the lfsr given 32 bits of the keystream
* additionally you can use the in parameter to specify the value
* that was fed into the lfsr at the time the keystream was generated

.
So, I think it means that if we feed the ks1, then we call the function like

lfsr_recovery32(ks1, uid^tag_nonce);

, then we can get 65536 possible initial state of lfsr, right?

Last edited by rich (2009-08-21 19:59:35)

Offline

#12 2009-08-22 07:51:27

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

I have gotten the latest code - Crapto1-v2.4. And I diff them, it seems just updated for memory manage.
I tested ks1 with the new code. The result is still different number.
And I rollback them with below code:

      ks1 = (guess_nt)^nt_enc;
                count = 0;
    revstate = lfsr_recovery32(ks1, 0);
  
    while((revstate->odd != 0x0) || (revstate->even != 0x0)){
      lfsr_rollback(revstate, (guess_nt)^uid, 0);
      crypto1_get_lfsr(revstate,&key);
      revstate++;
      count++;
    }

The possible KEY is not just 65536 too, and I can not get my default key from those possible KEYs.
Has my rollback code some problem?

Last edited by rich (2009-08-22 07:59:48)

Offline

#13 2009-08-24 18:00:31

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Hi, hat, thanks for your patience.

And excuse me, what is the real of /* come on ...*/?
I try 3 codes as below:

1st

      ks1 = (guess_nt)^nt_enc;
                count = 0;
    revstate = lfsr_recovery32(ks1, 0);
  
    while((revstate->odd != 0x0) || (revstate->even != 0x0)){
      lfsr_rollback(revstate, (guess_nt)^uid, 0);
      crypto1_get_lfsr(revstate,&key);
      printf("possible key: %qx\n", key);
      revstate++;
      count++;
    }

2nd

      ks1 = (guess_nt)^nt_enc;
                count = 0;
    revstate = lfsr_recovery32(ks1, 1);
  
    while((revstate->odd != 0x0) || (revstate->even != 0x0)){
      lfsr_rollback(revstate, (guess_nt)^uid, 0);
      crypto1_get_lfsr(revstate,&key);
      printf("possible key: %qx\n", key);
      revstate++;
      count++;
    }

3rd

      ks1 = (guess_nt)^nt_enc;
                count = 0;
    revstate = lfsr_recovery32(ks1, (guess_nt)^uid);
  
    while((revstate->odd != 0x0) || (revstate->even != 0x0)){
      lfsr_rollback(revstate, (guess_nt)^uid, 0);
      crypto1_get_lfsr(revstate,&key);
      printf("possible key: %qx\n", key);
      revstate++;
      count++;
    }

Just the 3rd code can get the default KEY FFFFFFFFFFFF.
I get the correct result, but I don't know why.

So, could you help me?

Thanks a lot.

Last edited by rich (2009-08-24 18:02:18)

Offline

#14 2009-08-24 20:17:01

phadom
Member
Registered: 2009-03-30
Posts: 14

Re: Multi-section Authentication with Card-Only attack

The third code works cause if you see the description of the lfsr recovery32 in crapto it clearly states that it takes two inputs. One of them is the keystream, in this case ks1 and the other is the variable in, where in is what it was fed into the LFSR at the point when the keystream was made. If you see the how the crypto 1 works, you will understand why the third instance works and the others dont even make sense.

Offline

#15 2009-08-24 23:56:55

rich
Member
Registered: 2009-07-07
Posts: 14

Re: Multi-section Authentication with Card-Only attack

Oh, yeah, I get, thanks a lot.

Offline

Board footer

Powered by FluxBB