Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jglim committed Oct 12, 2020
1 parent 46d22ea commit 5f8d90b
Show file tree
Hide file tree
Showing 30 changed files with 2,176 additions and 0 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# SecurityAccessQuery

Interact with Vector security DLLs that are used to generate Security Access Keys in a ECU challenge/response ("seed key").

![Header image](https://raw.github.com/jglim/SecurityAccessQuery/main/docs/resources/SAQ_Header.png)

## Usage

SAQ requires .NET 4.6 or newer. You will also need to bring your own security DLLs.

### Set up

- Download SAQ from the [Releases page](https://github.com/jglim/SecurityAccessQuery/releases).
- Unzip the archive, including the empty Library folder.
- Add your DLLs into the Library folder. **No DLLs are provided by default.**
- Run SAQ.

### Generate Seed Key

- Under `File`, click `Select DLL (Filtered)`
- Select the DLL file that matches your ECU (double-click)
- In the text field, insert your seed value from Monaco or Vediamo
- The key will be automatically generated (shown beside `Access Key`)
- Select the cell and copy from it (`CTRL + C`)
- The key can now be pasted back into Monaco or Vediamo

## Testing

A set of tests are available here. As I do not own a C4, I used seed requests and generated keys that are shown in public screenshots and videos to verify that the generated values are correct.

## Issues

Please note: SAQ does not perform the actual key generation. It is only an interface to a target DLL.

### Obtaining DLL files

The DLL files are typically packaged with vendor tools like DTS Monaco, and several automotive forums typically share these files. As they are proprietary blobs, they **cannot** be included directly in this repository for legal reasons. Please **do not** share or request for them here.

### Incorrect keys

The keys are generated by the DLL. If the key is not accepted, it may indicate that the wrong or mismatched DLL was used. The challenges (seed) are also refreshed on reset or disconnection so they cannot be reused.

---

# Technical notes

Some modern ECU systems offer a layer of security that prevents normal users from making changes without completing a seed-key challenge. An authorized client will typically have a DLL or JAR file that takes in a seed challenge, and generates a key. Vector has a well-written application note (AN-IDG-1-017) available [here](https://assets.vector.com/cms/content/know-how/_application-notes/AN-IDG-1-017_SecurityAccess.pdf), that describes this verification process.

At its essence, SAQ is simply a wrapper to call a target security DLL's key generation function — namely `GenerateKeyEx` or `GenerateKeyExOpt`.

In my limited understanding, the DLLs are usually packaged in a container format, and only extracted by the vendor tools when they are required. For example, in the `MED40.smr-d` ODB file, the security DLLs are present as `med40_abgleich_00_00_01.dll` , `med40_flash_12_39_00.dll` and `med40_sec_00_00_01.dll`.

![DB diff screenshot](https://raw.github.com/jglim/SecurityAccessQuery/main/docs/resources/diff.png)

Recent ECUs seem to prefer JARs instead of DLLs, which should offer much better cross-platform support and disassembly quality.

---

## License

MIT

Icon from [http://www.famfamfam.com/lab/icons/silk/](http://www.famfamfam.com/lab/icons/silk/)
25 changes: 25 additions & 0 deletions SecurityAccessQuery/SecurityAccessQuery.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30309.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecurityAccessQuery", "SecurityAccessQuery\SecurityAccessQuery.csproj", "{67781F09-398D-4EA7-9087-938C7FBD9D98}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{67781F09-398D-4EA7-9087-938C7FBD9D98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67781F09-398D-4EA7-9087-938C7FBD9D98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67781F09-398D-4EA7-9087-938C7FBD9D98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67781F09-398D-4EA7-9087-938C7FBD9D98}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25950996-1E60-42CA-8DFC-943E60EEE528}
EndGlobalSection
EndGlobal
6 changes: 6 additions & 0 deletions SecurityAccessQuery/SecurityAccessQuery/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>
82 changes: 82 additions & 0 deletions SecurityAccessQuery/SecurityAccessQuery/BitUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;

namespace SecurityAccessQuery
{
/// <summary>
/// Utilities for bit and byte operations.
/// (Frequently copied-and-pasted across my projects)
/// </summary>
class BitUtility
{
/// <summary>
/// Sets all values in an array of bytes to a specific value
/// </summary>
/// <param name="value">Value to set byte array to</param>
/// <param name="buf">Target byte array buffer</param>
public static void Memset(byte value, byte[] buf)
{
for (int i = 0; i < buf.Length; i++)
{
buf[i] = value;
}
}
// Internally used by BytesFromHex
private static byte[] StringToByteArrayFastest(string hex)
{
// see https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array
if (hex.Length % 2 == 1)
{
throw new Exception("The binary key cannot have an odd number of digits");
}
byte[] arr = new byte[hex.Length >> 1];
for (int i = 0; i < hex.Length >> 1; ++i)
{
arr[i] = (byte)((GetHexValue(hex[i << 1]) << 4) + (GetHexValue(hex[(i << 1) + 1])));
}
return arr;
}
// Internally used by StringToByteArrayFastest
private static int GetHexValue(char hex)
{
int val = (int)hex;
return val - (val < 58 ? 48 : 55);
}
/// <summary>
/// Converts an array of bytes into its hex-string equivalent
/// </summary>
/// <param name="inBytes">Input byte array</param>
/// <param name="spacedOut">Option to add spaces between individual bytes</param>
/// <returns>Hex-string based on the input byte array</returns>
public static string BytesToHex(byte[] inBytes, bool spacedOut = false)
{
return BitConverter.ToString(inBytes).Replace("-", spacedOut ? " " : "");
}

/// <summary>
/// Converts an array of bytes into a printable hex-string
/// </summary>
/// <param name="hexString">Input hex-string to convert into a byte array</param>
/// <returns>Byte array based on the input hex-string</returns>
public static byte[] BytesFromHex(string hexString)
{
return StringToByteArrayFastest(hexString.Replace(" ", ""));
}

/// <summary>
/// Resize a smaller array of bytes to a larger array. The padding bytes will be 0.
/// </summary>
/// <param name="inData">Input byte array</param>
/// <param name="finalSize">New size for the input array</param>
/// <returns>Resized byte array</returns>
public static byte[] PadBytes(byte[] inData, int finalSize)
{
if (inData.Length > finalSize)
{
return inData;
}
byte[] result = new byte[finalSize];
Buffer.BlockCopy(inData, 0, result, 0, inData.Length);
return result;
}
}
}
Loading

0 comments on commit 5f8d90b

Please sign in to comment.