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:
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Generate/Check Mifare Keys\r\n");
- Console.WriteLine("Pass 'g' to generate keys.");
- Console.WriteLine("Pass 'c' to check keys.");
- Console.WriteLine("Different value close program.");
- Console.WriteLine("Waiting for key...");
- ConsoleKeyInfo clickedKey = Console.ReadKey();
- if(clickedKey.Key == ConsoleKey.G)
- {
- Console.WriteLine("\r\n");
- Console.WriteLine("Selected generate keys:");
- GenerateKeys();
- }
- else if (clickedKey.Key == ConsoleKey.C)
- {
- Console.WriteLine("\r\n");
- Console.WriteLine("Selected check keys:");
- Console.WriteLine("Pass keys (keyA keyB) (format FFFFFFFFFFFF FFFFFFFFFFFF):");
- string keyA_B = Console.ReadLine();
- string[] keys = keyA_B.Split(' ');
- Console.WriteLine("Passed KeyA: " + keys[0]);
- Console.WriteLine("Passed KeyB: " + keys[1]);
- if (SearchInFile_CompareKeys(keys[0], keys[1]) != 0)
- {
- Console.WriteLine("ERROR MATCH FOUND");
- }
- else
- {
- Console.WriteLine("OK No keys in txt file");
- }
- }
- Console.ReadKey();
- }
- static void GenerateKeys()
- {
- string keyAStr = "";
- string keyBStr = "";
- byte operationStatus = 0;
- Random rand = new Random(Guid.NewGuid().GetHashCode());
- uint[] randomValues = new uint[12];
- while(operationStatus == 0)
- {
- for (uint i = 0; i < randomValues.Length; ++i)
- {
- randomValues[i] = (uint)rand.Next(1, 255);
- }
- 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]);
- 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]);
- if(SearchInFile_CompareKeys(keyAStr, keyBStr) == 0)
- {
- Console.WriteLine("Keys generate properly: \r\n");
- Console.WriteLine("keyAStr:" + keyAStr + "\r\n");
- Console.WriteLine("keyBStr:" + keyBStr + "\r\n");
- operationStatus = 1;
- }
- }
- }
- static byte SearchInFile_CompareKeys(string keyA, string keyB)
- {
- string pathToFile = "keys_example.txt";
- if (!System.IO.File.Exists(pathToFile))
- {
- Console.WriteLine("No keys_example.txt file to compare created file\r\n");
- return 0;
- }
- string[] lines = System.IO.File.ReadAllLines(pathToFile);
- foreach (string line in lines)
- {
- int compareStringKeyA = String.Compare(line, keyA);
- int compareStringKeyB = String.Compare(line, keyB);
- if (compareStringKeyA == 0) {
- Console.WriteLine("Find match to key A. Another generation start\r\n");
- return 1;
- }
- if (compareStringKeyB == 0) {
- Console.WriteLine("Find match to key B. Another generation start\r\n");
- return 1;
- }
- }
- return 0;
- }
- }
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:
- public byte SearchInDB_BaseOnKeyA(SQLiteConnection db, string keyA)
- {
- var query = db.Table<Company>().Where(v => v.CompanyKeyA.Equals(keyA));
- int test = query.Count();
- if(test != 0) { return 1; }
- return 0;
- }
- public byte SearchInDB_BaseOnKeyB(SQLiteConnection db, string keyB)
- {
- var query = db.Table<Company>().Where(v => v.CompanyKeyB.Equals(keyB));
- int test = query.Count();
- if (test != 0) { return 1; }
- return 0;
- }
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).
- import os
- from pathlib import Path
- import secrets
- def Generate_Keys():
- opStatus = 1
- while opStatus != 0:
- generateKeysA_B = secrets.token_hex(12)
- print("Generated data: " + generateKeysA_B)
- keyA = generateKeysA_B[:len(generateKeysA_B)//2]
- keyB = generateKeysA_B[len(generateKeysA_B)//2:]
- print("Generated keyA: " + keyA)
- print("Generated keyB: " + keyB)
- opStatus = OpenFile_CompareKeys(keyA, keyB)
- if opStatus == 0:
- print("Keys generate correctly")
- elif opStatus == 1:
- print("Keys generate without compering")
- opStatus = 0
- elif opStatus == 2 or opStatus == 3:
- print("Another key generation")
- print("KeyA: " + keyA)
- print("KeyB: " + keyB)
- def OpenFile_CompareKeys(keyA, keyB):
- pathToFile = "keys_example.txt"
- keysFile = Path(pathToFile)
- if keysFile.is_file():
- print("keys_example.txt file present")
- if os.stat(pathToFile).st_size == 0:
- print("File exist but is empty")
- return 1
- else:
- print("File not exist")
- return 1
- f = open(pathToFile, "r")
- lines = f.read().splitlines()
- for line in lines:
- if line == keyA:
- return 2
- elif line == keyB:
- return 3
- return 0
- def main():
- print("Generate mifare keys.")
- Generate_Keys()
- if __name__ == "__main__":
- main()
Efekt działania programu jest następujący:
- Generate mifare keys.
- Generated data: 35c6f12b1cba545397415e0f
- Generated keyA: 35c6f12b1cba
- Generated keyB: 545397415e0f
- keys_example.txt file present
- Keys generate correctly
- KeyA: 35c6f12b1cba
- KeyB: 545397415e0f