czwartek, 26 sierpnia 2021

Python, C# - Prosty generator kluczy Mifare

W tym poście chciałbym przedstawić prosty program do generowania kluczy Mifare. 

[Źródło: https://applover.pl/technology/python]

Program oprócz generowania liczb losowych z podanego zakresu ma też za zadanie każdą z wygenerowanych wartości sprawdzać z kluczami z programu Mifare Classic Tool (można je znaleźć dosyć łatwo w serwisie Github).

C#


Poniżej krótka aplikacja w C# na konsoli:

  1.     class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             Console.WriteLine("Generate/Check Mifare Keys\r\n");
  6.             Console.WriteLine("Pass 'g' to generate keys.");
  7.             Console.WriteLine("Pass 'c' to check keys.");
  8.             Console.WriteLine("Different value close program.");
  9.             Console.WriteLine("Waiting for key...");
  10.  
  11.             ConsoleKeyInfo clickedKey = Console.ReadKey();
  12.  
  13.             if(clickedKey.Key == ConsoleKey.G)
  14.             {
  15.                 Console.WriteLine("\r\n");
  16.                 Console.WriteLine("Selected generate keys:");
  17.                 GenerateKeys();
  18.             }
  19.             else if (clickedKey.Key == ConsoleKey.C)
  20.             {
  21.                 Console.WriteLine("\r\n");
  22.                 Console.WriteLine("Selected check keys:");
  23.                 Console.WriteLine("Pass keys (keyA keyB) (format FFFFFFFFFFFF FFFFFFFFFFFF):");
  24.  
  25.                 string keyA_B = Console.ReadLine();
  26.  
  27.                 string[] keys = keyA_B.Split(' ');
  28.  
  29.                 Console.WriteLine("Passed KeyA: " + keys[0]);
  30.                 Console.WriteLine("Passed KeyB: " + keys[1]);
  31.  
  32.                 if (SearchInFile_CompareKeys(keys[0], keys[1]) != 0)
  33.                 {
  34.                     Console.WriteLine("ERROR MATCH FOUND");
  35.                 }
  36.                 else
  37.                 {
  38.                     Console.WriteLine("OK No keys in txt file");
  39.                 }
  40.             }
  41.  
  42.             Console.ReadKey();
  43.         }
  44.  
  45.         static void GenerateKeys()
  46.         {
  47.             string keyAStr = "";
  48.             string keyBStr = "";
  49.  
  50.             byte operationStatus = 0;
  51.  
  52.             Random rand = new Random(Guid.NewGuid().GetHashCode());
  53.  
  54.             uint[] randomValues = new uint[12];
  55.  
  56.             while(operationStatus == 0)
  57.             {
  58.                 for (uint i = 0; i < randomValues.Length; ++i)
  59.                 {
  60.                     randomValues[i] = (uint)rand.Next(1, 255);
  61.                 }
  62.  
  63.                 keyAStr = String.Format("{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}", randomValues[0], randomValues[1], randomValues[2], randomValues[3], randomValues[4], randomValues[5]);
  64.                 keyBStr = String.Format("{0:X2}{1:X2}{2:X2}{3:X2}{4:X2}{5:X2}", randomValues[6], randomValues[7], randomValues[8], randomValues[9], randomValues[10], randomValues[11]);
  65.  
  66.                 if(SearchInFile_CompareKeys(keyAStr, keyBStr) == 0)
  67.                 {
  68.                     Console.WriteLine("Keys generate properly: \r\n");
  69.                     Console.WriteLine("keyAStr:" + keyAStr + "\r\n");
  70.                     Console.WriteLine("keyBStr:" + keyBStr + "\r\n");
  71.                     operationStatus = 1;
  72.                 }
  73.             }
  74.         }
  75.  
  76.         static byte SearchInFile_CompareKeys(string keyA, string keyB)
  77.         {
  78.             string pathToFile = "keys_example.txt";
  79.  
  80.             if (!System.IO.File.Exists(pathToFile))
  81.             {
  82.                 Console.WriteLine("No keys_example.txt file to compare created file\r\n");
  83.                 return 0;
  84.             }
  85.  
  86.             string[] lines = System.IO.File.ReadAllLines(pathToFile);
  87.  
  88.             foreach (string line in lines)
  89.             {
  90.                 int compareStringKeyA = String.Compare(line, keyA);
  91.                 int compareStringKeyB = String.Compare(line, keyB);
  92.  
  93.                 if (compareStringKeyA == 0) {
  94.                     Console.WriteLine("Find match to key A. Another generation start\r\n");
  95.                     return 1;
  96.                 }
  97.                 if (compareStringKeyB == 0) {
  98.                     Console.WriteLine("Find match to key B. Another generation start\r\n");
  99.                     return 1;
  100.                 }
  101.             }
  102.  
  103.             return 0;
  104.         }
  105.     }

