From 9d9f01fba4ee145bc873a85898b74041ca6d8831 Mon Sep 17 00:00:00 2001
From: Philippe Teuwen <phil@teuwen.org>
Date: Fri, 17 Feb 2017 16:14:01 +0100
Subject: [PATCH] Simplify PRNG validation

---
 src/crapto1.c |  6 ++++++
 src/crapto1.h |  2 ++
 src/mfoc.c    | 55 +++++----------------------------------------------
 3 files changed, 13 insertions(+), 50 deletions(-)

diff --git a/src/crapto1.c b/src/crapto1.c
index 94995f3..e94840d 100644
--- a/src/crapto1.c
+++ b/src/crapto1.c
@@ -374,6 +374,12 @@ int nonce_distance(uint32_t from, uint32_t to)
   }
   return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535;
 }
+bool validate_prng_nonce(uint32_t nonce)
+{
+  // init prng table:
+  nonce_distance(nonce, nonce);
+  return ((65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535) == 16;
+}
 
 
 static uint32_t fastfwd[2][8] = {
diff --git a/src/crapto1.h b/src/crapto1.h
index 4b8c90c..525a02f 100644
--- a/src/crapto1.h
+++ b/src/crapto1.h
@@ -20,6 +20,7 @@
 #ifndef CRAPTO1_INCLUDED
 #define CRAPTO1_INCLUDED
 #include <stdint.h>
+#include <stdbool.h>
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -39,6 +40,7 @@ extern "C" {
   void lfsr_rollback(struct Crypto1State *s, uint32_t in, int fb);
   uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
   int nonce_distance(uint32_t from, uint32_t to);
+  bool validate_prng_nonce(uint32_t nonce);
 #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
   uint32_t __n = 0,__M = 0, N = 0;\
   int __i;\
diff --git a/src/mfoc.c b/src/mfoc.c
index 052014c..6e3538b 100644
--- a/src/mfoc.c
+++ b/src/mfoc.c
@@ -72,41 +72,6 @@ uint32_t unknownSector = 0;
 char unknownKeyLetter = 'A';
 uint32_t unexpected_random = 0;
 
-// Determine the distance between two nonces.
-// Assume that the difference is small, but we don't know which is first.
-// Therefore try in alternating directions.
-int32_t dist_nt(uint32_t nt1, uint32_t nt2) {
-
-        if (nt1 == nt2) return 0;
-
-        uint16_t i;
-        uint32_t nttmp1 = nt1;
-        uint32_t nttmp2 = nt2;
-
-        for (i = 1; i < (32768/8); ++i) {
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -i;
-
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+1;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+1);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+2;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+2);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+3;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+3);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+4;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+4);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+5;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+5);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+6;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+6);
-                nttmp1 = prng_successor(nttmp1, 1);     if (nttmp1 == nt2) return i+7;
-                nttmp2 = prng_successor(nttmp2, 1);     if (nttmp2 == nt1) return -(i+7);
-        }
-        // either nt1 or nt2 are invalid nonces
-        return(-99999);
-}
-
-
 int main(int argc, char *const argv[])
 {
   int ch, i, k, n, j, m;
@@ -1093,23 +1058,13 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
       }
       NtLast = bytes_to_num(Rx, 4) ^ crypto1_word(pcs, bytes_to_num(Rx, 4) ^ t.authuid, 1);
 
+      // Make sure the card is using the known PRNG
+      if (! validate_prng_nonce(NtLast)) {
+           printf("Card is not vulnerable to nested attack\n");
+           return -99999;
+      }
       // Save the determined nonces distance
       d->distances[m] = nonce_distance(Nt, NtLast);
-      int checkForValidPRNG = dist_nt(Nt, NtLast);
-      //printf("NT distance: %d\n", checkForValidPRNG);
-
-      // if no distance between,  then we are in sync.
-      if (checkForValidPRNG == 0) {
-          printf("NT Distance is zero..........\n");
-      } else {
-          if (checkForValidPRNG == -99999) { // invalid nonce received
-              ++unexpected_random;
-              if (unexpected_random > 4) {
-                   printf("PRNG is not vulnerable to nested attack\n");
-                   return -99999;
-              }
-          }
-      }
 
       // Again, prepare and send {At}
       for (i = 0; i < 4; i++) {