[PATCH 1/1] BTWinLinkKeyExport - Tool to export link-keys stored by the WIDCOMM stack

Alexander Holler
2009-05-22T13:38:41Z

I've used this for dualboot-systems because I didn't want to
pair the devices every time I've switched systems.

Currently it exports the keys using the old bluez format with files
named 'link_key' and 'linkkeys'. To use it with newer versions of bluez
it has either to be modified or someone has to write an import.
---
tools/windows/BTWinLinkKeyExport.cpp | 210 ++++++++++++++++++++++++++++++++++
1 files changed, 210 insertions(+), 0 deletions(-)
create mode 100644 tools/windows/BTWinLinkKeyExport.cpp

diff --git a/tools/windows/BTWinLinkKeyExport.cpp b/tools/windows/BTWinLinkKeyExport.cpp
new file mode 100644
index 0000000..deadabe
--- /dev/null
+++ b/tools/windows/BTWinLinkKeyExport.cpp
@@ -0,0 +1,210 @@
+//
+// BTWinLinkKeyExport.cpp
+//
+// Exports bluetooth-link-keys stored by the WIDCOMM stack for use with
+// Dual- or Multi-booting systems.
+//
+// Written 2004 by Alexander Holler.
+//
+// This source is free in every aspect. You can use, modify, distribute
+// or sell it at your wish. You can even replace my name with yours if
+// that would earn you some credits you otherwise wouldn't get.
+//
+// No warrantys are given. This software might destroy your hardware,
+// software or datas.
+//
+// This software uses functions like sscanf() and such bad things,
+// feel free to make it safe up to point your security-officer wants it.
+//
+// To compile it I've used the free Borland Compiler, but it should work using
+// any compiler. For bcc I've used the following few lines:
+//
+// path=%path%;d:\Programme\Borland\Bcc55\bin
+// bcc32 -O2 -DNDEBUG -c BTWinLinkKeyExport.cpp
+// bcc32 -O2 -DNDEBUG BTWinLinkKeyExport.obj
+//
+// (WIDCOMM is a registered trademark of WIDCOMM Inc. and
+// Borland is a trademark of Borland Software Corporation)
+//
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <string>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+typedef unsigned char uint8_t;
+
+#pragma pack(1)
+
+typedef struct {
+ uint8_t b[6];
+} bdaddr_t;
+
+#pragma pack(4)
+
+struct link_key {
+ bdaddr_t sba; // Dongle address
+ bdaddr_t dba; // external Device address
+ uint8_t key[16];
+ uint8_t type;
+ time_t time;
+};
+
+#pragma pack()
+
+static char* local_device;
+
+static void displayLastError(void)
+{
+ LPVOID lpMsgBuf;
+ DWORD msgid=GetLastError();
+ if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, msgid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf, 0, NULL ))
+ return;
+ fprintf(stderr, "Error %u: %s\n", msgid, lpMsgBuf);
+ LocalFree( lpMsgBuf );
+}
+
+static int exportKey(const char* regkeyname, HCRYPTPROV& hProv, FILE* file,
+ FILE* file2)
+{
+ // This function tries to read the registry entry linkkey, decrypts it and
+ // writes an entry to the link-key-file for linux
+ std::string s=std::string("SOFTWARE\\Widcomm\\BTConfig\\Devices\\") +
+ regkeyname;
+ HKEY rKey=NULL;
+ long rc=RegOpenKeyEx(HKEY_LOCAL_MACHINE, s.c_str(), 0, KEY_READ, &rKey);
+ if(rc!=ERROR_SUCCESS) {
+ LPVOID lpMsgBuf;
+ if(!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
+ 0, NULL ))
+ return 0;
+ fprintf(stderr, "Error %u: %s\n", rc, lpMsgBuf);
+ LocalFree( lpMsgBuf );
+ return 1;
+ }
+ BYTE keybuf[1024]; // I'm lazy, fixed size
+ DWORD keybuflen=sizeof(keybuf);
+ DWORD type;
+ rc=RegQueryValueEx(rKey, "LinkKey", NULL, &type, keybuf, &keybuflen);
+ RegCloseKey(rKey);
+ if(rc!=ERROR_SUCCESS)
+ return 0; // No error, just no link key
+ // If anyone wants to implement boundary checks for keybuf,
+ // he has my permissions. ;)
+ DWORD dwDataLen=*((DWORD*)(keybuf+4));
+ unsigned char *importkey=keybuf+8;
+ HCRYPTKEY hKey = NULL;
+ if(!CryptImportKey(hProv, importkey, dwDataLen, 0, 0, &hKey)) {
+ displayLastError();
+ return 2;
+ }
+ unsigned char* realkey=importkey+dwDataLen+4;
+ DWORD dwDataLen2=*((DWORD*)(realkey-4));
+ BYTE* newkey=(BYTE*)malloc(dwDataLen2);
+ memcpy(newkey, realkey, dwDataLen2);
+ if(!CryptDecrypt(hKey, 0, 1, 0, newkey, &dwDataLen2 )) {
+ displayLastError();
+ CryptDestroyKey(hKey);
+ return 3;
+ }
+ CryptDestroyKey(hKey);
+ struct link_key lkey;
+ memset(&lkey, 0, sizeof(lkey));
+ unsigned adr[6];
+ if(sscanf(regkeyname, "%x:%x:%x:%x:%x:%x", &adr[0], &adr[1], &adr[2],
+ &adr[3],&adr[4], &adr[5])!= 6)
+ return 4;
+ for(int i=0; i<6; i++)
+ lkey.dba.b[5-i]=adr[i];
+ if(sscanf(local_device, "%x:%x:%x:%x:%x:%x", &adr[0], &adr[1], &adr[2],
+ &adr[3],&adr[4], &adr[5])!= 6)
+ return 5;
+ for(int i=0; i<6; i++)
+ lkey.sba.b[5-i]=adr[i];
+ for(int i=0; i<16; i++)
+ lkey.key[i]=newkey[dwDataLen2-1-i];
+ lkey.time=time(NULL); // We are faking as this is not needed for operation
+ lkey.type=0; // I don't know the types, but my devices are all having 0
+ if(fwrite(&lkey, sizeof(lkey), 1, file)!=1)
+ return 6;
+ for(int i=0; i<17; i++)
+ // I haven't checked if bluez treads them case insensitiv, so we are
+ // exporting them like they were originally found in bluez (uppercase)
+ fprintf(file2, "%c", toupper(regkeyname[i]));
+ fprintf(file2, " ");
+ for(int i=0; i<16; i++)
+ fprintf(file2, "%02X", lkey.key[i]);
+ fprintf(file2, " 0%c", 0x0a);
+ printf("Link key for %s exported.\n", regkeyname);
+ return 0;
+}
+
+static void showHelp(void)
+{
+ printf("\nBTLinkKeyExport V1.0\nWritten 2004 Alexander Holler\n"
+ "Free in every aspect. See the source for details.\n\n");
+ printf(" Usage: BTLinkKeyExport localDeviceMAC\n");
+ printf(" Where localDeviceMAC is in the form xx:xx:xx:xx:xx:xx\n");
+}
+
+int main(int argc, char **argv)
+{
+ if(argc!=2) {
+ showHelp();
+ return 1;
+ }
+ if(strlen(argv[1])!=17) {
+ showHelp();
+ return 2;
+ }
+ local_device=argv[1];
+ FILE* file=fopen("link_key", "wb");
+ if(!file) {
+ fprintf(stderr, "Unable to open file 'link_key' for writing!\n");
+ return 3;
+ }
+ FILE* file2=fopen("linkkeys", "wb");
+ if(!file2) {
+ fprintf(stderr, "Unable to open file 'linkkeys' for writing!\n");
+ return 3;
+ }
+ const char* provider="Microsoft Base Cryptographic Provider v1.0";
+ const char* container="Widcomm Bluetooth Key Container Name";
+ HCRYPTPROV hProv = NULL;
+ if(!CryptAcquireContext(&hProv, container, provider, 1 /* dwProviderType */,
+ 0x20 /* dwFlags */ )) {
+ displayLastError();
+ fclose(file);
+ return 4;
+ }
+ HKEY rKey;
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Widcomm\\BTConfig\\Devices", 0,
+ KEY_READ, &rKey);
+ int ret=0;
+ for(unsigned i=0; ; i++) {
+ char rkeyname[255];
+ DWORD rkeynamelen=sizeof(rkeyname);
+ FILETIME ftLastWriteTime;
+ int rc=RegEnumKeyEx(rKey, i, rkeyname, &rkeynamelen, NULL, NULL, NULL,
+ &ftLastWriteTime);
+ if(rc!=ERROR_SUCCESS)
+ break;
+ ret=exportKey(rkeyname, hProv, file, file2);
+ if(ret) {
+ ret+=4;
+ break; // An error occured
+ }
+ }
+ RegCloseKey(rKey);
+ CryptReleaseContext(hProv, 0);
+ fclose(file);
+ return ret;
+}
--
1.6.0.4