Wynik działania generatora kluczy jest następujący:


Funkcja GenerateKeys() generuje klucz A oraz klucz B. Generacja jest powtarzana aż uda się wygenerować klucz który nie jest zapisany w pliku tekstowym. W praktyce prawdopodobieństwo trafienia na klucz, który jest zapisany w pliku jest bardzo małe (klucz mifare zapisany jest na 6 bajtach. Co daje 281474976710655 (DEC) unikalnych kluczy). 

Dodatkowo przygotowałem drugą opcję która pozwala na sprawdzenie czy takie klucze są już zapisane w wykorzystywanym pliku tekstowym. Ponownie, prawdopodobieństwo uzyskania takiego samego klucza jest prawie niemożliwe. W tym przypadku wynik działania programu jest następujący:


Wyszukiwanie można też zmienić na obsługę z bazy danych. Przykładowa funkcja sprawdzająca:

  1. public byte SearchInDB_BaseOnKeyA(SQLiteConnection db, string keyA)
  2. {
  3.     var query = db.Table<Company>().Where(v => v.CompanyKeyA.Equals(keyA));
  4.     int test = query.Count();
  5.  
  6.     if(test != 0) { return 1; }
  7.     return 0;
  8. }
  9.  
  10. public byte SearchInDB_BaseOnKeyB(SQLiteConnection db, string keyB)
  11. {
  12.     var query = db.Table<Company>().Where(v => v.CompanyKeyB.Equals(keyB));
  13.     int test = query.Count();
  14.  
  15.     if (test != 0) { return 1; }
  16.     return 0;
  17. }

Projekt można w łatwy sposób dostosować oraz w bardzo prosty sposób dodać klucze których przy generacji chcielibyśmy uniknąć.

Poniżej projekt w języku Python. Tutaj tylko generacja kluczy, natomiast dorobienie sprawdzania do tego mini programu nie powinno sprawić problemu.

Do generowania wykorzystałem bibliotekę secrets. Dostępną dla Pythona od wersji 3.6 (link). 

  1. import os
  2. from pathlib import Path
  3. import secrets
  4.  
  5. def Generate_Keys():
  6.     opStatus = 1
  7.  
  8.     while opStatus != 0:
  9.         generateKeysA_B = secrets.token_hex(12)
  10.         print("Generated data: " + generateKeysA_B)
  11.  
  12.         keyA = generateKeysA_B[:len(generateKeysA_B)//2]
  13.         keyB = generateKeysA_B[len(generateKeysA_B)//2:]
  14.    
  15.         print("Generated keyA: " + keyA)
  16.         print("Generated keyB: " + keyB)
  17.  
  18.         opStatus = OpenFile_CompareKeys(keyA, keyB)
  19.  
  20.         if opStatus == 0:
  21.             print("Keys generate correctly")
  22.         elif opStatus == 1:
  23.             print("Keys generate without compering")
  24.             opStatus = 0
  25.         elif opStatus == 2 or opStatus == 3:
  26.             print("Another key generation")
  27.  
  28.     print("KeyA: " + keyA)
  29.     print("KeyB: " + keyB)
  30.        
  31. def OpenFile_CompareKeys(keyA, keyB):
  32.     pathToFile = "keys_example.txt"
  33.     keysFile = Path(pathToFile)
  34.  
  35.     if keysFile.is_file():
  36.         print("keys_example.txt file present")
  37.         if os.stat(pathToFile).st_size == 0:
  38.             print("File exist but is empty")
  39.             return 1
  40.     else:
  41.         print("File not exist")
  42.         return 1
  43.  
  44.     f = open(pathToFile, "r")
  45.     lines = f.read().splitlines()
  46.  
  47.     for line in lines:
  48.         if line == keyA:
  49.             return 2
  50.         elif line == keyB:
  51.             return 3
  52.     return 0
  53.  
  54. def main():
  55.     print("Generate mifare keys.")
  56.     Generate_Keys()
  57.  
  58. if __name__ == "__main__":
  59.     main()

Efekt działania programu jest następujący:

  1. Generate mifare keys.
  2. Generated data: 35c6f12b1cba545397415e0f
  3. Generated keyA: 35c6f12b1cba
  4. Generated keyB: 545397415e0f
  5. keys_example.txt file present
  6. Keys generate correctly
  7. KeyA: 35c6f12b1cba
  8. KeyB: 545397415e0f

Programu można pobrać z dysku Google pod tym linkiem.