static void VWTest(List <Definition> definitions, List <SecurityProvider> providers) { SecurityProvider vwProvider = providers.Find(x => x.GetProviderName() == "VolkswagenSA2"); Definition vw1 = definitions.Find(x => x.EcuName == "VW_SA2_TEST1"); Definition vw2 = definitions.Find(x => x.EcuName == "VW_SA2_TEST2"); byte[] vwKey = new byte[4]; byte[] expectedOutput; expectedOutput = BitUtility.BytesFromHex("3C7876D8"); vwProvider.GenerateKey(BitUtility.BytesFromHex("A04EB1ED"), vwKey, 1, vw1.Parameters); // 0x3C7876D8 if (!vwKey.SequenceEqual(expectedOutput)) { Assert.Fail(); } expectedOutput = BitUtility.BytesFromHex("6A37F02E"); vwProvider.GenerateKey(BitUtility.BytesFromHex("1A1B1C1D"), vwKey, 1, vw2.Parameters); // 0x6a37f02e if (!vwKey.SequenceEqual(expectedOutput)) { Assert.Fail(); } }
public void TryGenerateKey(byte[] inByte) { if (dgvMain.SelectedRows.Count != 1) { txtKeyValue.Text = "Please select a definition first"; return; } int selectedIndex = int.Parse(dgvMain.SelectedRows[0].Cells[0].Value.ToString()); Definition definition = Definitions[selectedIndex]; groupBox2.Text = $"Key Generation ({definition})"; if (definition.SeedLength != inByte.Length) { txtKeyValue.Text = $"Expecting a {definition.SeedLength}-byte seed. Current length is {inByte.Length}"; return; } SecurityProvider provider = SecurityProvider.GetSecurityProviders().Find(x => x.GetProviderName() == definition.Provider); if (provider is null) { txtKeyValue.Text = $"Could not load security provider for {definition.Provider}"; return; } byte[] outKey = new byte[definition.KeyLength]; if (provider.GenerateKey(inByte, outKey, definition.AccessLevel, definition.Parameters)) { txtKeyValue.Text = BitUtility.BytesToHex(outKey, true); } else { txtKeyValue.Text = $"Key generation was unsuccessful ({definition.Provider})"; return; } }
static void QuickTest(Definition definition, List <SecurityProvider> providers) { // Build in x86 to test, else the pinvokes will fail! SecurityProvider provider = providers.Find(x => x.GetProviderName() == definition.Provider); if (provider is null) { Console.WriteLine($"Could not find a security provider for {definition.EcuName} ({definition.Provider})"); Assert.Fail(); return; } string dllPath = $"{GetLibraryFolder()}{definition.Provider}_L{definition.AccessLevel}.dll"; Console.WriteLine(dllPath); if (!File.Exists(dllPath)) { Console.WriteLine($"Could not find the target security DLL to verify with. {definition.EcuName} ({definition.Provider})"); Assert.Fail(); return; } Console.WriteLine($"Running QuickTest for {definition.EcuName} ({definition.Provider})"); DllContext context = new DllContext(dllPath, false); Tuple <uint, int, int> match = context.AccessLevels.Find(x => x.Item1 == definition.AccessLevel); if (match is null) { Console.WriteLine($"DLL does not support access level {definition.AccessLevel}"); Assert.Fail(); return; } List <byte[]> TestInput = new List <byte[]>(); foreach (GeneratedByteType byteType in Enum.GetValues(typeof(GeneratedByteType))) { TestInput.Add(GenerateBytes(definition.SeedLength, byteType)); } bool matchesAreValid = true; foreach (byte[] testRow in TestInput) { byte[] outKey = new byte[definition.KeyLength]; if (provider.GenerateKey(testRow, outKey, definition.AccessLevel, definition.Parameters)) { byte[] dllResult = context.GenerateKeyAuto((uint)definition.AccessLevel, testRow); matchesAreValid &= outKey.SequenceEqual(dllResult); Console.WriteLine($"In: {BitUtility.BytesToHex(testRow)} Out: {BitUtility.BytesToHex(outKey)} DLL: {BitUtility.BytesToHex(dllResult)}"); } } string testResult = matchesAreValid ? "Passed" : "Failed"; Console.WriteLine($"QuickTest {testResult}"); if (!matchesAreValid) { Assert.Fail(); } }
static void Main(string[] args) { bool showHelp = false; bool showDefinitions = false; int accessLevel = 1; string databasePath = "db.json"; string seedText = ""; string ecuName = ""; string prefix = ""; OptionSet options = new OptionSet() { { "d|database=", "Path to the JSON definition database", (string v) => databasePath = v }, { "s|seed=", "Seed value as received from ECU", (string v) => seedText = v }, { "n|name=", "Target ECU name", (string v) => ecuName = v }, { "l|level=", "Access level", (int v) => accessLevel = v }, { "h|help", "Show this message and exit", v => showHelp = v != null }, { "e|list", "Show a list of ECU definitions, then exit", v => showDefinitions = v != null }, { "p|prefix=", "Prefix this string on successful key generation", (string v) => prefix = v }, }; List <string> extraArgs; try { extraArgs = options.Parse(args); } catch (OptionException ex) { Console.WriteLine($"UnlockECU exception: {ex.Message}"); Console.WriteLine("Try `consoleunlockecu --help' for more information."); return; } if (showHelp) { ShowHelp(options); return; } // check params if they are valid first if (!File.Exists(databasePath)) { Console.WriteLine($"Could not open definition database file. Please check if the database exists at \"{databasePath}\""); return; } string definitionJson = ""; try { definitionJson = File.ReadAllText(databasePath); } catch (Exception ex) { Console.WriteLine($"UnlockECU exception while reading database : {ex.Message}"); return; } List <Definition> definitions = new List <Definition>(); try { definitions = System.Text.Json.JsonSerializer.Deserialize <List <Definition> >(definitionJson); } catch (Exception ex) { Console.WriteLine($"UnlockECU exception while parsing database : {ex.Message}. Please check if the JSON database file is valid."); return; } if (showDefinitions) { Console.WriteLine($"UnlockECU: {definitions.Count} definitions available in {databasePath}"); foreach (Definition d in definitions) { Console.Write($"{d.EcuName} ({d.Origin}): Level {d.AccessLevel}, Seed Length: {d.SeedLength}, Key Length: {d.KeyLength}, Provider: {d.Provider}\n"); } return; } if (ecuName.Length == 0) { Console.WriteLine($"UnlockECU: ECU name cannot be empty."); ShowHelp(options); return; } Definition matchingDefinition = Definition.FindDefinition(definitions, ecuName, accessLevel); if (matchingDefinition is null) { Console.WriteLine($"UnlockECU exception: Could not find a definition that matches {ecuName} (level {accessLevel})"); return; } // clean up user's seed input bool validHex = true; string cleanedText = seedText.Replace(" ", "").Replace("\r", "").Replace("\n", "").Replace("\t", "").Replace("-", "").ToUpper(); if (cleanedText.Length % 2 != 0) { validHex = false; } if (!System.Text.RegularExpressions.Regex.IsMatch(cleanedText, @"\A\b[0-9a-fA-F]+\b\Z")) { validHex = false; } byte[] seed = new byte[] { }; if (validHex) { seed = BitUtility.BytesFromHex(cleanedText); } else if (matchingDefinition.SeedLength == 0) { // do nothing, array is already empty } else { Console.WriteLine($"UnlockECU exception: ECU {matchingDefinition.EcuName} requires a valid {matchingDefinition.SeedLength}-byte seed"); return; } // attempt to generate the key SecurityProvider provider = SecurityProvider.GetSecurityProviders().Find(x => x.GetProviderName() == matchingDefinition.Provider); if (provider is null) { Console.WriteLine($"UnlockECU exception: Could not load security provider for {matchingDefinition.EcuName} ({matchingDefinition.Provider})"); return; } byte[] outKey = new byte[matchingDefinition.KeyLength]; if (provider.GenerateKey(seed, outKey, matchingDefinition.AccessLevel, matchingDefinition.Parameters)) { Console.Write($"{prefix}{BitUtility.BytesToHex(outKey)}"); return; } else { Console.WriteLine($"UnlockECU exception: Key generation was unsuccessful for {matchingDefinition.EcuName} ({matchingDefinition.Provider})"); return; } }